From d065d589727e84e7a6f4ba62edc2c16d5519e21b Mon Sep 17 00:00:00 2001 From: "Philipp S. Sommer" Date: Mon, 14 Feb 2022 13:02:29 +0100 Subject: [PATCH] [semver:patch] Compatibility fixes for psy-simple v1.4.1 (#42) Fix projection issues Fixed ----- - `false_easting` and `false_northing` are now expected to be optional arguments for most projections (see #41) Changed ------- - we now use the `convert_coordinate` method that has been introduced in psyplot/psyplot#39 and psyplot/psy-simple#30. See #41 --- .appveyor.yml | 2 +- .circleci/config.yml | 2 +- CHANGELOG.rst | 18 ++++++++++ docs/environment.yml | 1 + psy_maps/plotters.py | 71 +++++++++++++++++++++++++++------------ tests/test_projections.py | 33 ++++++++++++++++++ 6 files changed, 103 insertions(+), 24 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3c825cc..b958416 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -43,7 +43,7 @@ after_test: deploy_script: - cmd: " IF NOT DEFINED APPVEYOR_REPO_TAG_NAME ( - deploy-conda-recipe -l %APPVEYOR_REPO_BRANCH% -py %PYTHON_VERSION% ci/conda-recipe + deploy-conda-recipe -l %APPVEYOR_REPO_BRANCH:/=-% -py %PYTHON_VERSION% ci/conda-recipe ) ELSE ( deploy-conda-recipe -py %PYTHON_VERSION% ci/conda-recipe )" diff --git a/.circleci/config.yml b/.circleci/config.yml index 92856ef..79b789f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 orbs: - psyplot: psyplot/psyplot-ci-orb@1.5.24 + psyplot: psyplot/psyplot-ci-orb@1.5.31 mattermost-plugin-notify: nathanaelhoun/mattermost-plugin-notify@1.2.0 executors: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5b35024..0057c02 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,21 @@ +v1.4.1 +====== +Fix projection issues + +Fixed +----- +- ``false_easting`` and ``false_northing`` are now expected to be optional + arguments for most projections (see + `#41 `__) + +Changed +------- +- we now use the ``convert_coordinate`` method that has been introduced in + `psyplot/psyplot#39 `__ and + `psyplot/psy-simple#30 `__. + See `#41 `__ + + v1.4.0 ====== Compatibility fixes and LGPL license diff --git a/docs/environment.yml b/docs/environment.yml index 1b5ca07..dd6512a 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -1,6 +1,7 @@ name: psyplot_docs channels: - local + - psyplot/label/__CURRENTBRANCH__ - psyplot/label/master - conda-forge dependencies: diff --git a/psy_maps/plotters.py b/psy_maps/plotters.py index 314fb2c..96d5de5 100755 --- a/psy_maps/plotters.py +++ b/psy_maps/plotters.py @@ -319,9 +319,9 @@ def albers_conical_equal_area_from_cf(self, crs): iter(kwargs['standard_parallels']) except TypeError: kwargs['standard_parallels'] = [kwargs['standard_parallels']] - if getattr(crs, 'false_easting'): + if getattr(crs, 'false_easting', None): kwargs['false_easting'] = crs.false_easting - if getattr(crs, 'false_northing'): + if getattr(crs, 'false_northing', None): kwargs['false_northing'] = crs.false_northing return ccrs.AlbersEqualArea(**kwargs) @@ -330,9 +330,9 @@ def azimuthal_equidistant_from_cf(self, crs): central_longitude=crs.longitude_of_projection_origin, central_latitude=crs.latitude_of_projection_origin, ) - if getattr(crs, 'false_easting'): + if getattr(crs, 'false_easting', None): kwargs['false_easting'] = crs.false_easting - if getattr(crs, 'false_northing'): + if getattr(crs, 'false_northing', None): kwargs['false_northing'] = crs.false_northing return ccrs.AzimuthalEquidistant(**kwargs) @@ -342,9 +342,9 @@ def geostationary_from_cf(self, crs): satellite_height=crs.perspective_point_height, sweep_axis=crs.sweep_angle_axis, ) - if getattr(crs, 'false_easting'): + if getattr(crs, 'false_easting', None): kwargs['false_easting'] = crs.false_easting - if getattr(crs, 'false_northing'): + if getattr(crs, 'false_northing', None): kwargs['false_northing'] = crs.false_northing return ccrs.Geostationary(**kwargs) @@ -353,9 +353,9 @@ def lambert_azimuthal_equal_area_from_cf(self, crs): central_longitude=crs.longitude_of_projection_origin, central_latitude=crs.latitude_of_projection_origin, ) - if getattr(crs, 'false_easting'): + if getattr(crs, 'false_easting', None): kwargs['false_easting'] = crs.false_easting - if getattr(crs, 'false_northing'): + if getattr(crs, 'false_northing', None): kwargs['false_northing'] = crs.false_northing return ccrs.LambertAzimuthalEqualArea(**kwargs) @@ -369,9 +369,9 @@ def lambert_conformal_conic_from_cf(self, crs): iter(kwargs['standard_parallels']) except TypeError: kwargs['standard_parallels'] = [kwargs['standard_parallels']] - if getattr(crs, 'false_easting'): + if getattr(crs, 'false_easting', None): kwargs['false_easting'] = crs.false_easting - if getattr(crs, 'false_northing'): + if getattr(crs, 'false_northing', None): kwargs['false_northing'] = crs.false_northing return ccrs.LambertConformal(**kwargs) @@ -390,9 +390,9 @@ def mercator_from_cf(self, crs): ) if hasattr(crs, 'scale_factor_at_projection_origin'): kwargs['scale_factor'] = crs.scale_factor_at_projection_origin - if getattr(crs, 'false_easting'): + if getattr(crs, 'false_easting', None): kwargs['false_easting'] = crs.false_easting - if getattr(crs, 'false_northing'): + if getattr(crs, 'false_northing', None): kwargs['false_northing'] = crs.false_northing return ccrs.Mercator(**kwargs) @@ -427,9 +427,9 @@ def sinusoidal_from_cf(self, crs): kwargs = dict( central_longitude=crs.longitude_of_central_meridian, ) - if getattr(crs, 'false_easting'): + if getattr(crs, 'false_easting', None): kwargs['false_easting'] = crs.false_easting - if getattr(crs, 'false_northing'): + if getattr(crs, 'false_northing', None): kwargs['false_northing'] = crs.false_northing return ccrs.Sinusoidal(**kwargs) @@ -439,9 +439,9 @@ def stereographic_from_cf(self, crs): central_longitude=crs.longitude_of_projection_origin, scale_factor=crs.scale_factor_at_projection_origin ) - if getattr(crs, 'false_easting'): + if getattr(crs, 'false_easting', None): kwargs['false_easting'] = crs.false_easting - if getattr(crs, 'false_northing'): + if getattr(crs, 'false_northing', None): kwargs['false_northing'] = crs.false_northing return ccrs.Stereographic(**kwargs) @@ -451,9 +451,9 @@ def transverse_mercator_from_cf(self, crs): central_latitude=crs.latitude_of_projection_origin, scale_factor=crs.scale_factor_at_central_meridian, ) - if getattr(crs, 'false_easting'): + if getattr(crs, 'false_easting', None): kwargs['false_easting'] = crs.false_easting - if getattr(crs, 'false_northing'): + if getattr(crs, 'false_northing', None): kwargs['false_northing'] = crs.false_northing return ccrs.TransverseMercator(**kwargs) @@ -2047,10 +2047,6 @@ class MapPlotter(psyps.Base2D): """Base plotter for visualizing data on a map """ - #: Boolean that is True if coordinates with units in radian should be - #: converted to degrees - convert_radian = True - _rcparams_string = ['plotter.maps.'] background = MapBackground('background') @@ -2093,6 +2089,37 @@ def ax(self): def ax(self, value): self._ax = value + @docstrings.dedent + def convert_coordinate(self, coord, *variables): + """Convert a coordinate from radian to degree. + + This method checks if the coordinate or one of the given variables has + units in radian. If yes, the given `coord` is converted to degree. + + Parameters + ---------- + %(Formatoption.convert_coordinate.parameters)s + + Returns + ------- + %(Formatoption.convert_coordinate.returns)s + """ + + def in_rad(var): + return var.attrs.get('units', '').startswith('radian') + + def in_km(var): + return var.attrs.get('units', '') == "km" + + if any(map(in_rad, chain([coord], variables))): + coord = coord.copy(data=coord * 180. / np.pi) + coord.attrs["units"] = "degrees" + elif any(map(in_km, chain([coord], variables))): + coord = coord.copy(data=coord * 1000) + coord.attrs["units"] = "m" + + return coord + class FieldPlotter(psyps.Simple2DBase, MapPlotter, psyps.BasePlotter): """Plotter for 2D scalar fields on a map diff --git a/tests/test_projections.py b/tests/test_projections.py index bc1208c..8036874 100644 --- a/tests/test_projections.py +++ b/tests/test_projections.py @@ -123,3 +123,36 @@ def test_rotated_pole_extent(open_grid_ds): assert isinstance(plotter.ax.projection, ccrs.RotatedPole) lonmin, lonmax = plotter.ax.get_extent()[:2] assert lonmax - lonmin < 200 + + +def test_false_easting(open_grid_ds, grid, grid_projection): + grid_ds = open_grid_ds(grid) + grid_var = grid_ds["Band1"].grid_mapping + if "false_easting" not in grid_ds[grid_var].attrs: + pytest.skip(f"No false_easting parameter for {grid_var} grid.") + return + del grid_ds[grid_var].attrs["false_easting"] + with grid_ds.psy.plot.mapplot() as sp: + assert len(sp) == 1 + plotter = sp.plotters[0] + assert isinstance(plotter.transform.projection, grid_projection) + assert plotter.plot._kwargs.get('transform') is \ + plotter.transform.projection + assert isinstance(plotter.projection.projection, grid_projection) + + +def test_false_northing(open_grid_ds, grid, grid_projection): + grid_ds = open_grid_ds(grid) + grid_var = grid_ds["Band1"].grid_mapping + if "false_northing" not in grid_ds[grid_var].attrs: + pytest.skip(f"No false_northing parameter for {grid_var} grid.") + return + del grid_ds[grid_var].attrs["false_northing"] + with grid_ds.psy.plot.mapplot() as sp: + assert len(sp) == 1 + plotter = sp.plotters[0] + assert isinstance(plotter.transform.projection, grid_projection) + assert plotter.plot._kwargs.get('transform') is \ + plotter.transform.projection + assert isinstance(plotter.projection.projection, grid_projection) +