feat: detect GeoArrow columns in PyArrow tables - #10558
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
All contributors have signed the CLA ✍️ ✅ |
There was a problem hiding this comment.
Pull request overview
This PR extends marimo’s table geometry support to PyArrow-backed (Narwhals) tables by detecting GeoArrow extension metadata and treating those columns as the geometry semantic type, ensuring correct serialization and operation-guard behavior.
Changes:
- Detect GeoArrow geometry columns in PyArrow tables by reading
ARROW:extension:namefield metadata (geoarrow.*,ogc.wkb). - Format geometry cells during
NarwhalsTableManager.to_json_str()(WKB → placeholder; WKT/objects → capped text) while preserving schema metadata acrossapply_formatting(). - Add/update characterization and contract tests covering detection, formatting, and guard behavior (search/top-k/unique/stats).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| tests/_plugins/ui/_impl/tables/test_geometry.py | Adds PyArrow/GeoArrow detection + manager behavior tests (serialization + operation guards). |
| tests/_plugins/ui/_impl/tables/test_geometry_fixtures.py | Updates GeoArrow characterization expectations to geometry semantic type. |
| marimo/_plugins/ui/_impl/tables/narwhals_table.py | Formats geometry cells in JSON output and changes formatting application to preserve PyArrow field metadata. |
| marimo/_plugins/ui/_impl/tables/geometry.py | Adds PyArrow GeoArrow detection via field extension metadata parsing. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Architecture diagram
sequenceDiagram
participant UI as Marimo UI
participant TM as Table Manager
participant NTM as NarwhalsTableManager
participant GEO as Geometry Utils
participant NW as Narwhals Frame
participant PA as PyArrow Table
Note over UI,PA: GeoArrow Column Detection and Formatting Flow
UI->>TM: Request table data
TM->>NTM: get_field_types()
NTM->>GEO: find_geometry_columns(frame)
GEO->>NW: Check implementation type
alt PyArrow implementation
NW-->>GEO: is_pyarrow() = true
GEO->>PA: Get schema fields
PA-->>GEO: Field metadata
loop For each field
GEO->>GEO: Read ARROW:extension:name
alt geoarrow.wkb or ogc.wkb
GEO->>GEO: Set encoding = "wkb"
else geoarrow.wkt
GEO->>GEO: Set encoding = "wkt"
else geoarrow.* prefix
GEO->>GEO: Set encoding = "other"
else Non-geo extension
GEO->>GEO: Skip column
end
end
GEO-->>NTM: Geometry column map
NTM-->>TM: Field types with "geometry" semantic
else Pandas implementation
NW-->>GEO: is_pandas() = true
GEO->>GEO: Use Pandas-specific detection
GEO-->>NTM: Geometry column map
NTM-->>TM: Field types with "geometry" semantic
end
Note over UI,PA: Table JSON Serialization Flow
UI->>TM: Get table data (to_json_str)
TM->>NTM: to_json_str()
NTM->>NTM: Apply formatting if mapping
alt Format mapping provided
NTM->>NW: Apply column formatting
loop For each formatted column
NTM->>NW: Create new series
NW->>PA: with_columns()
PA-->>NW: Updated table with preserved metadata
end
end
NTM->>NW: Get rows as named dicts
NW-->>NTM: Row data with raw geometry values
alt Geometry columns found
loop For each row
loop For each column
alt Is geometry column
NTM->>GEO: format_geometry_cell(value, encoding)
alt WKB encoding
GEO->>GEO: Generate placeholder with byte size
else WKT encoding
GEO->>GEO: Pass through text, cap length
else Other encoding
GEO->>GEO: Skip or minimal formatting
end
GEO-->>NTM: Formatted geometry value
end
end
end
end
NTM->>NTM: sanitize_json_bigint()
NTM-->>UI: JSON string with formatted geometry
Note over UI,PA: Downstream Operations
UI->>TM: Search / sort / stats request
TM->>NTM: Operation on geometry column
NTM->>GEO: Check _geometry_columns
alt Search on geometry
NTM-->>TM: Skip search (0 results)
else Top-K on geometry
NTM-->>TM: Return empty list
else Unique values on geometry
NTM-->>TM: Return empty list
else Stats on geometry
NTM->>PA: Count total and nulls
PA-->>NTM: Stats with unique = null
NTM-->>TM: Stats summary
end
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
953daca to
fee6cd1
Compare
e4ff06b to
f1a83b2
Compare
fee6cd1 to
9d1c439
Compare
f1a83b2 to
50c03c5
Compare
## 📝 Summary Add shared geometry fixtures and current-behavior baselines for the geospatial foundation work in MO-6362. Freeze false-positive and ordinary-table payloads, and keep geometry characterization local until it runs reliably in CI. ## 🗺️ Stack This PR is part of a four-PR stack that adds a semantic `geometry` type for geospatial columns ([MO-6362](https://linear.app/marimo/issue/MO-6362)). Merge bottom-up with squash. Each PR targets the branch below it, so each diff shows only its own commits. After each merge, I rebase the remaining PRs. 1. #10516: geometry fixture corpus and ordinary-table baselines ⬅️ this PR 2. #10536: `geometry` contract and GeoPandas detection 3. #10558: PyArrow adapter (GeoArrow field metadata) 4. #10592: DuckDB adapter and SQL metadata (completes the release gate) ibis detection is deferred: no user demand, and nothing downstream depends on it. Closes MO-7322
apply_formatting must not rebuild geometry columns via new_series, which drops GeoArrow field metadata. to_json_str now reads geometry detection from the formatted manager so the two views stay aligned.
9d1c439 to
501d40f
Compare
50c03c5 to
f713ef6
Compare
4e6b1c5
into
kg/geometry-contract-geopandas
Summary
Detect GeoArrow extension metadata on PyArrow tables as the
geometrysemantic type (MO-6362).The generic
NarwhalsTableManagerformats geometry cells into_json_strand preserves PyArrow field metadata throughapply_formatting. Existing host guards (search, sort, stats, top-k, unique values) activate via_geometry_columnswith no new guard code.GeoPandas and pandas tables are unchanged; they continue to use
PandasTableManageroverrides from #10536.No frontend changes.
🗺️ Stack
This PR is part of a four-PR stack that adds a semantic
geometrytype for geospatial columns (MO-6362). Merge bottom-up with squash. Each PR targets the branch below it, so each diff shows only its own commits. After each merge, I rebase the remaining PRs.geometrycontract and GeoPandas detectionibis detection is deferred: no user demand, and nothing downstream depends on it.
Important
Release gate: do not include this PR in a marimo release until #10592 also merges.
Closes MO-7324