Adding a CRS attribute to Shapely objects
See original GitHub issueHi all,
I would like to propose adding a CRS attribute to Shapely objects. The rational is that Shaply is commonly used in GIS, and the CRS info that exists in the GIS files, like geo-json, is discarded, thus when one gets a Shapely object in some function, it can’t know which CRS it is originated.
In my case, there are many times when the convention is wgs84 (i.e. lat, lng) and in other cases crs84 (i.e. lng, lat), and in some cases we use projected coordinates. I could pass along the CRS for each input, but maybe there is a more elegant way to do so.
For the sake of proof of concept I’ve added a crs filed in Shapely 2.0b2 objects code and made the following example. I will make a proper PR to evaluate this if there is any interest in going forward with this idea.
@jorisvandenbossche related: https://github.com/shapely/shapely/issues/962#issuecomment-1317197517
import pyproj
from shapely.geometry import Point, shape, mapping
from shapely.geometry.base import BaseGeometry
from shapely.ops import transform
def get_transform(shp: BaseGeometry, dest_crs):
return pyproj.Transformer.from_crs(shp.crs, dest_crs).transform
def transform_crs(get_transform_func, dest_crs, geom):
func = get_transform_func(geom, dest_crs)
output_geom = transform(func, geom)
output_geom.crs = dest_crs
return output_geom
def test_point_with_crs(lat, lng, utm_crs_str):
wgs84_str = "urn:ogc:def:crs:EPSG::4326"
crs84_str = 'urn:ogc:def:crs:OGC::CRS84'
crs84_pt = Point(lng, lat, crs=crs84_str)
print(f'{crs84_pt=}')
p = {
"type": "Point",
"coordinates": crs84_pt.coords,
"crs": {"type": "name", "properties": {"name": crs84_pt.crs}},
}
crs84_pt2 = shape(p)
print(f'{crs84_pt2=}')
crs84_pt3_map = mapping(crs84_pt2)
print(f'{crs84_pt3_map=}')
project = pyproj.Transformer.from_crs(crs84_str, utm_crs_str).transform
# project = pyproj.Transformer.from_crs(wgs84_str, utm, always_xy=True).transform
utm_point = transform(project, crs84_pt)
print(f'{utm_point=}')
utm_point2 = transform_crs(get_transform, utm_crs_str, crs84_pt)
print(f'{utm_point2=}')
project = pyproj.Transformer.from_crs(crs84_str, wgs84_str).transform
# project = pyproj.Transformer.from_crs(wgs84_str, utm, always_xy=True).transform
wgs84_point = transform(project, crs84_pt)
print(f'{wgs84_point=}')
wgs84_point2 = transform_crs(get_transform, wgs84_str, crs84_pt)
print(f'{wgs84_point2=}')
test_point_with_crs(lat=47.6, lng=-122.3, utm_crs_str = 'EPSG:32610')
output:
crs84_pt=<POINT (-122.3 47.6)><urn:ogc:def:crs:OGC::CRS84>
crs84_pt2=<POINT (-122.3 47.6)><urn:ogc:def:crs:OGC::CRS84>
crs84_pt3_map={'type': 'Point', 'coordinates': (-122.3, 47.6), 'crs': 'urn:ogc:def:crs:OGC::CRS84'}
utm_point=<POINT (552619.097 5272080.811)>
utm_point2=<POINT (552619.097 5272080.811)><EPSG:32610>
wgs84_point=<POINT (47.6 -122.3)>
wgs84_point2=<POINT (47.6 -122.3)><urn:ogc:def:crs:EPSG::4326>
Issue Analytics
- State:
- Created 10 months ago
- Comments:10 (5 by maintainers)
Top GitHub Comments
Thanks for bringing this up @idanmiara and good to discuss this point and share our opinions.
I think one of the reasons is that Shapely is such a popular tool in the GIS world is that it does one thing, and it does it well. As the current scope of shapely is “a planar geometry library”, the concept of CRS is not in scope, but a contextual value that might be taken into account when interpreting the geometries.
Just as a comparison: numpy does numerical computing (and it does it well). To interpret an array of float values you often need a unit. I wouldn’t think of suggesting to add the property “unit” to a numpy ndarray.
Coming back to the “crs” question: we would need to extend the scope of shapely to encompass coordinate reference systems. Constructors will need to adapt, representations, IO. What type will the “crs” attribute be? Do we accept pyproj as dependency? Does the crs survive all operations? Is it a mutable attribute? Only Projected or also geometric systems? Do we handle meridian crossings?
I think that is just too much a can of worms and at the same time the situation it solves is merely an annoyance. I’d like to stick with the current scope and see shapely focus on the planar geometries.
I’m locking this issue because I don’t think collecting more opinions here does the project any good. Start a discussion if you like: https://github.com/shapely/shapely/discussions.