“There was a point in time where it was so clear that the thing to do was put these technologies together”

GeoParquet

# ~5s
geopandas.read_parquet("ns-water_elevation_geo.parquet").geometry.crs
#> <Compound CRS: {"$schema": "https://proj.org/schemas/v0.7/projjso ...>
#> Name: NAD83(CSRS)v6 / UTM zone 20N + CGVD2013(CGG2013) height

…but it still takes 5s (and what about other Arrow stuff?)

Spatial data engineering in 2024

…or so we thought

https://github.com/apache/parquet-format/pull/240

…or so we thought

https://github.com/apache/iceberg/pull/10981






!?!?!?!!?!?!

Geometry

Geography

Coordinate Reference Systems

ax = df[df.ZVALUE > 500].plot()

Coordinate Reference Systems

url = "https://raw.githubusercontent.com/geoarrow/geoarrow-data/v0.2.0/natural-earth/files/natural-earth_countries.fgb"
countries = geopandas.read_file(url)
countries = countries[countries.name == "Canada"].to_crs(df.crs).intersection(df.union_all().convex_hull)
ax = df[df.ZVALUE > 500].plot()
countries.boundary.plot(color="purple", ax=ax)

Statistics

Nobody should have to read all the row groups!

(Global?) Statistics

x_range: [-180.00, 180.00]

(Global?) Statistics

x_range: [177.28, -179.79]

…and finally!

https://github.com/apache/arrow/pull/45459

…and finally!

https://github.com/apache/arrow/pull/45459

Spatial data engineering in 2025

import geoarrow.pyarrow

f = "ns-water_elevation.parquet"
tab = parquet.read_table(f)
geopandas.GeoDataFrame.from_arrow(tab).info()
#> <class 'geopandas.geodataframe.GeoDataFrame'>
#> RangeIndex: 11438004 entries, 0 to 11438003
#> Data columns (total 4 columns):
#>  #   Column     Dtype
#> ---  ------     -----
#>  0   FEAT_CODE  object
#>  1   FEAT_DESC  object
#>  2   ZVALUE     float64
#>  3   geometry   geometry

Spatial data engineering in 2025

import duckdb

duckdb.load_extension("spatial")
duckdb.sql("CALL register_geoarrow_extensions()")

tab = parquet.read_table(f)
duckdb.sql("SELECT geometry FROM tab LIMIT 5")
#> ┌──────────────────────────────────────────────────────────────────┐
#> │                             geometry                             │
#> │                             geometry                             │
#> ├──────────────────────────────────────────────────────────────────┤
#> │ POINT Z (255919.02740000002 4831906.580700001 6.699999999999363) │
#> │ POINT Z (256023.9274000004 4831899.6807 1.399999999999977)       │
#> │ POINT Z (255988.62739999965 4831942.2807 1.399999999999977)      │
#> │ POINT Z (255900.7274000002 4831946.8807 1.399999999999977)       │
#> │ POINT Z (255862.2274000002 4831922.580700001 9.900000000000091)  │
#> └──────────────────────────────────────────────────────────────────┘

Spatial data engineering in 2025

Stay tuned…

sd.read_parquet(f).to_view("tab")
sd.sql("SELECT * FROM tab").to_pandas()

Spatial data engineering in 2025

@paleolimbot / dewey.dunnington.ca

Get the data!

curl -L \
  https://github.com/geoarrow/geoarrow-data/releases/download/v0.2.0/ns-water_elevation.fgb \
  -o ns-water_elevation.fgb

curl -L \
  https://github.com/geoarrow/geoarrow-data/releases/download/v0.2.0/ns-water_elevation_geo.parquet \
  -o ns-water_elevation_geo.parquet

curl -L \
  https://github.com/geoarrow/geoarrow-data/releases/download/v0.2.0/ns-water_elevation.parquet \
  -o ns-water_elevation.parquet