vibespatial.geometry.device_array¶
DeviceGeometryArray – pandas ExtensionArray backed by device-resident OwnedGeometryArray.
This module inverts the storage model: OwnedGeometryArray is the source of truth (device-resident when GPU is available), and Shapely objects are materialized lazily on demand. The goal is to eliminate D->H->Shapely->H->D roundtrips when GPU-decoded geometry flows through GeoDataFrame into GPU consumers.
See epic vibeSpatial-o17.9.13 and ADR-0005 for design rationale.
Attributes¶
Classes¶
pandas dtype for device-resident geometry arrays. |
|
pandas ExtensionArray backed by a device-resident OwnedGeometryArray. |
Module Contents¶
- vibespatial.geometry.device_array.TAG_FAMILIES¶
- class vibespatial.geometry.device_array.DeviceGeometryDtype¶
pandas dtype for device-resident geometry arrays.
- type¶
The scalar type for the array, e.g.
intIt’s expected
ExtensionArray[item]returns an instance ofExtensionDtype.typefor scalaritem, assuming that value is valid (not NA). NA values do not need to be instances of type.
- name = 'device_geometry'¶
A string identifying the data type.
Will be used for display in, e.g.
Series.dtype
- na_value = None¶
Default NA value to use for this type.
This is used in e.g. ExtensionArray.take. This should be the user-facing “boxed” version of the NA value, not the physical NA value for storage. e.g. for JSONArray, this is an empty dictionary.
- classmethod construct_from_string(string: str) DeviceGeometryDtype¶
Construct this type from a string.
This is useful mainly for data types that accept parameters. For example, a period dtype accepts a frequency parameter that can be set as
period[h](where H means hourly frequency).By default, in the abstract class, just the name of the type is expected. But subclasses can overwrite this method to accept parameters.
Parameters¶
- stringstr
The name of the type, for example
category.
Returns¶
- ExtensionDtype
Instance of the dtype.
Raises¶
- TypeError
If a class cannot be constructed from this ‘string’.
Examples¶
For extension dtypes with arguments the following may be an adequate implementation.
>>> import re >>> @classmethod ... def construct_from_string(cls, string): ... pattern = re.compile(r"^my_type\[(?P<arg_name>.+)\]$") ... match = pattern.match(string) ... if match: ... return cls(**match.groupdict()) ... else: ... raise TypeError( ... f"Cannot construct a '{cls.__name__}' from '{string}'" ... )
- classmethod construct_array_type() type[DeviceGeometryArray]¶
Return the array type associated with this dtype.
Returns¶
type
- class vibespatial.geometry.device_array.DeviceGeometryArray(owned: vibespatial.geometry.owned.OwnedGeometryArray, *, crs: Any | None = None)¶
pandas ExtensionArray backed by a device-resident OwnedGeometryArray.
Source of truth is
_owned(an OwnedGeometryArray). Shapely objects are materialized lazily into_shapely_cacheonly when pandas or user code requires individual geometry objects.Key properties: -
takeoperates on owned buffers without Shapely round-trip. -copyduplicates owned buffers on the current residency side. -_concat_same_typemerges owned buffers. - Diagnostic events are emitted for every materialization (per ADR-0005).- property dtype: DeviceGeometryDtype¶
An instance of ExtensionDtype.
See Also¶
api.extensions.ExtensionDtype : Base class for extension dtypes. api.extensions.ExtensionArray : Base class for extension array types. api.extensions.ExtensionArray.dtype : The dtype of an ExtensionArray. Series.dtype : The dtype of a Series. DataFrame.dtype : The dtype of a DataFrame.
Examples¶
>>> pd.array([1, 2, 3]).dtype Int64Dtype()
- property owned: vibespatial.geometry.owned.OwnedGeometryArray¶
The underlying OwnedGeometryArray (source of truth).
- property crs: Any | None¶
- property nbytes: int¶
The number of bytes needed to store this object in memory.
See Also¶
ExtensionArray.shape: Return a tuple of the array dimensions. ExtensionArray.size: The number of elements in the array.
Examples¶
>>> pd.array([1, 2, 3]).nbytes 27
- isna() numpy.ndarray¶
A 1-D array indicating if each value is missing.
Returns¶
- numpy.ndarray or pandas.api.extensions.ExtensionArray
In most cases, this should return a NumPy ndarray. For exceptional cases like
SparseArray, where returning an ndarray would be expensive, an ExtensionArray may be returned.
See Also¶
ExtensionArray.dropna: Return ExtensionArray without NA values. ExtensionArray.fillna: Fill NA/NaN values using the specified method.
Notes¶
If returning an ExtensionArray, then
na_values._is_booleanshould be Truena_valuesshould implementExtensionArray._reduce()na_valuesshould implementExtensionArray._accumulate()na_values.anyandna_values.allshould be implemented
Examples¶
>>> arr = pd.array([1, 2, np.nan, np.nan]) >>> arr.isna() array([False, False, True, True])
- property geom_type: numpy.ndarray¶
Geometry type names from owned tags — no Shapely materialization.
- property is_empty: numpy.ndarray¶
Per-geometry emptiness from owned empty_mask — no Shapely materialization.
- property bounds: numpy.ndarray¶
Per-geometry bounds from owned coordinate buffers — no Shapely materialization.
Returns (N, 4) float64 array of [minx, miny, maxx, maxy].
- property total_bounds: numpy.ndarray¶
Aggregate bounds — no Shapely materialization.
- estimate_utm_crs(datum_name: str = 'WGS 84')¶
Estimate UTM CRS from bounds – no Shapely materialization.
- to_crs(crs=None, epsg=None)¶
Reproject via vibeProj transform_buffers – stays on device.
- check_geographic_crs(stacklevel: int) None¶
Warn if CRS is geographic.
- property area: numpy.ndarray¶
Area — GPU-accelerated from owned coordinate buffers, no Shapely.
- property length: numpy.ndarray¶
Length — GPU-accelerated from owned coordinate buffers, no Shapely.
- property is_valid: numpy.ndarray¶
OGC validity — GPU-accelerated from owned coordinate buffers, no Shapely.
is_valid_owned() covers full OGC validity: ring closure, min coords, ring self-intersection, hole-in-shell containment, ring-ring crossing, collinear overlap, and interior connectedness (multi-touch detection). Zero-copy: reads device buffers directly, returns boolean mask to host.
- property is_simple: numpy.ndarray¶
Simplicity — GPU-accelerated from owned coordinate buffers, no Shapely.
- property is_ring: numpy.ndarray¶
- property is_closed: numpy.ndarray¶
- property has_z: numpy.ndarray¶
has_z from owned metadata — OwnedGeometryArray is 2D (x/y only).
- property has_m: numpy.ndarray¶
has_m from owned metadata — OwnedGeometryArray is 2D (x/y only).
- is_valid_reason() numpy.ndarray¶
- property boundary¶
Boundary — GPU-accelerated via owned path, no Shapely.
- property centroid¶
- property convex_hull¶
Convex hull — GPU-accelerated via owned path, no Shapely.
- property envelope¶
- property exterior¶
- property unary_union¶
- union_all(method='unary', grid_size=None)¶
- buffer(distance, resolution=16, **kwargs)¶
Buffer – routes through owned dispatch with GPU kernel when possible.
- simplify(tolerance, preserve_topology=True)¶
- normalize(precision='auto')¶
- offset_curve(distance, quad_segs=8, join_style='round', mitre_limit=5.0)¶
- make_valid(method='linework', keep_collapsed=True)¶
- representative_point()¶
- affine_transform(matrix)¶
- translate(xoff=0.0, yoff=0.0, zoff=0.0)¶
- rotate(angle, origin='center', use_radians=False)¶
- scale(xfact=1.0, yfact=1.0, zfact=1.0, origin='center')¶
- skew(xs=0.0, ys=0.0, origin='center', use_radians=False)¶
- count_coordinates()¶
- count_geometries()¶
- count_interior_rings()¶
- to_wkb(**kwargs)¶
- to_wkt(**kwargs)¶
- to_owned() vibespatial.geometry.owned.OwnedGeometryArray¶
Return the underlying OwnedGeometryArray — no materialization.
- supports_owned_spatial_input() bool¶
Device-resident geometries always support the owned query path.
- owned_flat_sindex()¶
Return
(owned, flat_index)without Shapely materialization.The flat spatial index is built directly from the OwnedGeometryArray coordinate buffers and cached for reuse.
- property sindex¶
Spatial index that routes through the owned query engine.
Construction does NOT trigger Shapely materialization. The returned
SpatialIndexis backed by a lazy STRtree (built on first non-owned query) and eagerly caches the owned flat index.
- property has_sindex: bool¶
Check existence of the spatial index without generating it.
- intersects(other, *args, **kwargs)¶
- contains(other, *args, **kwargs)¶
- within(other, *args, **kwargs)¶
- touches(other, *args, **kwargs)¶
- crosses(other, *args, **kwargs)¶
- overlaps(other, *args, **kwargs)¶
- covers(other, *args, **kwargs)¶
- covered_by(other, *args, **kwargs)¶
- disjoint(other, *args, **kwargs)¶
- contains_properly(other, *args, **kwargs)¶
- equals(other, *args, **kwargs)¶
Return if another array is equivalent to this array.
Equivalent means that both arrays have the same shape and dtype, and all values compare equal. Missing values in the same location are considered equal (in contrast with normal equality).
Parameters¶
- otherExtensionArray
Array to compare to this Array.
Returns¶
- boolean
Whether the arrays are equivalent.
See Also¶
numpy.array_equal : Equivalent method for numpy array. Series.equals : Equivalent method for Series. DataFrame.equals : Equivalent method for DataFrame.
Examples¶
>>> arr1 = pd.array([1, 2, np.nan]) >>> arr2 = pd.array([1, 2, np.nan]) >>> arr1.equals(arr2) True
>>> arr1 = pd.array([1, 3, np.nan]) >>> arr2 = pd.array([1, 2, np.nan]) >>> arr1.equals(arr2) False
- geom_equals(other)¶
- geom_equals_exact(other, tolerance)¶
- distance(other, *args, **kwargs)¶
- dwithin(other, distance)¶
- hausdorff_distance(other, densify=None)¶
- frechet_distance(other, densify=None)¶
- clip_by_rect(xmin, ymin, xmax, ymax)¶
- intersection(other, *args, **kwargs)¶
- union(other, *args, **kwargs)¶
- difference(other, *args, **kwargs)¶
- symmetric_difference(other, *args, **kwargs)¶
- view(dtype=None) DeviceGeometryArray¶
Return a shallow view sharing the same owned array.
pandas’ ExtensionArray.view() calls
self[:]which triggers a fulltake; override to share the backing OwnedGeometryArray directly (semantically identical for immutable-in-practice DGA).
- take(indices: numpy.ndarray | collections.abc.Sequence[int], *, allow_fill: bool = False, fill_value: Any = None) DeviceGeometryArray¶
Take elements from an array.
Parameters¶
- indicessequence of int or one-dimensional np.ndarray of int
Indices to be taken.
- allow_fillbool, default False
How to handle negative values in indices.
False: negative values in indices indicate positional indices from the right (the default). This is similar to
numpy.take().True: negative values in indices indicate missing values. These values are set to fill_value. Any other other negative values raise a
ValueError.
- fill_valueany, optional
Fill value to use for NA-indices when allow_fill is True. This may be
None, in which case the default NA value for the type,self.dtype.na_value, is used.For many ExtensionArrays, there will be two representations of fill_value: a user-facing “boxed” scalar, and a low-level physical NA value. fill_value should be the user-facing version, and the implementation should handle translating that to the physical version for processing the take if necessary.
Returns¶
- ExtensionArray
An array formed with selected indices.
Raises¶
- IndexError
When the indices are out of bounds for the array.
- ValueError
When indices contains negative values other than
-1and allow_fill is True.
See Also¶
numpy.take : Take elements from an array along an axis. api.extensions.take : Take elements from an array.
Notes¶
ExtensionArray.take is called by
Series.__getitem__,.loc,iloc, when indices is a sequence of values. Additionally, it’s called bySeries.reindex(), or any other method that causes realignment, with a fill_value.Examples¶
Here’s an example implementation, which relies on casting the extension array to object dtype. This uses the helper method
pandas.api.extensions.take().def take(self, indices, allow_fill=False, fill_value=None): from pandas.api.extensions import take # If the ExtensionArray is backed by an ndarray, then # just pass that here instead of coercing to object. data = self.astype(object) if allow_fill and fill_value is None: fill_value = self.dtype.na_value # fill value should always be translated from the scalar # type for the array, to the physical storage type for # the data, before passing to take. result = take( data, indices, fill_value=fill_value, allow_fill=allow_fill ) return self._from_sequence(result, dtype=self.dtype)
- copy() DeviceGeometryArray¶
Return a copy of the array.
This method creates a copy of the ExtensionArray where modifying the data in the copy will not affect the original array. This is useful when you want to manipulate data without altering the original dataset.
Returns¶
- ExtensionArray
A new ExtensionArray object that is a copy of the current instance.
See Also¶
DataFrame.copy : Return a copy of the DataFrame. Series.copy : Return a copy of the Series.
Examples¶
>>> arr = pd.array([1, 2, 3]) >>> arr2 = arr.copy() >>> arr[0] = 2 >>> arr2 <IntegerArray> [1, 2, 3] Length: 3, dtype: Int64
- property diagnostics: list[vibespatial.geometry.owned.DiagnosticEvent]¶