Skip to content

BF: for degenerate polygons, add CLOSEPOLY vertex #17982

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

Conversation

brunobeltran
Copy link
Contributor

@brunobeltran brunobeltran commented Jul 20, 2020

PR Summary

Fixes #17975. New iter_bezier code exposed an existing bug in patches.Polygon.set_xy.

The check xy[0] != xy[-1] was meant to check if the user had already included an extra CLOSEPOLY vertex for us in the list of vertices (shape(xy) = (N, 2)). But for single-vertex (degenerate) Polygons, it produced a false positive (since xy[0] == xy[-1] by definition), leading to malformed Paths that look like:

In [1]: from matplotlib.patches import Polygon
In [2]: pp = Polygon([[0, 0]])
In [3]: pp.get_path()
Out[3]: Path(array([[0., 0.]]), array([79], dtype=uint8))

PR Checklist

  • Has Pytest style unit tests
  • Code is Flake 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/next_api_changes/* if API changed in a backward-incompatible way

@brunobeltran brunobeltran added topic: path handling Release critical For bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. labels Jul 20, 2020
@brunobeltran brunobeltran force-pushed the closepoly-clobbers-poly-vertex branch from 33cc440 to 787bf03 Compare July 20, 2020 23:00
Copy link
Member

@QuLogic QuLogic left a comment

Choose a reason for hiding this comment

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

Add a test?

@QuLogic QuLogic added this to the v3.3.1 milestone Jul 20, 2020
@brunobeltran brunobeltran force-pushed the closepoly-clobbers-poly-vertex branch from 787bf03 to e551a27 Compare July 20, 2020 23:13
@brunobeltran
Copy link
Contributor Author

Add a test?

Couldn't decide what to test initially. Settled on testing that for a single point (x, y), the extents of a degenerate polygon with only that point as its vertices has the extents Bbox([[x, y], [x, y]]), which is the behavior where we actually differ from the (buggy) 3.2 behavior.

@jklymak
Copy link
Member

jklymak commented Jul 20, 2020

I'm sure this was covered in the other PR, but what happens if x=np.Nan?

@brunobeltran
Copy link
Contributor Author

tl;dr: NaN works.

The Polygon class doesn't complain about NaN's or clean them explicitly (currently. You might argue that it should).

So Polygon([[np.nan, 0]]) creates a path that would be correct if there were no NaN's there: Path([[np.nan, 0], [np.nan, 0]], [MOVETO, CLOSEPOLY]). The new Path.get_extents blindly adds all possible extremal values to a Bbox.null() (which in this case are all NaN). Adding a NaN to a Bbox is a no-op, (the call chain ends in _path.update_path_extents, which works on a PathNaNRemover<agg:conv_transform<PathIterator>>), so the Bbox stays null, correctly indicating there are no non-NaN points in the polygon.

@brunobeltran
Copy link
Contributor Author

CI fail is due to "error allocating resources" on our Mac box?

@jklymak
Copy link
Member

jklymak commented Jul 21, 2020

... the mac CI on azure seems to have issues

if self._closed:
if len(xy) and (xy[0] != xy[-1]).any():
if N == 1 or N > 1 and (xy[0] != xy[-1]).any():
Copy link
Member

Choose a reason for hiding this comment

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

Could you add a quick comment about the if statements you've changed just to say what they're doing? And maybe nverts is a better variable name than just N?

Copy link
Contributor Author

@brunobeltran brunobeltran Jul 21, 2020

Choose a reason for hiding this comment

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

I was reticent to add these comments, because technically the checks here are very brittle as-written, so I didn't want to give people the impression this is something which is okay to do in other code.

The checks are bad because we don't guarantee anything about the coordinates of a CLOSEPOLY vertex, but this code uses the assumption that these vertices will "correctly" match the start point of the curve.

In particular, both Python (e.g. Path.iter_bezier) and C++ code (i.e. handlers for agg:path_flags_close) actively ignore this vertex's value, because it's known to hold "trash" sometimes, especially after cleaning NaN arrays, etc (weird stuff like #17885 and #17914).

But, I added comments that make it more clear what the if statements are nominally doing, since you think it's a good idea. I personally like N since it matches what all the Polygon docstrings use, but I agree that nverts is easier to read if you're skimming the code only.

@brunobeltran brunobeltran force-pushed the closepoly-clobbers-poly-vertex branch from e551a27 to 1a1c288 Compare July 21, 2020 14:51
@brunobeltran brunobeltran force-pushed the closepoly-clobbers-poly-vertex branch from 1a1c288 to 0d5c018 Compare July 21, 2020 15:02
@QuLogic QuLogic merged commit 21c3e3f into matplotlib:master Jul 22, 2020
meeseeksmachine pushed a commit to meeseeksmachine/matplotlib that referenced this pull request Jul 22, 2020
QuLogic added a commit that referenced this pull request Jul 22, 2020
…982-on-v3.3.x

Backport PR #17982 on branch v3.3.x (BF: for degenerate polygons, add CLOSEPOLY vertex)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Release critical For bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. topic: path handling
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Computing the bounding box of a degenerate polygon throws an error
4 participants