Skip to content
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

Convert AreaDefinitions to odc geoboxes #545

Merged
merged 14 commits into from
Dec 13, 2023
Merged
1 change: 1 addition & 0 deletions continuous_integration/environment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ dependencies:
- pytest-lazy-fixture
- importlib-metadata
- sphinx-reredirects
- odc-geo
13 changes: 13 additions & 0 deletions pyresample/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -1972,6 +1972,19 @@
return "EPSG:{}".format(self.crs.to_epsg())
return self.crs.to_proj4()

def to_odc_geobox(self):
"""Convert AreaDefinition to ODC GeoBox.

See: https://odc-geo.readthedocs.io/en/latest/
"""
try:
from odc.geo.geobox import GeoBox
except ModuleNotFoundError:
raise ModuleNotFoundError("Please install 'odc-geo' to use this method.")

Check warning on line 1983 in pyresample/geometry.py

View check run for this annotation

Codecov / codecov/patch

pyresample/geometry.py#L1982-L1983

Added lines #L1982 - L1983 were not covered by tests

return GeoBox.from_bbox(bbox=self.area_extent, crs=self.crs,
resolution=np.mean([self.pixel_size_x, self.pixel_size_y]), tight=True)
Copy link
Member

Choose a reason for hiding this comment

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

I think resolution can be a 2 element pair using the Resolution class:

https://odc-geo.readthedocs.io/en/latest/_api/odc.geo.Resolution.html#odc.geo.Resolution

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I know I can't really remember why I didn't use it but will check and change it eventually.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed it to use the Resolution class. One thing to note is that by default if Resolution is given one value it is assumed that the second (y) value is -x. Because in Pyresample resolution values are always positive I added a minus sign in front of the y value to keep the behavior I initially implemented. In the GeoBox this affects where the "anchor" point (i.e. from where the raster is indexed). This is mostly visible in the affine transformation of the GeoBox. You can also see this in the representation of the GeoBox as seen below (top is the implemented behavior, bottom is the behavior when both resolution values are positive; look at the small dot on the boundary).
odc_geobox


def create_areas_def(self):
"""Generate YAML formatted representation of this area.

Expand Down
29 changes: 29 additions & 0 deletions pyresample/test/test_geometry/test_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,35 @@ def test_cartopy_crs_latlon_bounds(self, create_test_area):
latlong_crs = area_def.to_cartopy_crs()
np.testing.assert_allclose(latlong_crs.bounds, [-180, 180, -90, 90])

def test_to_odc_geobox(self, stere_area, create_test_area):
Copy link
Member

Choose a reason for hiding this comment

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

Can we xfail or skip if odc is missing? I think pytest has a decorator specifically for skipping if import fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a good Idea. I will also add a test for missing odc-geosince that is not tested yet.

Copy link
Member

Choose a reason for hiding this comment

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

And thanks for using the create_test_area fixture. It makes my work on Pyresample 2.0 much easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a test for the case where odc-geo is not installed and changed the setup to include it as a requirement for testing. I thought about it and I think the test should not be skipped if odc-geo is not installed instead odc-geo should be required for testing as it is now.

"""Test conversion from area definition to odc GeoBox."""
from odc.geo.geobox import GeoBox

europe = stere_area
seviri = create_test_area(
{
'proj': 'geos',
'lon_0': 0.0,
'a': 6378169.00,
'b': 6356583.80,
'h': 35785831.00,
'units': 'm'},
123,
123,
(-5500000, -5500000, 5500000, 5500000))

for area_def in [europe, seviri]:
geobox = area_def.to_odc_geobox()

assert isinstance(geobox, GeoBox)

# Affine coefficiants
af = geobox.affine
assert af.a == area_def.pixel_size_x
assert af.e == -area_def.pixel_size_y
assert af.xoff == area_def.area_extent[0]
assert af.yoff == area_def.area_extent[3]

def test_dump(self, create_test_area):
"""Test exporting area defs."""
from io import StringIO
Expand Down
8 changes: 8 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,16 @@
'cf': ['xarray'],
'gradient_search': ['shapely'],
'xarray_bilinear': ['xarray', 'dask', 'zarr'],
'odc-geo': ['odc-geo'],
'tests': test_requires}

all_extras = []
for extra_deps in extras_require.values():
all_extras.extend(extra_deps)
extras_require['all'] = list(set(all_extras))

setup_requires = ['numpy>=1.10.0', 'cython']
Copy link
Member

Choose a reason for hiding this comment

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

This isn't actually used anywhere, plus this kind of thing (setup_requires) should be defined in the pyproject.toml build section.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. I have to admit I just copied it to get the different extra install options working.


if sys.platform.startswith("win"):
extra_compile_args = []
else:
Expand Down
Loading