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

Add optional metadata to Pyresample 2.0 AreaDefinition #464

Merged
merged 25 commits into from
Feb 13, 2023

Conversation

djhoese
Copy link
Member

@djhoese djhoese commented Oct 28, 2022

As part of one of my projects it has been requested that AreaDefinition's officially support a container of metadata. This is inline with what we had planned for Pyresample 2.0. This PR is the initial support of this functionality.

Note: At the time of writing this is mostly just a refactor of pyresample's future geometry objects to prepare for this functionality.

  • Closes #xxxx
  • Tests added
  • Tests passed
  • Passes git diff origin/main **/*py | flake8 --diff
  • Fully documented

@djhoese djhoese added this to the v2.0 milestone Oct 28, 2022
@codecov
Copy link

codecov bot commented Oct 28, 2022

Codecov Report

Merging #464 (be2bf83) into main (b8ecc71) will decrease coverage by 0.07%.
The diff coverage is 99.15%.

@@            Coverage Diff             @@
##             main     #464      +/-   ##
==========================================
- Coverage   94.33%   94.27%   -0.07%     
==========================================
  Files          74       78       +4     
  Lines       12947    12910      -37     
==========================================
- Hits        12214    12171      -43     
- Misses        733      739       +6     
Flag Coverage Δ
unittests 94.27% <99.15%> (-0.07%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
pyresample/area_config.py 90.65% <ø> (ø)
pyresample/ewa/ewa.py 75.86% <ø> (ø)
pyresample/test/test_resamplers/test_nearest.py 100.00% <ø> (ø)
pyresample/test/test_geometry_legacy.py 97.80% <97.80%> (ø)
pyresample/test/test_geometry/test_area.py 99.18% <99.18%> (ø)
pyresample/future/geometry/__init__.py 100.00% <100.00%> (ø)
pyresample/future/geometry/area.py 100.00% <100.00%> (ø)
pyresample/future/geometry/base.py 100.00% <100.00%> (ø)
pyresample/test/conftest.py 98.40% <100.00%> (+0.38%) ⬆️
pyresample/test/test_geometry/__init__.py 100.00% <100.00%> (ø)
... and 1 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@coveralls
Copy link

coveralls commented Oct 28, 2022

Coverage Status

Coverage: 93.799% (-0.06%) from 93.862% when pulling be2bf83 on djhoese:feature-area-metadata into b8ecc71 on pytroll:main.

@djhoese djhoese self-assigned this Oct 31, 2022
@djhoese djhoese marked this pull request as ready for review October 31, 2022 17:52
Copy link
Member

@mraspaud mraspaud 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 starting this! a few questions

)


class AreaDefinition(LegacyAreaDefinition):
Copy link
Member

Choose a reason for hiding this comment

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

Do we want the new area def to inherit all the methods of the legacy one, or do we want to split responsibility a bit?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah I struggled with this decision. Initially this class in the future subpackage didn't have anything custom about it so it was just a basic import. I think for ease of transitioning to future we might want it to be a subclass so that isinstance checks still work? Or maybe usages of stuff like that should be fixed to be more duck-typing-friendly?

Copy link
Member

Choose a reason for hiding this comment

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

I vote for more duck typing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Please read my other comments. That is the plan, but I don't want to throw that all into one PR and I also don't want to deal with all the tests failing because I didn't implement one of 50 methods on the legacy AreaDefinition class. The plan is to do this work in one of the next 2 or 3 PRs.

pyresample/test/test_geometry/test_area.py Outdated Show resolved Hide resolved
pyresample/test/test_geometry/test_area.py Outdated Show resolved Hide resolved
@djhoese
Copy link
Member Author

djhoese commented Nov 24, 2022

I think my biggest TODO on this is to move the area ID to an optional "name" metadata key in .attrs.

@djhoese
Copy link
Member Author

djhoese commented Jan 27, 2023

@mraspaud So my last commits add a new pytest fixture which returns a function that automatically handles keyword argument rearranging and defaulting so the tests in pyresample/test/test_geometry/test_area.py now test both the legacy AreaDefinition class and the new/future one. In these last commits I also removed area_id as a required parameter and made attrs={"name": "some name"} an optional special metadata value along with description.

Some things I thought of or noticed while doing this and/or things that I see as needing to be done. @pnuu @gerritholl @ghiggi I'm curious on your opinions about this as well.

  1. I'd like to convert width and height into a single shape argument.
  2. I'd like to add a "feature flag" to pyresample, probably with a donfig config object, that will allow users to say "all utility methods, use the new class". I need this to complete the test_area.py code testing both classes as it often uses the utility create_area_def which always makes the old area definition classes.
  3. After the new tests are done, I'd like to remove the old area tests module and only use the new one. The new tests aren't named in a "future" way at all (test/test_geometry/test_area.py) so it should be clear to contributors that the AreaDefinition tests are in the new tests module. To really do this I may need to also copy over a lot of SwathDefinition tests which may not be fun, but is going to be needed eventually so 🤷‍♂️.

All of these things deserve their own PR in my opinion. It looks like I still need to fix some tests, but otherwise I think I'd like to merge this. Since it only affects the future interfaces merging this shouldn't break anything.

@djhoese
Copy link
Member Author

djhoese commented Jan 27, 2023

Unstable CI is failing because matplotlib needs importlib-resources but we explicitly don't install dependencies for unstable packages.

Edit: If we bumped to Python 3.10 it would work fine.

Copy link
Contributor

@ghiggi ghiggi left a comment

Choose a reason for hiding this comment

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

I added some inline comments on the current PR.

Other minor comments/ideas related to AreaDefinition attributes and properties:

  • For AreaDefinition, many methods are not clear if they return data in xy or lat/lon; the pixel centroid or the outermost pixel corner. Maybe would be worth adding a common suffix (i.e. _ll) when they return lat/lons, and otherwise expect they return xy coords. This will enhance code readability.
    Example:
    • area_def.corners currently returns the centroid lat/lon coords in the very old spherical object
    • area_def.outer_boundary_corners currently returns the corners lat/lon coords in the very old spherical object
      --> Possible new methods: corners_centroids, corners, corners_centroids_ll, corners_ll ... or see next bullet point
  • Add utility properties like upper_left_corner_ll, upper_left_centroid_ll,
    A possible pattern: <lower/upper>_<right/left>_<''/'ll'> (or bottom instead of lower).
    Currently the upper_left_corner is provided by upper_left_extent
  • Add xy_bbox and ll_bbox properties for consistency with satpy? Equivalent to area_extent and area_extent_ll
  • Current area_extent_<> and <>_bbox follow the (xmin, ymin, xmax, ymax) convention. More precisely the area_extent is defined as (lower_left_x, lower_left_y, upper_right_x, upper_right_y).
    • This is also the convention adopted by rasterio/rioxarray/shapely object bounds method.
      --> Maybe we could add a bounds property?
    • When retrieving the area_extent_ll (in lat/lon) the lower-left and upper-right corners do not necessarily currently define the outermost lat/lon coordinates of the area. Maybe this method should be changed! And maybe we could also add a bounds_ll method.
    • Additionally, the area_extent convention differs from the i.e. matplotlib cartopy and matplotlib extent which is defined as (xmin, xmax, ymin, ymax)
      --> Maybe we could add a <mpl/cartopy>_area_extent_<''/ll> property?
  • For GEO AreaDef, all the above _ll methods currently return np.nan/np.inf values. Maybe ad-hoc processing using get_geostationary_bounding_box_in_lonlats could be implemented for area_extent_ll, but the corners would remain undefined ! Maybe would be worth raising an error to avoid downstream bugs !

y dimension in number of pixels, aka number of grid rows
size (int):
Number of points in grid
area_extent_ll (tuple):
Copy link
Contributor

Choose a reason for hiding this comment

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

In the attributes, it should be listed also the area_extent .

height:
y dimension in number of pixels, aka number of grid rows
area_extent:
Area extent as a list (lower_left_x, lower_left_y, upper_right_x, upper_right_y)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Area extent as a list (lower_left_x, lower_left_y, upper_right_x, upper_right_y)
Area extent (in projection coordinates) provided as a list (lower_left_x, lower_left_y, upper_right_x, upper_right_y)

Pixel width in projection units
pixel_size_y (float):
Pixel height in projection units
upper_left_extent (tuple):
Copy link
Contributor

Choose a reason for hiding this comment

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

upper_left_extent is a misleading name. I would rather call it upper_left_corner. It's used only in AreaDefinition.from_ul_corner btw

Copy link
Member

Choose a reason for hiding this comment

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

extent is the extreme border in all extent definitions I've seen, also outside of Pytroll, so I don't see that as very misleading.

Pixel height in projection units
upper_left_extent (tuple):
Coordinates (x, y) of upper left corner of upper left pixel in projection units
pixel_upper_left (tuple):
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a thought: maybe pixel_upper_left could be renamed upper_left_centroid (see previous comment)

@djhoese
Copy link
Member Author

djhoese commented Jan 28, 2023

Thanks for all the feedback @ghiggi, but I think there's been a misunderstanding. The tests added here (with a few exception for the new metadata handling) are all copies from the original AreaDefinition tests. None of these coordinate features/names are new/different. I think we should maybe move the discussion of changes to the AreaDefinition interface somewhere else...I thought I had an issue for that 🤔

I have my own ideas for changing interfaces and some of us have discussed them in the past. For example, put all coordinate operations (ex. get_lonlats) in a separate coordinate handling class.

Looks like there are no "here's all the area stuff we want to change" issues. We have these for v2.0: https://github.com/pytroll/pyresample/issues?q=is%3Aopen+is%3Aissue+milestone%3Av2.0

@djhoese
Copy link
Member Author

djhoese commented Jan 31, 2023

@ghiggi do you have any additional comments about the stuff I did in this PR? Mainly my comment just before your last comment, the idea of metadata in the AreaDefinition (in pyresample 2.0), or the pytest fixture I'm using to test both legacy areas and new areas?

@ghiggi
Copy link
Contributor

ghiggi commented Feb 1, 2023

Sorry for the very late reply (and the misunderstanding) @djhoese ... I am having super busy days.
I have no additional comments ;)

Copy link
Member

@mraspaud mraspaud 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 the PR. Some comments inline

)


class AreaDefinition(LegacyAreaDefinition):
Copy link
Member

Choose a reason for hiding this comment

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

I vote for more duck typing.

pyresample/test/conftest.py Show resolved Hide resolved
pyresample/future/geometry/area.py Show resolved Hide resolved
pyresample/future/geometry/area.py Show resolved Hide resolved
area_def.area_extent = (-1000000, -900000, 1000000, 1500000)


class TestAreaDefinitionMetadata:
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 about the name here. At least, should this class and all that is future-specific be moved to a future test file?

Copy link
Member Author

@djhoese djhoese Feb 6, 2023

Choose a reason for hiding this comment

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

I thought about this a lot when I started this PR and I think I still agree with past Dave. Or at least I'm 50/50 on it so I can't say I feel that strongly. The original plan (and how it is being implemented now) is that this module will test legacy and future implementations and the legacy test module will eventually be removed. So I didn't want to confuse contributions for the legacy area definition by telling people "I know you want to put the tests in test/, but they should actually go in test/future/ even though that's not where your changes went.

@@ -0,0 +1,2003 @@
# Copyright (C) 2010-2022 Pyresample developers
Copy link
Member

Choose a reason for hiding this comment

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

Feels like this is a copy of existing tests? Is this really needed? can't we have just one version of this?

Copy link
Member Author

Choose a reason for hiding this comment

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

"one version" of what? Of the AreaDefinition tests? Please read my comments with my questions and my plans to remove the legacy-only tests right after this PR is merged.

Copy link
Member Author

Choose a reason for hiding this comment

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

...and yes this copyright is here like this because these tests were copied from the original/legacy geometry tests so I guess the copyright still stands?

Copy link
Member

Choose a reason for hiding this comment

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

yeah, this wasn't about the copyright :)
Ok, so I think it's a good idea to have have tests for both legacy and future in one module. But I would like to avoid being in a limbo for a while where we have duplicated tests. Do you think it's possible to remove the legacy tests already in this PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

If that's really what you want. The idea was that I was going to make a ton of PRs right away after this merge a week or so ago when I had time. Now I'm not so sure how fast I can do that so I guess I can put it here.

@djhoese
Copy link
Member Author

djhoese commented Feb 8, 2023

Strange. Github complained about merge conflicts but when I merged it locally it did it perfectly fine. 🤷‍♂️

Now to start on converting all the old tests...

@djhoese
Copy link
Member Author

djhoese commented Feb 10, 2023

@mraspaud Ok I think this is ready from the "no duplicate tests" point of view. The tests are much more organized and are all pytest-based now. The remaining tests in the legacy module are for classes that don't currently have a future-pyresample version.

Copy link
Member

@mraspaud mraspaud left a comment

Choose a reason for hiding this comment

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

I think we're good for now, let's merge this and see what happens

@mraspaud mraspaud merged commit f770984 into pytroll:main Feb 13, 2023
@djhoese djhoese deleted the feature-area-metadata branch February 28, 2023 20:36
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.

5 participants