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
Bug fixes in WCSAxes.plot_coord #8927
Conversation
Is this addressing any existing Astropy issue(s)? Also please add change log and tests. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple of comments below - thanks!
@@ -299,7 +304,7 @@ def plot_coord(self, *args, **kwargs): | |||
raise TypeError("The 'transform' keyword argument is not allowed," | |||
" as it is automatically determined by the input coordinate frame.") | |||
|
|||
transform = self.get_transform(frame0) | |||
transform = self.get_transform(native_frame) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can maybe just do 'world'
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did that at one point but this seemed easier to read. Is there a good reason for one or the other?
elif coord.coord_type == 'latitude': | ||
plot_data.append(frame0.data.lat.to_value(coord.coord_unit)) | ||
plot_data.append(frame0.spherical.lat.to_value(u.deg)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder whether it would make sense to only access spherical
if the current representation is not spherical
or unitspherical
, for performance? Or at least pre-compute frame0.spherical
to avoid computing it twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that frames cache their different representations anyway, so this should be basically free on both counts.
Possible regression test (fails pretty badly with master): from astropy import units as u
from astropy.wcs import WCS
from astropy.coordinates import SkyCoord
from astropy.utils.data import get_pkg_data_filename
from astropy.io import fits
import matplotlib.pyplot as plt
filename = get_pkg_data_filename('galactic_center/gc_msx_e.fits')
wcs = WCS(filename)
data = fits.getdata(filename)
coord = SkyCoord(0 * u.kpc, 0 * u.kpc, 0 * u.kpc, frame='galactocentric')
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=wcs)
ax.imshow(data)
ax.plot_coord(coord, 'ro')
fig.savefig('galcen.png') The marker should be at the center of the image. |
@astrofrog Not sure what the procedure is for the image tests? |
The image test docs are here: http://docs.astropy.org/en/stable/development/testguide.html#image-tests-with-pytest-mpl However, can't you just check the pixel coordinates of the resulting marker without doing a full image test? (which seems overkill here) |
@astrofrog I changed the test. Can you take a look to check I am comparing it to the right thing? Also I changed the isort config because I needed to use isort. |
ax.imshow(data) | ||
point, = ax.plot_coord(coord, 'ro') | ||
|
||
np.testing.assert_allclose(point.get_xydata()[0], [0, 0], atol=1e-4) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised that this would be at [0,0], it should be near the center of the image.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah this one confused me as well. is get_xydata
in pixels?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it should be 😕
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah no I think it might be the data before applying the transform
. So to some extent this test is correct but I'd still be happier if we can figure out how to get the transformed data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might need point.get_transform().transform(point.get_xydata())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That didn't work either, I can't see any other sensible solution other than this here 😕
This means the transform can be 3D without having to interact with the mpl transforms infrastructure.
7532a66
to
4c2012e
Compare
4c2012e
to
f9ad9c0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, and thanks for fixing the isort config!
Bug fixes in WCSAxes.plot_coord
@@ -289,12 +290,16 @@ def plot_coord(self, *args, **kwargs): | |||
if isinstance(frame0, SkyCoord): | |||
frame0 = frame0.frame | |||
|
|||
native_frame = self._transform_pixel2world.frame_out |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't work on 3.2.2:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <astropy.visualization.wcsaxes.core.WCSAxes object at 0x13297d210>
args = (<SkyCoord (ICRS): (ra, dec) in deg
(359.76045223, 0.26876217)>, 'o')
kwargs = {'transform': <matplotlib.transforms.CompositeGenericTransform object at 0x131f72190>}
frame0 = <ICRS Coordinate: (ra, dec) in deg
(359.76045223, 0.26876217)>
def plot_coord(self, *args, **kwargs):
"""
Plot `~astropy.coordinates.SkyCoord` or
`~astropy.coordinates.BaseCoordinateFrame` objects onto the axes.
The first argument to
:meth:`~astropy.visualization.wcsaxes.WCSAxes.plot_coord` should be a
coordinate, which will then be converted to the first two parameters to
`matplotlib.axes.Axes.plot`. All other arguments are the same as
`matplotlib.axes.Axes.plot`. If not specified a ``transform`` keyword
argument will be created based on the coordinate.
Parameters
----------
coordinate : `~astropy.coordinates.SkyCoord` or `~astropy.coordinates.BaseCoordinateFrame`
The coordinate object to plot on the axes. This is converted to the
first two arguments to `matplotlib.axes.Axes.plot`.
See Also
--------
matplotlib.axes.Axes.plot : This method is called from this function with all arguments passed to it.
"""
if isinstance(args[0], (SkyCoord, BaseCoordinateFrame)):
# Extract the frame from the first argument.
frame0 = args[0]
if isinstance(frame0, SkyCoord):
frame0 = frame0.frame
> native_frame = self._transform_pixel2world.frame_out
E AttributeError: 'WCSAxes' object has no attribute '_transform_pixel2world'
astropy/visualization/wcsaxes/core.py:295: AttributeError
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(relies on the reorganization from #8874)
This fixes two bugs in
plot_coord
:.spherical
rather than.data
to getlon
andlat
.The latter is a fix because the matplotlib transforms are only ever two dimensional, and it should not be assumed that the input coordinate to
plot_coord
is two dimensional, as it can be in any frame transformable to the native frame of the plot.I can't really think of a way to test this with just the astropy frames, if anyone has any suggestions of a transformation which would work in 3D but not 2D in astropy frames that would be great.
ping @ayshih