Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add a new time_support context manager for plotting times #8782

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

Merged
merged 23 commits into from
Jun 16, 2019

Conversation

astrofrog
Copy link
Member

@astrofrog astrofrog commented Jun 1, 2019

Matplotlib natively provides a mechanism for plotting dates and times on one or both of the axes, as described in Date tick labels. To make use of this, users need to explicitly access plot_date on time instances they want to plot. While this might be ok for a number of situations, I thought it would be nice to have a way of more seamlessly using times when plotting that gives more control over the time scale and format.

This PR implements a time_support context manager/function that is meant to be similar to quantity_support:

from matplotlib import pyplot as plt
from astropy.time import Time
from astropy.visualization import time_support

time_support()

plt.figure(figsize=(5,3))
plt.plot(Time([58000, 59000, 62000], format='mjd'), [1.2, 3.3, 2.3])

matplotlib_integration-3

(by default the time is removed from the ISO string if it's always midnight for all tick labels, this can be controlled with the simplify argument).

This can be used as a context manager and can take the format and scale to use for the axis:

with time_support(format='mjd', scale='tai'):
    plt.figure(figsize=(5,3))
    plt.plot(Time([58000, 59000, 62000], format='mjd'))

matplotlib_integration-5

Note that this also allows Time to be used in set_xlim/set_ylim for example. One of the benefits of this approach is that all times are automatically converted to a common scale/format.

A few notes:

  • Something which I'm not entirely happy with, which also affects quantity_support, is that even when using the context manager, once an axis has been used inside the context manager, it has a cache of the converter and it's impossible to change it again later. I think this is something that would need to be fixed in MPL though. As long as a new axis/figure is created, then the context manager works fine.

  • I'm also not really fond of the current names quantity_support and time_support, I feel there should be a plot or mpl in there somewhere so it's clear that it's related to plotting.

  • I've consolidated the docs to mention quantity_support and time_support in one place, in the visualization docs.

  • There is still some cleanup to do in various places and I think I can expand the docs and tests a little, but I don't want to invest too much time until I hear whether people are interested in this. I need this anyway for another project so I decided to implement it here, but it's ok if people would prefer not to include it!

Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks very nice! Some in-line comments, the largest one of which is that it would be nice if the default scale and format were taken from the (first) input times.

On the names: I guess one could go for mpl_quantity_support, but that certainly doesn't seem worth the trouble of changing the name.

Should there be an matplotlib_astropy_support, though, where all these options get turned on?

But those questions are probably best addressed separately.

YMDHMS_FORMATS = ('fits', 'iso', 'isot')


def time_support(scale='utc', format='isot', simplify=True):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to have the default set by the times first used? (say, scale=None here)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, this will be consistent with quantity_support - fixed

"""
scaled = getattr(value, self.scale)
if self.format in YMDHMS_FORMATS:
return scaled.mjd
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this done to make the values numerical? But, if so, shouldn't it happen for all string formats? For best precision for relevant times, one might consider using cxcsec or so.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now fixed compatibility for all string formats (and have tests for all of them).

@@ -0,0 +1,121 @@
.. _quantity:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link seems wrong.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

@astrofrog
Copy link
Member Author

@mhvk - thanks for the initial review! You mentioned that using MJD might not be ideal, so I was wondering whether, since you are intimately familiar with astropy.time, you would mind trying out this PR and finding cases where the precision doesn't work properly?

One use case I know of already that needs to be fixed is when looking at very small time intervals, the string-based formats need to have their precision updated (they are currently fixed to millisecond precision). But it would be great if you could let me know if you can find other cases that won't work properly/optimally!

@astrofrog
Copy link
Member Author

This whole functionality doesn't work very well with Matplotlib 2.0 just because of the way that it dealt with non-numpy arrays back then (it split the Time array into a list of many times, and same for Quantity). Since Matplotlib 2.1, 2.2, 3.0 and 3.1 are out now and 2.0 is over two years old, maybe we can just drop it? (rather than have to add convoluted workarounds here).

Copy link
Member

@larrybradley larrybradley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@astrofrog LGTM, thanks! I'm fine with dropping support for matplotlib 2.0. I don't think it's worth the trouble.

@larrybradley
Copy link
Member

larrybradley commented Jun 3, 2019

The travis test failures look real.

@mhvk
Copy link
Contributor

mhvk commented Jun 3, 2019

@astrofrog - using mjd means the best possible precision is

np.spacing(Time.now().mjd * u.day).to(u.us)
# <Quantity 0.62864274 us>

This is probably good enough for most purposes...

But it brings up a different question: do you also handle TimeDelta? I think those should just be treated as Quantity...

@astrofrog
Copy link
Member Author

@mhvk - just to check, do you mean we should support it in quantity_support or in time_support? It would be much cleaner to support it in the former. I guess this wouldn't matter if we then introduce a context manager such as matplotlib_astropy_support which enables all options like you suggest.

@mhvk
Copy link
Contributor

mhvk commented Jun 7, 2019

@astrofrog - yes, you're right, TimeDelta is more logically supported in quantity_support.

I do think an overall astropy_support makes sense; one really shouldn't want one without the other. Indeed, in implementing support for the new __array_function__ (which allows all numpy functions to work on quantities!), I'm finding that plain plot(q1, q2) starts breaking (because quantities are no longer interpreted as plain ndarray). So, the recommendation may well become to always have astropy_support on when plotting.

@astrofrog
Copy link
Member Author

@mhvk @larrybradley - this is now ready for a final review (I think TimeDelta and the joint context manager should be handled in a separate PR)

@codecov
Copy link

codecov bot commented Jun 14, 2019

Codecov Report

Merging #8782 into master will increase coverage by 0.02%.
The diff coverage is 97.67%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #8782      +/-   ##
==========================================
+ Coverage   86.99%   87.01%   +0.02%     
==========================================
  Files         400      401       +1     
  Lines       59469    59598     +129     
  Branches     1100     1100              
==========================================
+ Hits        51736    51861     +125     
- Misses       7092     7096       +4     
  Partials      641      641
Impacted Files Coverage Δ
astropy/visualization/__init__.py 100% <100%> (ø) ⬆️
astropy/visualization/time.py 97.65% <97.65%> (ø)
astropy/samp/hub.py 77.38% <0%> (-0.14%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 41930f7...899f0ee. Read the comment docs.

@codecov
Copy link

codecov bot commented Jun 14, 2019

Codecov Report

Merging #8782 into master will increase coverage by 0.02%.
The diff coverage is 97.67%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #8782      +/-   ##
==========================================
+ Coverage   86.99%   87.01%   +0.02%     
==========================================
  Files         400      401       +1     
  Lines       59469    59598     +129     
  Branches     1100     1100              
==========================================
+ Hits        51736    51861     +125     
- Misses       7092     7096       +4     
  Partials      641      641
Impacted Files Coverage Δ
astropy/visualization/__init__.py 100% <100%> (ø) ⬆️
astropy/visualization/time.py 97.65% <97.65%> (ø)
astropy/samp/hub.py 77.38% <0%> (-0.14%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 41930f7...5f7cdf7. Read the comment docs.

Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! One in-line question about whether we should raise the minimum version of matplotlib to 2.2 for astropy 4.0. But obviously that's no reason to hold up this PR, so approving.

Would be good to raise separate issues for

  • Support for TimeDelta - in the next matplotlib release, these will be captured by this time_support (as a subclass of Time), so we need an explicit solution (this probably needs a 4.0 milestone).
  • Combined astropy_support. Possibly with the question of whether we should turn both on by default...

Convert a Time value to a scalar or array.
"""

# For Matplotlib < 2.2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we increase our minimum version?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I already just increased it to 2.1 from 2.0, but we could consider increasing further especially given the 2 year support for 4.0. I wish we had a written down policy for this :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably OK to leave for later: #8822 (comment)

Copy link
Member

@larrybradley larrybradley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @astrofrog! Just one little inline nit about the parameter order in the docstring.

@astrofrog
Copy link
Member Author

@mhvk issues opened in #8859 and #8860

@mhvk
Copy link
Contributor

mhvk commented Jun 16, 2019

Thanks for raising the issues. SInce @larrybradley's comment was addressed, and he was happy otherwise, I'll merge now - very nice to have this!!

@mhvk mhvk dismissed larrybradley’s stale review June 16, 2019 12:43

Requested changes were made

@mhvk mhvk merged commit 62c3857 into astropy:master Jun 16, 2019
@mhvk
Copy link
Contributor

mhvk commented Jun 16, 2019

Hmm, having done it, not sure that the right way is to "dismiss a review"....

pllim added a commit to pllim/astropy that referenced this pull request Jan 25, 2023
and remove unnecessary code added in astropy#8818 and astropy#8782
@pllim pllim mentioned this pull request Jan 25, 2023
10 tasks
pllim added a commit to pllim/astropy that referenced this pull request Jan 25, 2023
and remove unnecessary code added in astropy#8818 and astropy#8782
pllim added a commit to pllim/astropy that referenced this pull request Jan 26, 2023
and remove unnecessary code added in astropy#8818 and astropy#8782
pllim added a commit to pllim/astropy that referenced this pull request Jan 30, 2023
and remove unnecessary code added in astropy#8818 and astropy#8782

Add new JSON for figure tests.
dougbrn pushed a commit to dougbrn/astropy that referenced this pull request Mar 13, 2023
and remove unnecessary code added in astropy#8818 and astropy#8782

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

Successfully merging this pull request may close these issues.

4 participants