Skip to content

Conversation

kshitijaucharmal
Copy link

@kshitijaucharmal kshitijaucharmal commented Oct 1, 2025

Description of proposed changes

This PR enhances the pygmt.grdcut function to support polygon-based subsetting of grids using the -F option. Users can now provide polygons in three different formats:

  • A geopandas.GeoDataFrame
  • A shapely.geometry.Polygon
  • A GMT ASCII polygon file

Additionally, two new boolean parameters, crop and invert, have been added to control how the polygon is applied:

  • crop=True crops the output grid region to the bounding box of the polygon.
  • invert=True inverts the selection, setting all nodes inside the polygon to NaN.

I have added both of these as parameters to grdcut, but they only apply to polygon mode. Please let me know if this is undesirable, and how would I implement this otherwise

A gallery example has been added to demonstrate all three polygon input methods and the effects of the crop and invert options, showing original, cropped, inverted, and cropped+inverted grids. This improves PyGMT’s functionality for extracting regions of interest from raster grids and makes the workflow more Pythonic and flexible.

Fixes #1529 (implements rather)

Preview: https://pygmt-dev--4135.org.readthedocs.build/en/4135/gallery/images/grdpolygon.html

Users can crop grids using polygons without manually creating ASCII files.
Example figure showing original grid and cropped and inverted grids

image

Reminders

  • Run make format and make check to make sure the code follows the style guide.
  • Add tests for new features or tests that would have caught the bug that you're fixing.
  • Add new public functions/methods/classes to doc/api/index.rst.
  • Write detailed docstrings for all functions/methods.
  • If wrapping a new module, open a 'Wrap new GMT module' issue and submit reasonably-sized PRs.
  • If adding new functionality, add an example to docstrings or tutorials.

@yvonnefroehlich yvonnefroehlich added hacktoberfest Hacking away in the month of October enhancement Improving an existing feature labels Oct 1, 2025
@yvonnefroehlich yvonnefroehlich added this to the 0.18.0 milestone Oct 1, 2025
@kshitijaucharmal
Copy link
Author

kshitijaucharmal commented Oct 1, 2025

@yvonnefroehlich I have added both of the +c and +i options as parameters to grdcut, but they only apply to polygon mode. Please let me know if this is undesirable, and how would I implement this otherwise

Also, the label is hacktoberfest-accepted (if you approve of this PR of course) :)

Copy link
Member

@weiji14 weiji14 left a comment

Choose a reason for hiding this comment

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

Thanks @kshitijaucharmal! Just a few comments for now. If you're able to add some unit tests to test_grdcut.py, that would be fantastic too!

- Checking for PathLike instead of str, bytes
- Inverted logic and comments to make it clearer
- Update gallery example:
  - removed "complex" from polygon desc.
  - improved docs
  - Switch CRS to OGC:CRS84
- Validated polygon input types, raising GMTValueError for unsupported types.
- Unit tests added for:
    - Shapely Polygon input
    - GeoDataFrame polygon input
    - GMT ASCII polygon file input
    - Crop (+c) and invert (+i) modifiers
    - Invalid polygon input type to raise error
@kshitijaucharmal
Copy link
Author

@weiji14 I have resolved all comments and added the unit tests as well, let me know if there are any more corrections! :)

@weiji14 weiji14 marked this pull request as draft October 2, 2025 06:18
Copy link
Member

@weiji14 weiji14 left a comment

Choose a reason for hiding this comment

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

Thanks for adding the unit tests! Here are some more comments, and apologies for the failing CI tests, we have some issues with DVC running on forks that we'll probably try to sort out next week.

Comment on lines 15 to 24
# Reusable polygon geometry
poly = Polygon(
[
(-52.5, -19.5),
(-51.5, -19.0),
(-50.5, -18.5),
(-51.5, -18.0),
(-52.5, -19.5),
]
)
Copy link
Member

Choose a reason for hiding this comment

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

This should be turned into a pytest fixture, see examples a few lines below.

Copy link
Author

Choose a reason for hiding this comment

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

Will convert this into a fixture

outgrid = grdcut(grid=grid, polygon=poly)
assert outgrid is not None
assert outgrid.rio.crs is None or str(outgrid.rio.crs) == "" # CRS not enforced
assert outgrid.size > 0
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 more precise assertion(s)? Ideally, you want to check the exact pixel count, and maybe also check that there are NaN values in the four corners or something.

Copy link
Author

Choose a reason for hiding this comment

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

I understand, for the polygon each vertex will need to not be NaN

polygon : str, geopandas.GeoDataFrame, or shapely.geometry
Extract a subregion using a polygon. Can be either:
- A GMT ASCII polygon file (`.gmt`)
- A geopandas.GeoDataFrame (must have CRS EPSG:4326)
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if that specific CRS is necessary, of if a CRS is needed actually. Other input types (ASCII file, shapely.geometry.Polygon) don't even have a CRS.

Extract a subregion using a polygon. Can be either:
- A GMT ASCII polygon file (`.gmt`)
- A geopandas.GeoDataFrame (must have CRS EPSG:4326)
- A shapely.geometry.Polygon or MultiPolygon
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 unit test to confirm that MultiPolygon does work?

@kshitijaucharmal
Copy link
Author

Thanks for adding the unit tests! Here are some more comments, and apologies for the failing CI tests, we have some issues with DVC running on forks that we'll probably try to sort out next week.

Yeah I was wondering why all the test keep failing
Anyways, will get back to you after resolving the comments

- Reusable polygon fixture for grdcut tests
- Improve assertions to check pixel counts and presence of NaNs outside polygons
- Add a test for MultiPolygon support
@kshitijaucharmal
Copy link
Author

I do not quite understand the precise assertions part, is checking for some pixels inside polygon to not be NaN enough? I hope the new cases are correct or at least in the right direction. Thanks !

@kshitijaucharmal kshitijaucharmal marked this pull request as ready for review October 3, 2025 10:00
@kshitijaucharmal kshitijaucharmal marked this pull request as draft October 3, 2025 10:01
@kshitijaucharmal kshitijaucharmal marked this pull request as ready for review October 3, 2025 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improving an existing feature hacktoberfest Hacking away in the month of October
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Subset grid using a geopandas.GeoDataFrame polygon with grdcut -F
3 participants