-
Notifications
You must be signed in to change notification settings - Fork 365
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: create a single inverted polygon when no exteriors found #2470
base: main
Are you sure you want to change the base?
Conversation
if polygon_bits: | ||
multi_poly = sgeom.MultiPolygon(polygon_bits) | ||
else: | ||
multi_poly = sgeom.MultiPolygon() |
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.
Note that MultiPolygon
will work fine with an empty list.
interior_polys.append(polygon) | ||
elif isinstance(polygon, sgeom.MultiPolygon): | ||
interior_polys.extend(polygon.geoms) | ||
elif isinstance(polygon, sgeom.GeometryCollection): |
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.
We do get a GeometryCollection
for the #1149 case.
I note that |
I appear to be reinventing part of #1739... |
I agree. Simplifying these down would really help us debug future issues too because I feel like it is confusing what the root cause of the issue is sometimes. A few thoughts in case this sparks anything.
That has a lot going on. Maybe this is a small piece of that and we can keep doing incremental updates? |
OK here's the simplest I have so far by studying #1149 (comment) import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import shapely.geometry as sgeom
sudo_ocean = sgeom.Polygon([(-180, -80), (180, -80), (180, 90), (-180, 90)],
[[(-50, -50), (-50, 0), (0, 0), (0, -50)]])
fig = plt.figure(figsize=(6, 8))
ax1 = fig.add_subplot(2, 1, 1, projection=ccrs.PlateCarree())
proj = ccrs.LambertAzimuthalEqualArea(central_latitude=45, central_longitude=-100)
ax2 = fig.add_subplot(2, 1, 2, projection=proj)
for ax in [ax1, ax2]:
ax.add_geometries(sudo_ocean, crs=ccrs.PlateCarree())
ax.set_global()
plt.show() |
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.
Should I remove the image test?
multi_polygon = proj.project_geometry(poly) | ||
# Should project to single polygon with multiple holes | ||
assert len(multi_polygon.geoms) == 1 | ||
assert len(multi_polygon.geoms[0].interiors) >= 2 |
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.
We actually get 36 holes. I assume most of them are responsible for the seam down the dateline visible in #2470 (comment). I didn't assert the exact number because I've no idea how stable that would be.
Against main, this test fails at the first assert
since we have two polygons in our multipolygon.
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 would remove the image test since it is downloading the natural earth ocean for every runner, or replace it with this example as an image comparison test that doesn't require external downloading.
The 36 holes is interesting and worth investigating IMO. For your example here, it looks like there are many small loops around the boundary points that are created. (your image has a small white curve/line in it protruding from the south pole area which are these linear rings I think)
import matplotlib.pyplot as plt
ax = plt.figure().add_subplot()
interior = multi_polygon.geoms[0].interiors
for i in range(len(interior)):
ax.plot(*interior[i].xy)
plt.show()
I wonder if these extra loops/rings are what is slowing down some of our projecting of geometries even 🤔
I'm also happy to defer these investigations to future PRs because this is already a pretty substantial improvement I think.
30a704f
to
b57388e
Compare
Rationale
When
_rings_to_multipolygon
finds interior rings without associated exteriors, for each of these interiors it creates a new polygon as the difference between ~the whole map and that interior. Intuitively, if there are multiple interiors, then all of those whole map polygons will overlay each other and you won't see the holes. Instead it should create a single ~whole map polygon which uses all of those left over interiors.I also switched out use of
.buffer(0)
forshapely.make_valid
as that seems like the more official way to do that.Fixes #1149, fixes #1674, fixes #2160 (all ocean feature examples) and fixes #1449 (
contourf
example)Also fixes the original case from #2030 (but not the second example so not linking that issue)
Also fixes the
contourf
examples at #1076 (comment) and #1076 (comment)I turned #1149 into an image test. Really there should be something more specific in
test_polygon.py
, but I'm at a loss how to create an artificial example for this.Implications