Skip to content

Commit 67e10c7

Browse files
authored
fix: Enable build against geoarrow-c 0.2 (#64)
1 parent 9d591c1 commit 67e10c7

File tree

10 files changed

+169
-103
lines changed

10 files changed

+169
-103
lines changed

geoarrow-pandas/src/geoarrow/pandas/lib.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -507,18 +507,18 @@ def bounds(self):
507507
"""See :func:`geoarrow.pyarrow.box`"""
508508
array_or_chunked = _ga.box(self._obj)
509509
if isinstance(array_or_chunked, _pa.ChunkedArray):
510-
flattened = [chunk.flatten() for chunk in array_or_chunked.chunks]
510+
flattened = [chunk.storage.flatten() for chunk in array_or_chunked.chunks]
511511
seriesish = [
512512
_pa.chunked_array(item, _pa.float64()) for item in zip(*flattened)
513513
]
514514
else:
515-
seriesish = array_or_chunked.flatten()
515+
seriesish = array_or_chunked.storage.flatten()
516516

517517
return _pd.DataFrame(
518518
{
519519
"xmin": seriesish[0],
520-
"xmax": seriesish[1],
521-
"ymin": seriesish[2],
520+
"xmax": seriesish[2],
521+
"ymin": seriesish[1],
522522
"ymax": seriesish[3],
523523
},
524524
index=self._obj.index,

geoarrow-pyarrow/src/geoarrow/pyarrow/_array.py

Lines changed: 9 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -78,49 +78,18 @@ def __repr__(self):
7878
return f"{type_name}:{repr(self.type)}[{len(self)}]\n{items_str}".strip()
7979

8080

81-
class PointArray(GeometryExtensionArray):
82-
pass
83-
84-
85-
class LinestringArray(GeometryExtensionArray):
86-
pass
87-
88-
89-
class PolygonArray(GeometryExtensionArray):
90-
pass
91-
92-
93-
class MultiPointArray(GeometryExtensionArray):
94-
pass
95-
96-
97-
class MultiLinestringArray(GeometryExtensionArray):
98-
pass
99-
100-
101-
class MultiPolygonArray(GeometryExtensionArray):
102-
pass
81+
class BoxArray(GeometryExtensionArray):
82+
def __repr__(self):
83+
type_name = type(self).__name__
84+
items_str = "\n".join(repr(item.bounds) for item in self)
85+
return f"{type_name}:{repr(self.type)}[{len(self)}]\n{items_str}".strip()
10386

10487

10588
def array_cls_from_name(name):
106-
if name == "geoarrow.wkb":
107-
return GeometryExtensionArray
108-
elif name == "geoarrow.wkt":
109-
return GeometryExtensionArray
110-
elif name == "geoarrow.point":
111-
return PointArray
112-
elif name == "geoarrow.linestring":
113-
return LinestringArray
114-
elif name == "geoarrow.polygon":
115-
return PolygonArray
116-
elif name == "geoarrow.multipoint":
117-
return MultiPointArray
118-
elif name == "geoarrow.multilinestring":
119-
return MultiLinestringArray
120-
elif name == "geoarrow.multipolygon":
121-
return MultiPolygonArray
89+
if name == "geoarrow.box":
90+
return BoxArray
12291
else:
123-
raise ValueError(f'Expected valid extension name but got "{name}"')
92+
return GeometryExtensionArray
12493

12594

12695
# Inject array_cls_from_name exactly once to avoid circular import
@@ -142,7 +111,7 @@ def array(obj, type_=None, *args, **kwargs) -> GeometryExtensionArray:
142111
GeometryExtensionArray:WktType(geoarrow.wkt)[1]
143112
<POINT (0 1)>
144113
>>> ga.as_geoarrow(["POINT (0 1)"])
145-
PointArray:PointType(geoarrow.point)[1]
114+
GeometryExtensionArray:PointType(geoarrow.point)[1]
146115
<POINT (0 1)>
147116
"""
148117
# Convert GeoPandas to WKB

geoarrow-pyarrow/src/geoarrow/pyarrow/_compute.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ def as_geoarrow(obj, type=None, coord_type=None, promote_multi=False):
251251
252252
>>> import geoarrow.pyarrow as ga
253253
>>> ga.as_geoarrow(["POINT (0 1)", "MULTIPOINT Z (0 1 2, 4 5 6)"])
254-
MultiPointArray:MultiPointType(geoarrow.multipoint_z)[2]
254+
GeometryExtensionArray:MultiPointType(geoarrow.multipoint_z)[2]
255255
<MULTIPOINT Z (0 1 nan)>
256256
<MULTIPOINT Z (0 1 2, 4 5 6)>
257257
"""
@@ -307,7 +307,7 @@ def make_point(x, y, z=None, m=None, crs=None):
307307
308308
>>> import geoarrow.pyarrow as ga
309309
>>> ga.make_point([1, 2, 3], [4, 5, 6])
310-
PointArray:PointType(geoarrow.point)[3]
310+
GeometryExtensionArray:PointType(geoarrow.point)[3]
311311
<POINT (1 4)>
312312
<POINT (2 5)>
313313
<POINT (3 6)>
@@ -338,10 +338,11 @@ def make_point(x, y, z=None, m=None, crs=None):
338338

339339
def _box_point_struct(storage):
340340
arrays = storage.flatten()
341-
return pa.StructArray.from_arrays(
342-
[arrays[0], arrays[0], arrays[1], arrays[1]],
343-
names=["xmin", "xmax", "ymin", "ymax"],
341+
box_storage = pa.StructArray.from_arrays(
342+
[arrays[0], arrays[1], arrays[0], arrays[1]],
343+
names=["xmin", "ymin", "xmax", "ymax"],
344344
)
345+
return _type.types.box().to_pyarrow().wrap_array(box_storage)
345346

346347

347348
def box(obj):
@@ -350,7 +351,7 @@ def box(obj):
350351
351352
>>> import geoarrow.pyarrow as ga
352353
>>> ga.box(["LINESTRING (0 10, 34 -1)"]).type
353-
StructType(struct<xmin: double, xmax: double, ymin: double, ymax: double>)
354+
BoxType(geoarrow.box)
354355
>>> print(str(ga.box(["LINESTRING (0 10, 34 -1)"])))
355356
-- is_valid: all not null
356357
-- child 0 type: double
@@ -359,11 +360,11 @@ def box(obj):
359360
]
360361
-- child 1 type: double
361362
[
362-
34
363+
-1
363364
]
364365
-- child 2 type: double
365366
[
366-
-1
367+
34
367368
]
368369
-- child 3 type: double
369370
[
@@ -399,15 +400,15 @@ def _box_agg_point_struct(arrays):
399400
out = [list(pc.min_max(array).values()) for array in arrays]
400401
out_dict = {
401402
"xmin": out[0][0].as_py(),
402-
"xmax": out[0][1].as_py(),
403403
"ymin": out[1][0].as_py(),
404+
"xmax": out[0][1].as_py(),
404405
"ymax": out[1][1].as_py(),
405406
}
406407

407408
# Apparently pyarrow reorders dict keys when inferring scalar types?
408-
return pa.scalar(
409-
out_dict, pa.struct([(nm, pa.float64()) for nm in out_dict.keys()])
410-
)
409+
storage_type = pa.struct([(nm, pa.float64()) for nm in out_dict.keys()])
410+
storage_array = pa.array([out_dict], storage_type)
411+
return _type.types.box().to_pyarrow().wrap_array(storage_array)[0]
411412

412413

413414
def box_agg(obj):
@@ -417,7 +418,7 @@ def box_agg(obj):
417418
418419
>>> import geoarrow.pyarrow as ga
419420
>>> ga.box_agg(["POINT (0 10)", "POINT (34 -1)"])
420-
<pyarrow.StructScalar: [('xmin', 0.0), ('xmax', 34.0), ('ymin', -1.0), ('ymax', 10.0)]>
421+
BoxScalar({'xmin': 0.0, 'ymin': -1.0, 'xmax': 34.0, 'ymax': 10.0})
421422
"""
422423

423424
obj = obj_as_array_or_chunked(obj)
@@ -495,7 +496,7 @@ def with_coord_type(obj, coord_type):
495496
496497
>>> import geoarrow.pyarrow as ga
497498
>>> ga.with_coord_type(["POINT (0 1)"], ga.CoordType.INTERLEAVED)
498-
PointArray:PointType(interleaved geoarrow.point)[1]
499+
GeometryExtensionArray:PointType(interleaved geoarrow.point)[1]
499500
<POINT (0 1)>
500501
"""
501502
return as_geoarrow(obj, coord_type=coord_type)
@@ -537,10 +538,10 @@ def with_dimensions(obj, dimensions):
537538
538539
>>> import geoarrow.pyarrow as ga
539540
>>> ga.with_dimensions(["POINT (0 1)"], ga.Dimensions.XYZM)
540-
PointArray:PointType(geoarrow.point_zm)[1]
541+
GeometryExtensionArray:PointType(geoarrow.point_zm)[1]
541542
<POINT ZM (0 1 nan nan)>
542543
>>> ga.with_dimensions(["POINT ZM (0 1 2 3)"], ga.Dimensions.XY)
543-
PointArray:PointType(geoarrow.point)[1]
544+
GeometryExtensionArray:PointType(geoarrow.point)[1]
544545
<POINT (0 1)>
545546
"""
546547
obj = as_geoarrow(obj)
@@ -557,13 +558,13 @@ def with_geometry_type(obj, geometry_type):
557558
558559
>>> import geoarrow.pyarrow as ga
559560
>>> ga.with_geometry_type(["POINT (0 1)"], ga.GeometryType.MULTIPOINT)
560-
MultiPointArray:MultiPointType(geoarrow.multipoint)[1]
561+
GeometryExtensionArray:MultiPointType(geoarrow.multipoint)[1]
561562
<MULTIPOINT (0 1)>
562563
>>> ga.with_geometry_type(["MULTIPOINT (0 1)"], ga.GeometryType.POINT)
563-
PointArray:PointType(geoarrow.point)[1]
564+
GeometryExtensionArray:PointType(geoarrow.point)[1]
564565
<POINT (0 1)>
565566
>>> ga.with_geometry_type(["LINESTRING EMPTY", "POINT (0 1)"], ga.GeometryType.POINT)
566-
PointArray:PointType(geoarrow.point)[2]
567+
GeometryExtensionArray:PointType(geoarrow.point)[2]
567568
<POINT (nan nan)>
568569
<POINT (0 1)>
569570
>>> ga.with_geometry_type(["MULTIPOINT (0 1, 2 3)"], ga.GeometryType.POINT)

geoarrow-pyarrow/src/geoarrow/pyarrow/_kernel.py

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,29 @@
22

33
import pyarrow as pa
44
import pyarrow_hotfix as _ # noqa: F401
5+
from geoarrow.types import box as box_spec
56
from geoarrow.pyarrow._type import GeometryExtensionType
67

78

89
_lazy_lib = None
10+
_geoarrow_c_version = None
911

1012

1113
def _geoarrow_c():
12-
global _lazy_lib
14+
global _lazy_lib, _geoarrow_c_version
1315
if _lazy_lib is None:
1416
try:
15-
from geoarrow.c import lib
17+
import geoarrow.c
18+
1619
except ImportError as e:
1720
raise ImportError("Requested operation requires geoarrow-c") from e
1821

19-
_lazy_lib = lib
22+
_lazy_lib = geoarrow.c.lib
23+
if hasattr(geoarrow.c, "__version_tuple__"):
24+
_geoarrow_c_version = geoarrow.c.__version_tuple__
25+
else:
26+
_geoarrow_c_version = (0, 1, 0)
27+
2028
return _lazy_lib
2129

2230

@@ -109,11 +117,19 @@ def unique_geometry_types_agg(type_in):
109117

110118
@staticmethod
111119
def box(type_in):
112-
return Kernel("box", type_in)
120+
kernel = Kernel("box", type_in)
121+
if _geoarrow_c_version <= (0, 1, 3):
122+
return BoxKernelCompat(kernel)
123+
else:
124+
return kernel
113125

114126
@staticmethod
115127
def box_agg(type_in):
116-
return Kernel("box_agg", type_in)
128+
kernel = Kernel("box_agg", type_in)
129+
if _geoarrow_c_version <= (0, 1, 3):
130+
return BoxKernelCompat(kernel)
131+
else:
132+
return kernel
117133

118134
@staticmethod
119135
def _pack_options(options):
@@ -132,3 +148,29 @@ def _pack_options(options):
132148
bytes += v.encode("UTF-8")
133149

134150
return bytes
151+
152+
153+
class BoxKernelCompat:
154+
"""A wrapper around the "box" kernel that works for geoarrow-c 0.1.
155+
This is mostly to ease the transition for geoarrow-python CI while
156+
all the packages are being updated."""
157+
158+
def __init__(self, parent: Kernel):
159+
self.parent = parent
160+
self.type_out = box_spec().to_pyarrow().with_crs(parent._type_in.crs)
161+
162+
def push(self, arr):
163+
parent_result = self.parent.push(arr)
164+
return (
165+
None if parent_result is None else self._old_box_to_new_box(parent_result)
166+
)
167+
168+
def finish(self):
169+
return self._old_box_to_new_box(self.parent.finish())
170+
171+
def _old_box_to_new_box(self, array):
172+
xmin, xmax, ymin, ymax = array.flatten()
173+
storage = pa.StructArray.from_arrays(
174+
[xmin, ymin, xmax, ymax], names=["xmin", "ymin", "xmax", "ymax"]
175+
)
176+
return self.type_out.wrap_array(storage)

0 commit comments

Comments
 (0)