Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Expose transform #3075

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 12 additions & 8 deletions geopandas/array.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import inspect
import numbers
import operator
import warnings
import inspect
from functools import lru_cache

import numpy as np
import pandas as pd
from pandas.api.extensions import (
ExtensionArray,
ExtensionDtype,
register_extension_dtype,
)

import shapely
import shapely.affinity
import shapely.geometry
from shapely.geometry.base import BaseGeometry
import shapely.ops
import shapely.wkt
from pandas.api.extensions import (
ExtensionArray,
ExtensionDtype,
register_extension_dtype,
)
from pyproj import CRS, Transformer
from pyproj.aoi import AreaOfInterest
from pyproj.database import query_utm_crs_info
from shapely.geometry.base import BaseGeometry

from .sindex import SpatialIndex

Expand Down Expand Up @@ -634,6 +633,11 @@ def segmentize(self, max_segment_length):
crs=self.crs,
)

def transform(self, transformation, include_z=False):
return GeometryArray(
shapely.transform(self._data, transformation, include_z), crs=self.crs
)

#
# Binary predicates
#
Expand Down
45 changes: 42 additions & 3 deletions geopandas/base.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from warnings import warn
import warnings
from warnings import warn

import numpy as np
import pandas as pd
from pandas import DataFrame, Series
import shapely
from shapely.geometry import box, MultiPoint
from pandas import DataFrame, Series
from shapely.geometry import MultiPoint, box
from shapely.geometry.base import BaseGeometry

from . import _compat as compat
Expand Down Expand Up @@ -1260,6 +1260,45 @@ def segmentize(self, max_segment_length):
"""
return _delegate_geo_method("segmentize", self, max_segment_length)

def transform(self, transformation, include_z=False):
"""Returns a ``GeoSeries`` with the transformation function
applied to the geom column coordinates.

JohnMoutafis marked this conversation as resolved.
Show resolved Hide resolved
Parameters
----------
transformation : Callable
A function that transforms a (N, 2) or (N, 3) ndarray of float64
to another (N,2) or (N, 3) ndarray of float64
include_z : bool, default False
If True include the third dimension in the coordinates array that
is passed to the transformation function. If a geometry has no third
dimension, the z-coordinates passed to the function will be NaN.
JohnMoutafis marked this conversation as resolved.
Show resolved Hide resolved

Returns
-------
GeoSeries

Examples
--------
>>> from shapely import Point, Polygon
>>> s = geopandas.GeoSeries([Point(0, 0)])
>>> s.transform(lambda x: x + 1)
0 POINT (1.00000 1.00000)
dtype: geometry

>>> s = geopandas.GeoSeries([Polygon([(0, 0), (1, 1), (0, 1)])])
>>> s.transform(lambda x: x * [2, 3])
0 POLYGON ((0.00000 0.00000, 2.00000 3.00000, 0.00000 3.00000...
dtype: geometry

By default the third dimension is ignored
>>> s = geopandas.GeoSeries([Point(0, 0, 0)])
JohnMoutafis marked this conversation as resolved.
Show resolved Hide resolved
>>> s.transform(lambda x: x + 1, include_z=True)
0 POINT Z (1.00000 1.00000 1.00000)
dtype: geometry
"""
return _delegate_geo_method("transform", self, transformation, include_z)

#
# Reduction operations that return a Shapely geometry
#
Expand Down
40 changes: 32 additions & 8 deletions geopandas/tests/test_geom_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,28 @@
import warnings

import numpy as np
import pytest
import shapely
from numpy.testing import assert_array_equal
from pandas import DataFrame, Index, MultiIndex, Series, concat

import shapely

from pandas.testing import assert_frame_equal, assert_index_equal, assert_series_equal
from shapely import wkt
from shapely.geometry import (
LinearRing,
LineString,
MultiLineString,
MultiPoint,
MultiPolygon,
Point,
Polygon,
MultiPolygon,
)
from shapely.geometry.collection import GeometryCollection
from shapely.ops import unary_union
from shapely import wkt

from geopandas import GeoDataFrame, GeoSeries
from geopandas.base import GeoPandasBase

from geopandas.testing import assert_geodataframe_equal
from geopandas.tests.util import assert_geoseries_equal, geom_almost_equals, geom_equals
from pandas.testing import assert_frame_equal, assert_index_equal, assert_series_equal
import pytest


def assert_array_dtype_equal(a, b, *args, **kwargs):
Expand Down Expand Up @@ -915,6 +912,33 @@ def test_segmentize_linestrings(self):
assert_geoseries_equal(expected_g1, result_g1)
assert_geoseries_equal(expected_g5, result_g5)

def test_transform(self):
JohnMoutafis marked this conversation as resolved.
Show resolved Hide resolved
test_2d = GeoSeries(
[LineString([(2, 2), (4, 4)]), Polygon([(0, 0), (1, 1), (0, 1)])]
)
expected_2d = GeoSeries(
[LineString([(4, 6), (8, 12)]), Polygon([(0, 0), (2, 3), (0, 3)])]
)
result_2d = test_2d.transform(lambda x: x * [2, 3])
assert_geoseries_equal(expected_2d, result_2d)

test_3d = GeoSeries(
[
Point(0, 0, 0),
LineString([(2, 2, 2), (4, 4, 4)]),
Polygon([(0, 0, 0), (1, 1, 1), (0, 1, 0.5)]),
]
)
expected_3d = GeoSeries(
[
Point(1, 1, 1),
LineString([(3, 3, 3), (5, 5, 5)]),
Polygon([(1, 1, 1), (2, 2, 2), (1, 2, 1.5)]),
]
)
result_3d = test_3d.transform(lambda x: x + 1, include_z=True)
assert_geoseries_equal(expected_3d, result_3d)

def test_concave_hull(self):
assert_geoseries_equal(self.squares, self.squares.concave_hull())

Expand Down