Skip to content

misplaced spines in dates plot #7138

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
anntzer opened this issue Sep 19, 2016 · 19 comments
Closed

misplaced spines in dates plot #7138

anntzer opened this issue Sep 19, 2016 · 19 comments

Comments

@anntzer
Copy link
Contributor

anntzer commented Sep 19, 2016

Noticed while investigating the test failure in #7123.

from matplotlib import dates; from datetime import *
plt.plot([datetime(1990, 1, 1), datetime(1990, 1, 1) + timedelta(microseconds=1500)], [0, 0])
plt.show()

1.5.3:
153
2.0b4:
20b4
Note how the horizontal spines are shifted in 2.0b4.

@anntzer anntzer added this to the 2.0 (style change major release) milestone Sep 19, 2016
@WeatherGod
Copy link
Member

wow, that's a doozy. does this still happen in 2.0b4 with mpl.use('classic')? If so, then that image could be use for direct comparison with the 1.5 image to figure out the exact differences (did the y-spine or the x-spine shift?)

@Kojoley
Copy link
Member

Kojoley commented Sep 19, 2016

matplotlib.style.use('classic') does not help, v2.0.0b1-v2.0.0b4 are affected.

did the y-spine or the x-spine shift?

It is x-spine shift. Open the plot, make the window wide and then slowly resize it - you will see.

@WeatherGod
Copy link
Member

You can't tell if it is an x or y spine shift to the right or left just by looking at one image. It has to be compared to a baseline - hence why classic mode would be helpful here since fonts and other settings have changed that would complicate direct comparisons.

@anntzer
Copy link
Contributor Author

anntzer commented Sep 19, 2016

It does not happen in classic mode for me.

@QuLogic
Copy link
Member

QuLogic commented Sep 19, 2016

If you pan and zoom, the x spine jumps between alignment with the y spine and how it looks here. The y spine does not shift position.

@Kojoley
Copy link
Member

Kojoley commented Sep 19, 2016

It does not happen in classic mode for me.

I have this
image

@QuLogic
Copy link
Member

QuLogic commented Sep 19, 2016

It doesn't happen in classic mode with these axes limits for me, but if you pan around enough, it does happen in classic mode.

@Kojoley
Copy link
Member

Kojoley commented Sep 19, 2016

Try to resize the window

@QuLogic
Copy link
Member

QuLogic commented Sep 19, 2016

I can also trigger it in 1.5.2 as well, with careful panning. Sometimes can even save it as well:
figure_1-1

@efiring efiring modified the milestones: 3.0 (future), 2.0 (style change major release) Sep 20, 2016
@tacaswell tacaswell modified the milestones: v3.0, v3.1 Aug 11, 2018
@tacaswell tacaswell modified the milestones: v3.1.0, v3.2.0 Mar 18, 2019
@anntzer
Copy link
Contributor Author

anntzer commented Aug 7, 2019

Upon further investigation this is indeed because of floating point inaccuracies: indeed, the spines are off by a few ms, which is ~10e-14 relative to the 2000y timedelta (given that the times are internally in floating point days relative to year 1); specifically the inaccuracy occurs when the transLimits and transAxes matrices are multiplied together first (essentially it's (transAxestransLimits)limits vs transAxes(transLimitslimits)).

I don't think there's much to do for matplotlib floating point datetimes per se; however this should not occur when using numpy datetimes (which do not suffer from this inaccuracy problem and can represent microseconds over tens of thousands of years exactly (https://docs.scipy.org/doc/numpy/reference/arrays.datetime.html#datetime-units) -- but because we internally convert them to matplotlib dates, all is lost.

May be worth checking whether we can have a parallel system (well, reusing as much machinery as possible) that uses numpy datetimes internally.

@jklymak
Copy link
Member

jklymak commented Aug 7, 2019

We have to convert to float at some point. That involves an inherent loss in resolution over a given date range.

As pointed out numerous times, using matplotlib date plotting on timescales shorter than milliseconds will lead to inaccuracies and the user should just plot as seconds from the start of the day, or some other reference time. I really don’t think there is any advantage to specially handling dates at such a small scale.

@anntzer
Copy link
Contributor Author

anntzer commented Aug 7, 2019

I'm actually fine with saying "we can't do anything about it", but I think if we can't even position plot elements accurately (if spines are at the wrong place it seems likely that other artists will be rendered at the wrong place too) then we should just error out. Or at least reword the warning in #15000 to something stronger: it's not that plotting microseconds at current reference times is "not well supported", it's that the plot may well have nothing to do with your actual data.

@jklymak
Copy link
Member

jklymak commented Aug 7, 2019

That'd be fine. But we don't error out on other floating point inaccuracies, its just that this one is more unexpected.

One thing we could do is change the epoch to something more modern, like 1970, or 2000. Most people plotting old dates do not need millisecond accuracy.

@jklymak
Copy link
Member

jklymak commented Aug 7, 2019

OK, what do you think about an mdates.set_epoch('1970-01-01') or some such? That would allow users who want to set today as the epoch get resolution out to very small numbers. Of course you would need to set the epoch before you start plotting, but that doesn't seem to be an issue to me.

@anntzer
Copy link
Contributor Author

anntzer commented Aug 7, 2019

I guess that may be nice to have.
OTOH your comment about other floating point inaccuracies not being warned upon also convinced me that this may not be worth overthinking about.

@jklymak
Copy link
Member

jklymak commented Aug 7, 2019

I did it. It works, down the point the microsecond locator gives up. But... we lose some guard-rails, like matplotlib times can't be less than 1. OTOH, not sure why that's really needed or desirable.

@jklymak
Copy link
Member

jklymak commented Aug 7, 2019

I guess I'm still somewhat of the opinion that if you are going to go to the trouble of specifying an epoch, you might as well just subtract the epoch from the time and plot as floats yourself, but I could be convinced otherwise.

@anntzer
Copy link
Contributor Author

anntzer commented Aug 7, 2019

Well we can still say "put your epoch to somewhere earlier than any date you're planning to use" and call it a day. We can even make date2num and friends set a global variable "a date conversion has been done" and make set_epoch error out if any date conversion has already been done (so that we don't end up with inconsistent epochs).

However I certainly also agree we may be overengineering this.

@tacaswell tacaswell modified the milestones: v3.2.0, needs sorting Sep 10, 2019
@QuLogic QuLogic modified the milestones: needs sorting, v3.3.0 Apr 29, 2020
@QuLogic
Copy link
Member

QuLogic commented Apr 29, 2020

This should be fixed by #15008, assuming you use a recent epoch.

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

No branches or pull requests

7 participants