FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Unnecessarily large date range created when plotting a single point using a Datetime object · Issue #5963 · matplotlib/matplotlib · GitHub

Repository navigation

Unnecessarily large date range created when plotting a single point using a Datetime object #5963

Closed as not planned

Description

As explained in my original StackOverflow question, I've found some unexpected behavior when plotting single points in matplotlib.pyplot with Datetime objects. Plotting multiple points (>1) gives the range of dates with some buffer on either side. Plotting a single point causes the range to span multiple years (2014 - 2018 using Feb 03, 2016).

When using the AutoDateLocator(), the (assumed) issue isn't as noticeable since the generated ticks are fairly conservative, but using a WeekdayLocator() instead results in a dense mess of ticks. The application I'm using this for deals with time spans of at most a few months, so suddenly getting a range of multiple years is quite jarring.

Below is some code that generates 6 matplotlib.pyplot plot images to demonstrate a few example cases and the output from running the script with the --verbose-debug flag

import matplotlib.pyplot as plt
import matplotlib.dates as md
from datetime import datetime

# Create figures
fig0 = plt.figure(0)
fig1 = plt.figure(1)
fig2 = plt.figure(2)
fig3 = plt.figure(3)
fig4 = plt.figure(4)
fig5 = plt.figure(5)
fig6 = plt.figure(6)
# Add some subplots
sub3 = fig3.add_subplot(111)
sub4 = fig4.add_subplot(111)
sub5 = fig5.add_subplot(111)
sub6 = fig6.add_subplot(111)

# Creating a regular plot directly with a single point
plt.figure(0)
plt.plot((2,), (3,), marker='o')
plt.title('Regular plot, single point')

# Doing the same, but with a subplot
sub3.plot((2,), (3,), marker='o')
sub3.set_title('Subplot, single point')

# Creating a regular plot using a Datetime object with multiple points
# Using the AutoDateLocator()
test_date_one = datetime.strptime('2016-02-03', '%Y-%m-%d')
test_date_two = datetime.strptime('2016-03-03', '%Y-%m-%d')

plt.figure(1)
plt.plot((test_date_one, test_date_two), (2, 3), marker='o')
fig1.autofmt_xdate()
plt.title('Regular plot, multiple Datetime points')

# Now with a single point
plt.figure(2)
plt.plot(test_date_one, 2, marker='o')
fig2.autofmt_xdate()
plt.title('Regular plot, single Datetime point')

# Doing the same, but with a subplot
# Multiple points
sub4.plot((test_date_one, test_date_two), (2, 3), marker='o')
fig4.autofmt_xdate()
sub4.set_title('Subplot, multiple Datetime points')

# Single point
sub5.plot(test_date_one, 2, marker='o')
fig5.autofmt_xdate()
sub5.set_title('Subplot, single Datetime point')

# Finally, single Datetime point with WeekdayLocator()
sub6.plot(test_date_two, 3, marker='o')
sub6.xaxis.set_major_locator(md.WeekdayLocator())
fig6.autofmt_xdate()
sub6.set_title('Subplot, single Datetime point, WeekdayLocator()')

plt.show()

Debug Output
$HOME=C:\Users******
matplotlib data path C:\Python27\lib\site-packages\matplotlib\mpl-data


You have the following UNSUPPORTED LaTeX preamble customizations:

Please do not ask for support with these customizations active.


loaded rc file C:\Python27\lib\site-packages\matplotlib\mpl-data\matplotlibrc
matplotlib version 1.5.1
verbose.level debug
interactive is False
platform is win32
loaded modules: <dictionary-keyiterator object at 0x04E08810>
CACHEDIR=C:\Users*.matplotlib
Using fontManager instance from C:\Users*
.matplotlib\fontList.cache
backend TkAgg version 8.5
Could not load matplotlib icon: can't use "pyimage10" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage19" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage28" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage37" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage46" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage55" as iconphoto: not a photo image
findfont: Matching :family=sans-serif:style=normal:variant=normal:weight=400:stretch=normal:size=medium to Bitstream Vera Sans (u'c:\python27\lib\site-packages\matplotlib\mpl-data\fonts\ttf\Vera.ttf') with score of 0.000000
findfont: Matching :family=sans-serif:style=normal:variant=normal:weight=400:stretch=normal:size=large to Bitstream Vera Sans (u'c:\python27\lib\site-packages\matplotlib\mpl-data\fonts\ttf\Vera.ttf') with score of 0.000000

