-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Use transformed paths for contour labelling decisions #26297
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
Conversation
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.
If I'm following this update, I think the biggest change here is that you are calling transform_path(path)
instead of transform(path.vertices)
, which for Cartopy is critical because they override transform_path
to account for nonlinear transforms, while if we just transform all of the vertices that may be incorrect for a curved path along those vertices.
Would it make sense for Cartopy to trigger the non-linear transform, create all the transformed paths, then use those paths and set the transform to ax.transAxes
before calling this as a super class method? Similar to what Cartopy was doing before, but rather than each individual path I'm wondering if you can replace the transform on the object without iterating through all the paths.
for subpath in trans.transform_path( | ||
self._paths[icon])._iter_connected_components(): | ||
screen_xys = subpath.vertices |
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 could save the inverse transform below by leaving the for loop as it was, and then calculating tsubpath = trans.transform_path(subpath)
inside the loop and then use subpath/tsubpath in the right locations below.
@greglucas thanks, yes you have nailed it! Solution now at SciTools/cartopy#2213 Everybody else: sorry for the noise! |
Still might be worth having Matplotlib do the right thing here? I think the current assumption within MPL's contour code is: |
I don't know about the transformed vertices. I think the main issue I'm seeing is because the transformed path has a different set of codes (i.e. it has more MOVETOs). But I am pretty far out of my depth with this... |
Can this be reproduced just using log/log and contour labelling? Or is there something fancy about cartopy's projections that make things more complicated? |
I do not know but I think it’s because Cartopy wraps the data around the world. For the test in question, it generates data with longitudes [0, 360] and plots a map with longitudes [-180, 180]. So some paths get broken (have more MOVETOs added) when they are transformed from data space to axes/screen space. |
Yes, Cartopy adds points to a line if the segment is long enough and wouldn't necessarily be straight. Think of some projections where you wouldn't want your line to be rendered straight, but rather you'd want it to be rendered as a curve (great circle arcs and the like). There are some thresholds you can set to how "smooth" you want that line approximation to be, and therefore how many points that get added can be variable. For lines |
That makes some sense. However, ignorant of the details, I wonder if I'd not do that for contours. It seems that if a contour is so long that it's straight in lat/Lon space it's probably ok for it to be straight in the projection? Eg the data is very sparse and it doesn't matter? |
Yeah, I think your comment is basically getting at where to do the contouring in data-space or in projected-data space. Contouring in Cartopy now has a "transform_first" option so that you can project all points and then do the contouring in projected space, rather than in data space, which does speed things up a lot (this is more akin to Basemap). https://scitools.org.uk/cartopy/docs/latest/gallery/scalar_data/contour_transforms.html#sphx-glr-gallery-scalar-data-contour-transforms-py |
Cool. But I'm also saying that path complication doesn't seem necessary for contours. The line segments tend to be of similar size to the data resolution, and exactly whether the line is straight in data space or screen space shouldn't matter. |
PR summary
In Cartopy, contour paths can wrap around the edges of the globe. So a path that would be complete in data space can break into segments in screen space. Matplotlib's contour labelling has never accounted for this.
Currently, Cartopy has a workaround where it removes all the paths from each
PathCollection
, transforms them to axes space, and adds them back in (sometimes as more shorter paths). The changes introduced at #25247 break the workaround (SciTools/cartopy#2207). I tried removing the workaround and found the test image gets a spurious horizontal line around 45 degrees north, where the label is being inserted right on the edge.This PR proposes transforming the paths to screen space before making the decisions about where to put the labels and how to update the paths. With this change (and a smaller font) we now get
I see two problems:
PR checklist