11from __future__ import annotations
22
3- from typing import TYPE_CHECKING , Any , Dict , List , Optional , Sequence , TypeVar
3+ from typing import TYPE_CHECKING , Any , Dict , List , Optional , Sequence , Tuple , TypeVar
44
55import numpy as np
66from arro3 .core import Schema
1212if TYPE_CHECKING :
1313 import geopandas as gpd
1414 import pandas as pd
15+ from numpy .typing import NDArray
1516
1617 DF = TypeVar ("DF" , bound = pd .DataFrame )
1718
@@ -120,10 +121,61 @@ def remove_extension_kwargs(
120121
121122def split_mixed_gdf (gdf : gpd .GeoDataFrame ) -> List [gpd .GeoDataFrame ]:
122123 """Split a GeoDataFrame into one or more GeoDataFrames with unique geometry type"""
124+ indices = indices_by_geometry_type (gdf .geometry )
125+ if indices is None :
126+ return [gdf ]
127+
128+ point_indices , linestring_indices , polygon_indices = indices
129+
130+ # Here we intentionally check geometries in a specific order.
131+ # Starting from polygons, then linestrings, then points,
132+ # so that the order of generated layers is polygon, then path then scatterplot.
133+ # This ensures that points are rendered on top and polygons on the bottom.
134+ gdfs = []
135+ for single_type_geometry_indices in (
136+ polygon_indices ,
137+ linestring_indices ,
138+ point_indices ,
139+ ):
140+ if len (single_type_geometry_indices ) > 0 :
141+ gdfs .append (gdf .iloc [single_type_geometry_indices ])
142+
143+ return gdfs
144+
145+
146+ def split_mixed_shapely_array (
147+ geometry : NDArray [np .object_ ],
148+ ) -> List [NDArray [np .object_ ]]:
149+ """Split a shapely array into one or more arrays with unique geometry type"""
150+ indices = indices_by_geometry_type (geometry )
151+ if indices is None :
152+ return [geometry ]
153+
154+ point_indices , linestring_indices , polygon_indices = indices
155+
156+ # Here we intentionally check geometries in a specific order.
157+ # Starting from polygons, then linestrings, then points,
158+ # so that the order of generated layers is polygon, then path then scatterplot.
159+ # This ensures that points are rendered on top and polygons on the bottom.
160+ arrays = []
161+ for single_type_geometry_indices in (
162+ polygon_indices ,
163+ linestring_indices ,
164+ point_indices ,
165+ ):
166+ if len (single_type_geometry_indices ) > 0 :
167+ arrays .append (geometry [single_type_geometry_indices ])
168+
169+ return arrays
170+
171+
172+ def indices_by_geometry_type (
173+ geometry : NDArray [np .object_ ],
174+ ) -> Tuple [NDArray [np .int64 ], NDArray [np .int64 ], NDArray [np .int64 ]] | None :
123175 import shapely
124176 from shapely import GeometryType
125177
126- type_ids = np .array (shapely .get_type_id (gdf . geometry ))
178+ type_ids = np .array (shapely .get_type_id (geometry ))
127179 unique_type_ids = set (np .unique (type_ids ))
128180
129181 if GeometryType .GEOMETRYCOLLECTION in unique_type_ids :
@@ -133,17 +185,17 @@ def split_mixed_gdf(gdf: gpd.GeoDataFrame) -> List[gpd.GeoDataFrame]:
133185 raise ValueError ("LinearRings not currently supported" )
134186
135187 if len (unique_type_ids ) == 1 :
136- return [ gdf ]
188+ return None
137189
138190 if len (unique_type_ids ) == 2 :
139191 if unique_type_ids == {GeometryType .POINT , GeometryType .MULTIPOINT }:
140- return [ gdf ]
192+ return None
141193
142194 if unique_type_ids == {GeometryType .LINESTRING , GeometryType .MULTILINESTRING }:
143- return [ gdf ]
195+ return None
144196
145197 if unique_type_ids == {GeometryType .POLYGON , GeometryType .MULTIPOLYGON }:
146- return [ gdf ]
198+ return None
147199
148200 point_indices = np .where (
149201 (type_ids == GeometryType .POINT ) | (type_ids == GeometryType .MULTIPOINT )
@@ -158,17 +210,4 @@ def split_mixed_gdf(gdf: gpd.GeoDataFrame) -> List[gpd.GeoDataFrame]:
158210 (type_ids == GeometryType .POLYGON ) | (type_ids == GeometryType .MULTIPOLYGON )
159211 )[0 ]
160212
161- # Here we intentionally check geometries in a specific order.
162- # Starting from polygons, then linestrings, then points,
163- # so that the order of generated layers is polygon, then path then scatterplot.
164- # This ensures that points are rendered on top and polygons on the bottom.
165- gdfs = []
166- for single_type_geometry_indices in (
167- polygon_indices ,
168- linestring_indices ,
169- point_indices ,
170- ):
171- if len (single_type_geometry_indices ) > 0 :
172- gdfs .append (gdf .iloc [single_type_geometry_indices ])
173-
174- return gdfs
213+ return point_indices , linestring_indices , polygon_indices
0 commit comments