Skip to content
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

fix treatment of spine paths with explicit path-codes #2362

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

raphaelquast
Copy link
Contributor

Rationale

The current implementation of the adjust_location method of GeoSpines assumes that the spine-path is a single connected path and potential path-codes are ignored.

This causes problems if multi-paths are used as bounaries to clip the map (e.g. with ax.set_boundary().... for example:

image

Implications

With the proposed changes, path-codes are preserved and multi-path clipping works as expected

image

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

In case the GeoSpine path represents a multi-path, don't attemt to close
it since this would convert the multi-path into a single closed path
resulting in unwanted connector-lines between the individual polygons.
@raphaelquast
Copy link
Contributor Author

@greglucas
I saw that you initially introduced this change a few months ago to avoid

"... a small gap at the corner of closure due to the capstyle of the lines being "butt" by default".

To keep your changes for single closed paths, I've implemented the fix so that it only triggers if the path actually represents a multi-path (e.g. if it contains more than 1 MOVETO code).

@raphaelquast
Copy link
Contributor Author

Tests fail with HTTP Error 502: Bad Gateway... I guess they require a re-run?

@greglucas
Copy link
Contributor

Is there a way to do something like: if not path.closed(): close_the_path

One other thought is that perhaps the previous fix was actually a non-ideal one where self._path = mpath.Path(self._path.vertices, closed=True) is going to remove the final vertex from the path, but I think we actually might want to append the beginning vertex to the end and then close so we don't drop a point?

This should get a test somehow, can you modify your example figure output to count moveto/close before/after this change?

Closing is hereby performed by appending the first vertex with a CLOSEPOLY
code rather than treating the last vertex as CLOSEPOLY to avoid gaps at
the corner.
@raphaelquast
Copy link
Contributor Author

Hey, @greglucas, thanks for the quick response!

One other thought is that perhaps the previous fix was actually a non-ideal one where self._path = mpath.Path(self._path.vertices, closed=True) is going to remove the final vertex from the path, but I think we actually might want to append the beginning vertex to the end and then close so we don't drop a point?

I had a quick look... it seems that using Path(..., closed=True) actually just replaces all path-codes with this:

...
elif closed and len(vertices):
    codes = np.empty(len(vertices), dtype=self.code_type)
    codes[0] = self.MOVETO
    codes[1:-1] = self.LINETO
    codes[-1] = self.CLOSEPOLY

I agree that this might cause problems if the last vertex and the first should actually be connected.
CLOSEPOLY is described in the docs as:

- CLOSEPOLY: 1 vertex (ignored)
   Draw a line segment to the start point of the current polyline.

I've now updated the PR to perform a more complete check and make sure that the path (and all potential sub-paths) are properly closed with the start-vertex.


This should get a test somehow, can you modify your example figure output to count moveto/close before/after this change?

For the currently implemented method I don't think it's necessary to count since Path(..., closed=True) will simply replace all codes as indicated above.

If you agree with my proposed solution, I can write a test for GeoSpine._ensure_path_closed() that checks some potential use-cases (e.g. treatment of single closed path, single open path, multi-paths etc.).

@raphaelquast
Copy link
Contributor Author

Test-failure is again just a download-issue.

@greglucas
Copy link
Contributor

@raphaelquast , some tests would be good regardless of the solution I think! You've definitely found some issues, so codifying those with tests would be great.

I think this is good. I do have some concern that this is in a potential hot-loop when zooming/panning around, but the fix looks like the "proper" solution to account for the various cases.

@raphaelquast
Copy link
Contributor Author

@greglucas I've now added some basic unittests to check proper handling of single- and multi-path boundaries (based on image-comparison)

@raphaelquast
Copy link
Contributor Author

Test failures are again unrelated but I don't seem to have the rights to trigger a manual re-run.

@raphaelquast
Copy link
Contributor Author

Hey, just checking in to see what's missing to get this merged?

  • Test failures after re-run still don't relate to this PR but to WFS connection issues)
  • I've contributed to cartopy before... as far as I remember I've already signed the CLA back then... do you need me to re-sign it?

Copy link
Contributor

@greglucas greglucas left a comment

Choose a reason for hiding this comment

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

Sorry, been really busy on other projects the past month and lost track of this, thanks for the ping!

CLA
Yes, you should sign it again. There is a new CLA on all SciTools contributions now. It is a much simpler process and should take place immediately instead of needing a human to review it.

Code
Did you look at this as an option for closing the polygons? https://matplotlib.org/stable/api/path_api.html#matplotlib.path.Path.to_polygons
Specifically, this comment catches my eye saying any unclosed polys will be closed:

If closed_only is True (default), only closed polygons, with the last point being the same as the first point, will be returned. Any unclosed polylines in the path will be explicitly closed.

Testing
Are you able to put all of those tests into a single image with subplots to reduce the number of image comparisons/binary data you're adding?

Is there a way to test this without image comparisons. Our image comparisons are always fragile, so I'm wondering if you can say something like "before this change the boundary path had only 1 CLOSEPOLY, now it should have 5".

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

Successfully merging this pull request may close these issues.

None yet

3 participants