question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Adding a CRS attribute to Shapely objects

See original GitHub issue

Hi 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:closed
  • Created 10 months ago
  • Comments:10 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
caspervdwcommented, Nov 27, 2022

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.

0reactions
sgilliescommented, Dec 21, 2022

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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

CRS of Shapely Object - python
I've imported a row from a Postgres DB using sqlalchemy. One of the column types is GEOMETRY from postgis and upon import
Read more >
The Shapely User Manual — Shapely 2.0.0 documentation
Objects of the types explained in Geometric Objects provide standard 1 predicates as attributes (for unary predicates) and methods (for binary predicates).
Read more >
Coordinate Reference Systems (CRS)
Coordinate reference systems (CRS) are important because the geometric shapes in a GeoDataFrame are simply a collection of coordinates in an ...
Read more >
python 3.x - GeoPandas Set CRS on Points
Setting the CRS on a GeoDataFrame using its EPSG code is as simple as ... import pandas as pd from shapely.geometry import Point...
Read more >
Setting the crs of naive geometries with EPSG number #245
This can be done with setting the .crs attribute with the appropriate crs dictionary. However, when you want to set the crs using...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found