Activity

  1. tacaswell commented on Feb 4, 2016

    Member

    Minimal example:

    from datetime import datetime
    import matplotlib.dates as md
    
    fig, ax = plt.subplots()
    
    test_date_two = datetime.strptime('2016-03-03', '%Y-%m-%d')
    
    ax.plot(test_date_two, 3, marker='o')
    ax.xaxis.set_major_locator(md.WeekdayLocator())

    Thank you for the extensive report, but there is something to be send for brevity.

  2. bcoov commented on Feb 4, 2016

    Author

    I've never submitted a bug report for something like this before, so I wanted to err on the side of too much info vs. too little. My apologies for the lengthy example though.

  3. tacaswell commented on Feb 4, 2016

    Member

    No worries! Thank you for the report. In the future please err on the side of brief but clear, the easier you make it for the reader the understand your problem the more likely it is they will look into fixing it. For example, we do not need to see the cases where it works (we assume the library works 😉 ).

    Do you have any suggestions on how, from a single time stamp, to pick a good scale? I think what is happening here is that for non-date data we go a few percent on either side. The way we plot dates is that internally they are converted to float seconds from year 0, so a date around now gives a value

    In [164]: ax.convert_xunits(test_date_two)
    Out[164]: 736026.0

    which gives a range of (690000.0, 780000.0) from the auto-expanding, which isn't so bad if you were plotting against scalars, but gives you this rather silly result if you put ticks ever 8.6k or so.

    The best solution here might be for you to write a helper function, something like

    def plot_my_date_data(ax, x, y, **kwargs):
        ret = ax.plot(x, y, **kwargs)
        if len(x) == 1:
            ax.set_xlim(x - week, x + week)
        ax.xaxis.set_major_locator(md.WeekdayLocator())
        return ret

    @njsmith Any thoughts on this sort of thing?

  4. added this to the milestone on Feb 4, 2016
  5. tacaswell commented on Feb 4, 2016

    Member

    labeled this as 2.0 as it relates to changing the behavior of the auto-limits.

  6. tacaswell commented on Feb 4, 2016

    Member

    Actually, digging into this a bit more, the nonsingular should be handled by the locator which is special cased for dates already....

  7. njsmith commented on Feb 4, 2016

    @tacaswell: As far as I understand it, the change in defaults is to make the display range = range of the data +/- 4%. For a single point, this gives a zero-width display range of [data value, data value] :-).

    Obviously this is not ideal, you need to special-case the singular case somehow and invent some sort of non-zero width. But I think the way you do that is orthogonal to the actual change in axis limit setting rules? Even with the old axis limit setting, if all you have is a single value 123.4, then the axis limits could be anyhing -- [100, 200], [120, 125], [123.0, 124.0], ...

  8. bcoov commented on Feb 4, 2016

    Author

    I was going to suggest basing the range off of the Locator being used, but considering:

    Actually, digging into this a bit more, the nonsingular should be handled by the locator which is special cased for dates already....

    I assume this is already implemented, or at least intended to be?

  9. WeatherGod commented on Feb 4, 2016

    Member

    What if we went with an order of magnitude rule? So, if seconds are
    non-zero, then 4% around seconds. If minutes are non-zero, 4% around the
    minute. If hour is non-zero, then 4% around that (and so on and so forth)?

    On Thu, Feb 4, 2016 at 12:45 PM, bcoov notifications@github.com wrote:

    I was going to suggest basing the range off of the Locator being used, but
    considering:

    Actually, digging into this a bit more, the nonsingular should be handled
    by the locator which is special cased for dates already....

    I assume this is already implemented, or at least intended to be?

    —
    Reply to this email directly or view it on GitHub
    #5963 (comment)
    .

  10. efiring commented on Feb 5, 2016

    Member

    I think it might be more natural for each specific date locator type to expand the singular range to a few of its units. Perhaps the AutoDateLocator could use something like your order of magnitude rule.

  11. WeatherGod commented on Feb 5, 2016

    Member

    Yeah, I think that makes sense.

    On Thu, Feb 4, 2016 at 10:21 PM, Eric Firing notifications@github.com
    wrote:

    I think it might be more natural for each specific date locator type to
    expand the singular range to a few of its units. Perhaps the
    AutoDateLocator could use something like your order of magnitude rule.

    —
    Reply to this email directly or view it on GitHub
    #5963 (comment)
    .

  12. modified the milestones: , on Feb 5, 2016
  13. 8 remaining items

  14. added this to the milestone on Sep 24, 2017
  15. modified the milestones: , on Mar 24, 2018
  16. modified the milestones: v3.0, v3.1 on Aug 11, 2018
  17. modified the milestones: v3.1.0, v3.2.0 on Mar 18, 2019
  18. github-actions commented on Mar 21, 2023

    This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

  19. jklymak commented on Mar 21, 2023

    Member

    I'm pretty sure the default date span is one day now. I'll close but feel free to reopen if I'm mistaken

  20. rcomer commented on Mar 21, 2023

    Member

    The code from #5963 (comment) now produces

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL