-
Notifications
You must be signed in to change notification settings - Fork 296
Refactor shape masking #6129
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
base: main
Are you sure you want to change the base?
Refactor shape masking #6129
Conversation
From @SciTools/peloton : discussed what we are seeing here and in #6126. |
Discussion with @acchamber notes:
|
What are @SciTools/peloton (@pp-mo) thoughts about adding This would facilitate better handling of shapes to rasters (which is essentially the problem we're solving) with the added bonus that we could also mask to other shape types, like lines, to extract a trajectory from a Cube, for example. |
I was planning on going to the AVD surgery this week to discuss some changes and/or make the case for rasterio |
Thanks for your patience everyone. It's sometimes a struggle to balance everything and we just haven't had an opportunity to discuss this. Coming to the Surgery (UK Met Office) is an ideal next step. |
@pp-mo, @trexfeathers and @stephenworsley have discussed this at the Surgery and agree in principle that we could consider adding rasterio as an optional dependency. |
for more information, see https://pre-commit.ci
From @SciTools/peloton: would @hsteptoe and @acchamber appreciate any more input from core devs at this point? |
I just need to find more time, which is in short supply as we get near the end of FY... |
This is now ready for some initial (alpha?) testing 🎉. @acchamber are you available to try out the new features? (Updates to docs etc. will follow if this is successful) Tests are incomplete are should not be review yet. This is a fairly substantial re-write. New/improved features include:
There are some breaking changes, principally moving away from having a My informal tests so far show working behaviour for iris test data from |
@stephenworsley @trexfeathers Can you advise on apparently And, do you know why my local pre-commit version of |
@hsteptoe really sorry for missing this. There is a MO-specific step you will need to do for the lockfiles, will message you offline. I'm less sure about pre-commit. There is some nuance about only testing files which have been edited; perhaps the merge from |
pre-commit related errors may have been something wrong going on with my pre-commit cache. Did a |
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.
Still left to review:
-
_shapefiles.py
- tests
- lock files
pyproject.toml
Outdated
[project.optional-dependencies] | ||
RASTERIO = ["rasterio"] | ||
|
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 didn't. However we are attempting to standardise across our repositories and we don't have an agreed way to handle optional dependencies, so please remove this entry.
cube: iris.cube.Cube, | ||
shape: shapely.Geometry, | ||
shape_crs: cartopy.crs | pyproj.CRS, | ||
in_place: bool = False, | ||
minimum_weight: float = 0.0, | ||
**kwargs, |
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.
You've changed the order of parameters. Anyone calling this without using keywords e.g. mask_cube_from_shapefile(my_cube, my_shape, 0.5, True)
will get a failure.
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.
Reverted back to depreciated function call, but have had to add a few extra lines to pull in a shape_crs
as per https://github.com/SciTools/iris/blob/fa6d61dd5f358c9e6b585a132cc213acebf95b70/lib/iris/_shapefiles.py#L142C18-L144C6
A number between 0-1 describing what % of a cube cell area must the shape overlap to be masked. | ||
Only applied to polygon shapes. If the shape is a line or point then this is ignored. | ||
Other Parameters |
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.
How did you decide which ones were kwargs
and which ones were named parameters?
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 decided that kwargs
would be parameters that are specifically used by rasterio
functions only, but I'm happy to expose them if that's clearer?
Extract a rectangular region covering the UK from a stereographic projection cube: | ||
>>> cube = iris.load_cube(iris.sample_data_path("toa_brightness_stereographic.nc")) |
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.
It would be great to print some one line Cube
summaries to demonstrate the effect that masking is having.
Example:
>>> cube = iris.load_cube(iris.sample_data_path("toa_brightness_stereographic.nc")) | |
>>> cube = iris.load_cube(iris.sample_data_path("toa_brightness_stereographic.nc")) | |
>>> print(cube.summary(shorten=True)) | |
toa_brightness_temperature / (K) (projection_y_coordinate: 160; projection_x_coordinate: 256) |
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.
Still left to review:
- tests
- lock files
- confirm stable behaviour given the heavy refactor
# to "OFF" in the environment. Having PROJ_NETWORK = "ON" | ||
# can lead to some coordinate transformations resulting in Inf values. |
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.
What a pointless feature! I'd be interested to know why.
lib/iris/_shapefiles.py
Outdated
if "iris.cube" in sys.modules: | ||
import iris.cube | ||
if "iris.analysis.cartography" in sys.modules: | ||
import iris.analysis.cartography |
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.
This is unprecedented. Something larger is wrong if these modules are not available.
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 can't remember anymore why I added this (!) so it's now removed.
w = len(x_coord.points) | ||
h = len(y_coord.points) | ||
# Mask by weight if minimum_weight > 0.0 | ||
if minimum_weight > 0: |
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 discussed preserving existing behaviour with minimum_weight
- #6129 (comment) - to avoid breaking changes. I'm having a hard time confirming this:
- The code for this behaviour has been heavily refactored
- The existing tests have been rewritten and can no longer be run in their original form due to API changes
Can you help? Do you have anything 'ready-made' that I can use to confirm stable behaviour? Otherwise I'll write something myself. Thanks
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.
The integration tests lib/iris/tests/integration/test_mask_cube_from_shape.py
include tests from the previous iteration of this function (which was itself benchmarking against ASCEND). Specifically, the tests test_4d_global_proj_brazil
, test_rotated_pole_proj_germany_weighted_area
and test_transverse_mercator_proj_uk
are testing against identical conditions. Would this be sufficient to confirm stable behaviour?
I have added warning text from _shapefiles
into utils
to emphasise behaviour change that may be seen as breaking behaviour (although this wasn't stable behaviour in the first place):
Because shape vectors are inherently Cartesian in nature, they contain no inherent
understanding of the spherical geometry underpinning geographic coordinate systems.
For this reason, **shapefiles or shape vectors that cross the antimeridian or poles
are not supported by this function to avoid unexpected masking behaviour**.
# Define raster transform based on cube | ||
# This maps the geometry domain onto the cube domain | ||
tr = _make_raster_cube_transform(cube) | ||
# Generate mask from geometry | ||
mask_template = rfeatures.geometry_mask( | ||
geometries=shapely.get_parts(geometry), | ||
out_shape=(h, w), | ||
transform=tr, | ||
all_touched=all_touched, | ||
) |
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.
Would you be up for giving me a 5 minute lesson about this?
Co-authored-by: Martin Yeo <[email protected]>
Co-authored-by: Martin Yeo <[email protected]>
Co-authored-by: Martin Yeo <[email protected]>
…bugfix-shape-masking
🚀 Pull Request
Description
Fixes #6126 by exposing the shape geometry to the user. Adds to docs and docstrings to make it clearer how to use this.
Consult Iris pull request check list
Add any of the below labels to trigger actions on this PR: