You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Doing a roundtrip from a Cartopy projection to a WKT string and back is expected to work as the WKT format is lossless (opposed to e.g. proj4). The following code snippet confirms this:
This works as expected. However, during this conversion, some properties of the PlateCarree() object are lost. Some of these properties are necessary for e.g. plotting:
>>>importmatplotlib.pyplotasplt>>>fig, ax=plt.subplots(subplot_kw=dict(projection=ccrs.PlateCarree())) # works>>>fig, ax=plt.subplots(subplot_kw=dict(projection=backward(forward(PlateCarree())))) # fails as `_as_mpl_axes` is missing# See traceback 1
Converting the CRS to a Projection does not succeed either:
>>>fig, ax=plt.subplots(subplot_kw=dict(projection=ccrs.Projection(backward(forward(PlateCarree()))))) # fails with self.bounds not implemented# See traceback 2
Partly solution
Digging a bit deeper, providing the BBOX argument to a WKT string can fix part of the issue:
>>>ccrs.PlateCarree().to_wkt()
'PROJCRS["unknown",BASEGEOGCRS["unknown",DATUM["Unknown based on WGS 84 ellipsoid",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1,ID["EPSG",9001]]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8901]]],CONVERSION["unknown",METHOD["Equidistant Cylindrical",ID["EPSG",1028]],PARAMETER["Latitude of 1st standard parallel",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Longitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["False easting",0,LENGTHUNIT["unknown",111319.490793274],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["unknown",111319.490793274],ID["EPSG",8807]]],CS[Cartesian,3],AXIS["(E)",east,ORDER[1],LENGTHUNIT["unknown",111319.490793274]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["unknown",111319.490793274]],AXIS["ellipsoidal height (h)",up,ORDER[3],LENGTHUNIT["metre",1,ID["EPSG",9001]]]]'>>>wkt=PROJCRS["unknown",BASEGEOGCRS["unknown",DATUM["Unknown based on WGS 84 ellipsoid",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1,ID["EPSG",9001]]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8901]]],CONVERSION["unknown",METHOD["Equidistant Cylindrical",ID["EPSG",1028]],PARAMETER["Latitude of 1st standard parallel",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8823]],PARAMETER["Longitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["False easting",0,LENGTHUNIT["unknown",111319.490793274],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["unknown",111319.490793274],ID["EPSG",8807]]],CS[Cartesian,3],AXIS["(E)",east,ORDER[1],LENGTHUNIT["unknown",111319.490793274]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["unknown",111319.490793274]],AXIS["ellipsoidal height (h)",up,ORDER[3],LENGTHUNIT["metre",1,ID["EPSG",9001]]], USAGE[BBOX[-90,-180,90,180]]]
>>>proj=pyproj.crs.CRS.from_wkt(wkt)
<ProjectedCRS: PROJCRS["unknown",BASEGEOGCRS["unknown",DATUM["Unk ...>Name: unknownAxisInfo [cartesian]:
-E[east]: Easting (unknown)
-N[north]: Northing (unknown)
-h[up]: Ellipsoidalheight (metre)
AreaofUse:
-name: undefined-bounds: (-180.0, -90.0, 180.0, 90.0)
CoordinateOperation:
-name: unknown-method: EquidistantCylindricalDatum: UnknownbasedonWGS84ellipsoid-Ellipsoid: WGS84-PrimeMeridian: Greenwich>>>fig, ax=plt.subplots(subplot_kw=dict(projection=Projection(proj)))
UPDATE: the BBOX needs to be within the valid boundary of the projection (e.g. is not allowed to extend to the poles for some projection methods This seems to be the case whenever, the projection is registered with an authority. So something (apart from e.g. the BBOX parameter) is written to WKT that actually enables cartopy to create a fully functional Projection object. What are these requirements?
Expectations
Round-trip via lossless protocol (e.g. WKT2) creates object with same properties
Plotting works for all CRS that are read via WKT2, especially those that are exported from a cartopy object
plotting works independently of bounding box defintions
Related issues
I think there are a lot of related issues that all touch on the cartopy backend being mostly proj4 opposed to WKT. I understand that this is a major refactoring undertaking, so I would like to particularly know how we could make the plotting more general, that it works with any/most Projection objects.
I'm not sure I totally follow the request here. Cartopy is providing conveniences for projections and adding nice things to plot with like boundaries, but the ultimate source of projections is pyproj under the hood. So if you want to create projections and move them around, pyproj is really where the work should be happening. For Cartopy, I think the serialization would have to happen in pickling/unpickling classes, not a standard like WKT.
I might be missing something though, and we are definitely interested in making sharing projections across the various libraries as seamless as possible, so any PRs / updates on that are very welcome.
Thanks for your feedback @greglucas! The issue developed a bit after I experimented a bit more so it probably lost it's clarity there. I think one of the main issues here is that plotting arbitrary Projection objects is currently not possible because self.bounds of the Projection is needed. If this requirement could be relaxed somehow then this would open the plotting to projections that have no bounding box defined.
Hi 👋
Thank you very much for maintaining this library! I really appreciate all the work that is put into this package. Projections are tough!
Setting the scene
I like to save a projection (pyproj, cartopy) following the CF-conventions, read it back in and visualize.
WKT2 seems to be one of the best formats to store the complete CRS without loosing information such that one needs to add the optional
crs_wkt
attribute to the single-property attributes in a CF compliant file. Using cartopy which supports WKT strings seems to be the natural choice to visualize such projections.The problem
Doing a roundtrip from a Cartopy projection to a WKT string and back is expected to work as the WKT format is lossless (opposed to e.g. proj4). The following code snippet confirms this:
This works as expected. However, during this conversion, some properties of the PlateCarree() object are lost. Some of these properties are necessary for e.g. plotting:
Converting the CRS to a
Projection
does not succeed either:Partly solution
Digging a bit deeper, providing the
BBOX
argument to a WKT string can fix part of the issue:The problem here is that the following transformation returns NaNs for the points and therefore the bounds are set to NaNhttps://github.com/SciTools/cartopy/blob/main/lib/cartopy/crs.py#L690-L692For projections, that are defined by authorities (and include a BBOX) the workflow works directly:
UPDATE: the BBOX needs to be within the valid boundary of the projection (e.g. is not allowed to extend to the poles for some projection methods
This seems to be the case whenever, the projection is registered with an authority. So something (apart from e.g. the BBOX parameter) is written to WKT that actually enables cartopy to create a fully functionalProjection
object. What are these requirements?Expectations
Related issues
I think there are a lot of related issues that all touch on the cartopy backend being mostly proj4 opposed to WKT. I understand that this is a major refactoring undertaking, so I would like to particularly know how we could make the plotting more general, that it works with any/most
Projection
objects.#153
#1911
#2099
Additional information
Traceback 1
Traceback 2
Traceback 3
The text was updated successfully, but these errors were encountered: