diff --git a/geopandas/geoseries.py b/geopandas/geoseries.py index c11850f..6bc586b 100644 --- a/geopandas/geoseries.py +++ b/geopandas/geoseries.py @@ -3,8 +3,10 @@ from warnings import warn import numpy as np from pandas import Series, DataFrame +from pandas.core.indexing import _NDFrameIndexer +from pandas.util.decorators import cache_readonly import pyproj -from shapely.geometry import shape, Polygon, Point +from shapely.geometry import box, shape, Polygon, Point from shapely.geometry.collection import GeometryCollection from shapely.geometry.base import BaseGeometry from shapely.ops import transform @@ -25,6 +27,28 @@ def _convert_array_args(args): args = ([args[0]],) return args +class _CoordinateIndexer(_NDFrameIndexer): + """ Indexing by coordinate slices """ + def _getitem_tuple(self, tup): + obj = self.obj + xs, ys = tup + # handle numeric values as x and/or y coordinate index + if type(xs) is not slice: + xs = slice(xs, xs) + if type(ys) is not slice: + ys = slice(ys, ys) + # don't know how to handle step; should this raise? + if xs.step is not None or ys.step is not None: + warn("Ignoring step - full interval is used.") + xmin, ymin, xmax, ymax = obj.total_bounds + bbox = box(xs.start or xmin, + ys.start or ymin, + xs.stop or xmax, + ys.stop or ymax) + idx = obj.intersects(bbox) + return obj[idx] + + class GeoSeries(GeoPandasBase, Series): """A Series object designed to store shapely geometry objects.""" _metadata = ['name', 'crs'] @@ -262,3 +286,5 @@ class GeoSeries(GeoPandasBase, Series): def __sub__(self, other): """Implement - operator as for builtin set type""" return self.difference(other) + +GeoSeries._create_indexer('cx', _CoordinateIndexer) diff --git a/tests/test_geoseries.py b/tests/test_geoseries.py index e867587..91c11f5 100644 --- a/tests/test_geoseries.py +++ b/tests/test_geoseries.py @@ -139,6 +139,13 @@ class TestSeries(unittest.TestCase): # XXX: method works inconsistently for different pandas versions #self.na_none.fillna(method='backfill') + def test_coord_slice(self): + """ Test CoordinateSlicer """ + # need some better test cases + self.assertTrue(geom_equals(self.g3, self.g3.cx[:, :])) + self.assertTrue(geom_equals(self.g3[[True, False]], self.g3.cx[0.9:, :0.1])) + self.assertTrue(geom_equals(self.g3[[False, True]], self.g3.cx[0:0.1, 0.9:1.0])) + def test_geoseries_geointerface(self): self.assertEqual(self.g1.__geo_interface__['type'], 'FeatureCollection') self.assertEqual(len(self.g1.__geo_interface__['features']),