-
Couldn't load subscription status.
- Fork 390
Description
Description
For 2 years now, pyproj has been able to parse CF "grid mapping" attributes (http://cfconventions.org/Data/cf-conventions/cf-conventions-1.10/cf-conventions.html#coordinate-system) (pyproj4/pyproj#660).
This is done through the pyproj.CRS.from_cf method. Sadly, it is a staticmethod, and not a classmethod. Thus, the result is a pyproj.CRS object, even we call the method on cartopy.crs.Projection. And this is does not work as expected with matplotlib.
The code seems to be done this way because even though the from_cf method lives in CRS, it actually returns children of CRS, but the exact type depends on the inputs. Would that mean it is not compatible with cartopy?
It would be interesting if the function could be overrided to actually return a cartopy object. Also, this direct use of cartopy.crs.Projection doesn't seem much documented. Is it uncommon? In that case, would a cartopy.crs.from_cf function be interesting?
I may have time to help on this. My long term goal would be to make cf-xarray aware of these grid_mappings CF variables and able to inject the correct cartopy CRS argument to matplotlib's transform argument.
Code to reproduce
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
cf_attrs = {'grid_mapping_name': 'rotated_latitude_longitude',
'grid_north_pole_latitude': 42.5,
'grid_north_pole_longitude': 83.0,
'north_pole_grid_longitude': 0.0}
rp = ccrs.Projection.from_cf(cf_attrs)
fig, ax = plt.subplots(subplot_kw={'projection': rp})
Traceback
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [15], line 6
1 cf_attrs = {'grid_mapping_name': 'rotated_latitude_longitude',
2 'grid_north_pole_latitude': 42.5,
3 'grid_north_pole_longitude': 83.0,
4 'north_pole_grid_longitude': 0.0}
5 rp = ccrs.Projection.from_cf(cf_attrs)
----> 6 fig, ax = plt.subplots(subplot_kw={'projection': rp})
File /exec/pbourg/.conda/cf_xarray_test/lib/python3.10/site-packages/matplotlib/pyplot.py:1443, in subplots(nrows, ncols, sharex, sharey, squeeze, width_ratios, height_ratios, subplot_kw, gridspec_kw, **fig_kw)
1299 """
1300 Create a figure and a set of subplots.
1301
(...)
1440
1441 """
1442 fig = figure(**fig_kw)
-> 1443 axs = fig.subplots(nrows=nrows, ncols=ncols, sharex=sharex, sharey=sharey,
1444 squeeze=squeeze, subplot_kw=subplot_kw,
1445 gridspec_kw=gridspec_kw, height_ratios=height_ratios,
1446 width_ratios=width_ratios)
1447 return fig, axs
File /exec/pbourg/.conda/cf_xarray_test/lib/python3.10/site-packages/matplotlib/figure.py:894, in FigureBase.subplots(self, nrows, ncols, sharex, sharey, squeeze, width_ratios, height_ratios, subplot_kw, gridspec_kw)
891 gridspec_kw['width_ratios'] = width_ratios
893 gs = self.add_gridspec(nrows, ncols, figure=self, **gridspec_kw)
--> 894 axs = gs.subplots(sharex=sharex, sharey=sharey, squeeze=squeeze,
895 subplot_kw=subplot_kw)
896 return axs
File /exec/pbourg/.conda/cf_xarray_test/lib/python3.10/site-packages/matplotlib/gridspec.py:308, in GridSpecBase.subplots(self, sharex, sharey, squeeze, subplot_kw)
306 subplot_kw["sharex"] = shared_with[sharex]
307 subplot_kw["sharey"] = shared_with[sharey]
--> 308 axarr[row, col] = figure.add_subplot(
309 self[row, col], **subplot_kw)
311 # turn off redundant tick labeling
312 if sharex in ["col", "all"]:
File /exec/pbourg/.conda/cf_xarray_test/lib/python3.10/site-packages/matplotlib/figure.py:743, in FigureBase.add_subplot(self, *args, **kwargs)
740 if (len(args) == 1 and isinstance(args[0], Integral)
741 and 100 <= args[0] <= 999):
742 args = tuple(map(int, str(args[0])))
--> 743 projection_class, pkw = self._process_projection_requirements(
744 *args, **kwargs)
745 ax = subplot_class_factory(projection_class)(self, *args, **pkw)
746 key = (projection_class, pkw)
File /exec/pbourg/.conda/cf_xarray_test/lib/python3.10/site-packages/matplotlib/figure.py:1682, in FigureBase._process_projection_requirements(self, axes_class, polar, projection, *args, **kwargs)
1680 kwargs.update(**extra_kwargs)
1681 else:
-> 1682 raise TypeError(
1683 f"projection must be a string, None or implement a "
1684 f"_as_mpl_axes method, not {projection!r}")
1685 if projection_class.__name__ == 'Axes3D':
1686 kwargs.setdefault('auto_add_to_figure', False)
TypeError: projection must be a string, None or implement a _as_mpl_axes method, not <Derived Geographic 2D CRS: {"$schema": "https://proj.org/schemas/v0.2/projjso ...>
Name: undefined
Axis Info [ellipsoidal]:
- lon[east]: Longitude (degree)
- lat[north]: Latitude (degree)
Area of Use:
- undefined
Coordinate Operation:
- name: Pole rotation (netCDF CF convention)
- method: Pole rotation (netCDF CF convention)
Datum: World Geodetic System 1984
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich
Full environment definition
Operating system
Linux 64
Cartopy version
0.21.0
pyproj version
3.4.0