Skip to content

Conversation

@chay0112
Copy link
Contributor

Did you read the Contributor Guide?

Is this PR related to a ticket?

What changes were proposed in this PR?

  • Implement concave_hull functionality

How was this patch tested?

  • Included unit and parity tests

Did this PR include necessary documentation updates?

  • Yes, I have updated the documentation.

@chay0112
Copy link
Contributor Author

chay0112 commented Nov 26, 2025

Hi @petern48

I'm encountering a test failure in our Sedona/GeoPandas parity suite for concave_hull(Passing in my local). The error is due to the vertex order of polygons returned by Sedona and GeoPandas being different, even though the polygons are geometrically identical. Our current comparison uses equals_exact(assert_geometry_almost_equal), which might be sensitive to vertex order:

=========================== short test summary info ============================ FAILED tests/geopandas/test_match_geopandas_series.py::TestMatchGeopandasSeries::test_concave_hull - ValueError: Geometry equality check failed for POLYGON ((1 4, 3 4, 4 4, 3 1, 4 0, 0 0, 1 1, 0 4, 1 4)) and POLYGON ((1 4, 3 4, 4 4, 4 0, 3 1, 0 0, 1 1, 0 4, 1 4))

https://github.com/apache/sedona/actions/runs/19687051539/job/56394868966?pr=2529

Would it be acceptable to change our comparison from equals_exact to equals for polygons, so that we check geometric equality rather than strict vertex order? Or is there a recommended workaround for this situation, or something I might be missing in our test setup?

Thank you for your guidance!

Comment on lines +749 to +753

mixed = [self.points[1], self.linestrings[1], self.polygons[1], None]
sgpd_result = GeoSeries(mixed).concave_hull()
gpd_result = gpd.GeoSeries(mixed).concave_hull()
self.check_sgpd_equals_gpd(sgpd_result, gpd_result)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
mixed = [self.points[1], self.linestrings[1], self.polygons[1], None]
sgpd_result = GeoSeries(mixed).concave_hull()
gpd_result = gpd.GeoSeries(mixed).concave_hull()
self.check_sgpd_equals_gpd(sgpd_result, gpd_result)

I don't think this test is necessary. We're already testing all of those cases separately in the for geom in self.geoms above. The function is executed on each geometry separately, so whether they're mixed together or not doesn't matter.

Comment on lines +730 to +733
for geom in self.geoms:
sgpd_result = GeoSeries(geom).concave_hull()
gpd_result = gpd.GeoSeries(geom).concave_hull()
self.check_sgpd_equals_gpd(sgpd_result, gpd_result)
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should test multiple ratio values here, not just the default of 0.0. We could do something like: Do one third of the iterations w/ 0.0, then the next third w/ 0.5, and the last third w/ 1.0. (Note the range of valid values for this argument is [0, 1].

Then also test allow_holes below (as you already are doing).

crs=3857,
)

result = s.concave_hull()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would be nice to have a test for allow_holes=True in this file too. But we should first get to the bottom of the errors.

@petern48
Copy link
Collaborator

Would it be acceptable to change our comparison from equals_exact to equals for polygons, so that we check geometric equality rather than strict vertex order? Or is there a recommended workaround for this situation, or something I might be missing in our test setup?

The issue is not whether we're using equals_exact() or equals(). If you give it a try, you'll see that the comparison fails either way. Despite the name, equals_exact is actually more lenient, since it supports a tolerance parameter.

Script to test using equals instead
import shapely
geom1 = shapely.wkt.loads("POLYGON ((1 4, 3 4, 4 4, 3 1, 4 0, 0 0, 1 1, 0 4, 1 4))")
geom2 = shapely.wkt.loads("POLYGON ((1 4, 3 4, 4 4, 4 0, 3 1, 0 0, 1 1, 0 4, 1 4))")
print(geom1.equals(geom2))  # False
print(geom1.equals_exact(geom2, 0.000001))  # False
Images to visualize the different results image image

As you can see above, these geometries actually are different. Why this is happening, I'm not sure. It could either be a bug in Sedona's function or a difference in algorithms or edge case behaviors. If it's a significant bug, we may want to hold off. If it's a reasonable difference in behavior that's still correct, we can add a note in the docs and merge this anyway. Either way, we need to understand what's happening before merging. I encourage you to investigate, though you're not obligated to, of course, and can continue with something else instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Geopandas: Implement concave_hull

2 participants