Geospatial analysis with Ibis and DuckDB (redux)

blog
duckdb
geospatial
Author

Naty Clementi and Gil Forsyth

Published

January 16, 2024

Spatial Dev Guru wrote a great tutorial that walks you through a step-by-step geospatial analysis of bike sharing data using DuckDB.

Ibis has support for all the geospatial functions used on the tutorial, and we decided to replicate it and share it with you.

Installation

Install Ibis with the dependencies needed to work with geospatial data using DuckDB:

$ pip install 'ibis-framework[duckdb,geospatial]'

Data

The parquet file used in the original tutorial is available at https://github.com/iamgeoknight/common_datasets/tree/main/parquet. The original data is also available from the citibike source but as a .csv file.

from pathlib import Path
import tarfile
from urllib.request import urlretrieve

# Download data
url = "https://github.com/iamgeoknight/common_datasets/raw/main/parquet/202003-citibike-tripdata.tar.xz"
tar_path = Path("202003-citibike-tripdata.tar.xz")
parquet_path = Path("202003-citibike-tripdata.parquet")

if not tar_path.exists():
    urlretrieve(url, tar_path)

if not parquet_path.exists():
    with tarfile.open(tar_path, "r:xz") as t:
        t.extract("202003-citibike-tripdata.parquet")

Now that we have the data, we import Ibis and turn on the interactive mode, to easily explore the output of our queries.

from ibis.interactive import *

Let’s get started

Because this dataset does not contain any geometries, we have to load the spatial extension. If the dataset included any geometry columns, Ibis is smart enough to load the extension for us upon reading the data.

con = ibis.duckdb.connect("biketrip.ddb")
con.load_extension("spatial")

# read data and rename columns to use snake case
biketrip = con.read_parquet("202003-citibike-tripdata.parquet").rename("snake_case")
biketrip
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━┓
┃ tripduration  starttime                 stoptime                  start_station_id  start_station_name             start_station_latitude  start_station_longitude  end_station_id  end_station_name             end_station_latitude  end_station_longitude  bikeid  usertype    birth_year  gender ┃
┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━┩
│ int64stringstringint64stringfloat64float64int64stringfloat64float64int64stringint64int64  │
├──────────────┼──────────────────────────┼──────────────────────────┼──────────────────┼───────────────────────────────┼────────────────────────┼─────────────────────────┼────────────────┼─────────────────────────────┼──────────────────────┼───────────────────────┼────────┼────────────┼────────────┼────────┤
│         15892020-03-01 00:00:03.64002020-03-01 00:26:32.9860224Spruce St & Nassau St        40.711464-74.0055243574Prospect Pl & Underhill Ave40.676969-73.96579016214Subscriber19801 │
│          3892020-03-01 00:00:16.75602020-03-01 00:06:46.0620293Lafayette St & E 8 St        40.730207-73.991026223W 13 St & 7 Ave            40.737815-73.99994729994Subscriber19912 │
│          6142020-03-01 00:00:20.05802020-03-01 00:10:34.2200379W 31 St & 7 Ave              40.749156-73.991600515W 43 St & 10 Ave           40.760094-73.99461839853Subscriber19911 │
│          5972020-03-01 00:00:24.35102020-03-01 00:10:22.33903739Perry St & Greenwich Ave     40.735918-74.000939325E 19 St & 3 Ave            40.736245-73.98473842608Subscriber19891 │
│         19202020-03-01 00:00:26.11202020-03-01 00:32:26.2680236St Marks Pl & 2 Ave          40.728419-73.987140312446 Ave & 5 St              40.747310-73.95451036288Subscriber19931 │
│         20552020-03-01 00:00:46.10102020-03-01 00:35:01.2880471Grand St & Havemeyer St      40.712868-73.956981497E 17 St & Broadway         40.737050-73.99009331313Subscriber19851 │
│          7642020-03-01 00:01:04.66502020-03-01 00:13:49.030083Atlantic Ave & Fort Greene Pl40.683826-73.9763233579Sterling Pl & Bedford Ave  40.672695-73.95413131216Subscriber19802 │
│         17192020-03-01 00:01:04.92502020-03-01 00:29:44.01403809W 55 St & 6 Ave              40.763189-73.9784343372E 74 St & 1 Ave            40.768974-73.95482327715Subscriber19682 │
│          4412020-03-01 00:01:09.30502020-03-01 00:08:30.86703463E 16 St & Irving Pl          40.735367-73.987974174E 25 St & 1 Ave            40.738177-73.97738742015Subscriber19701 │
│          6012020-03-01 00:01:09.44202020-03-01 00:11:11.2240406Hicks St & Montague St       40.695128-73.995951421Clermont Ave & Park Ave    40.695734-73.97129727592Subscriber19851 │
│             │
└──────────────┴──────────────────────────┴──────────────────────────┴──────────────────┴───────────────────────────────┴────────────────────────┴─────────────────────────┴────────────────┴─────────────────────────────┴──────────────────────┴───────────────────────┴────────┴────────────┴────────────┴────────┘

We have the information about the longitude and latitude for start and end stations, to create geometry points and put the spatial features to use.

Create bike trip table

In the original tutorial, Spatial Dev Guru creates a table with transformed “Pickup” and “Dropoff” points. In DuckDB the st_transform function takes by default points as YX (latitude/longitude) while in Ibis, we assume data in the form XY (longitude/latitude) to be consistent with PostGIS and Geopandas.

# Notice longitude/latitude order
pickup = _.start_station_longitude.point(_.start_station_latitude)
dropoff = _.end_station_longitude.point(_.end_station_latitude)

# convert is the equivalent of `st_transform`
biketrip = biketrip.mutate(
    pickup_point=pickup.convert("EPSG:4326", "EPSG:3857"),
    dropoff_point=dropoff.convert("EPSG:4326", "EPSG:3857"),
)

biketrip[["pickup_point", "dropoff_point"]]
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ pickup_point                        dropoff_point                      ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ geospatial:geometrygeospatial:geometry                │
├────────────────────────────────────┼────────────────────────────────────┤
│ <POINT (-8238257.278 4969875.321)><POINT (-8233834.079 4964810.852)> │
│ <POINT (-8236643.369 4972628.277)><POINT (-8237636.375 4973746.028)> │
│ <POINT (-8236707.235 4975412.341)><POINT (-8237043.245 4977019.779)> │
│ <POINT (-8237746.848 4973467.317)><POINT (-8235943.322 4973515.398)> │
│ <POINT (-8236210.701 4972365.622)><POINT (-8232578.395 4975141.09)>  │
│ <POINT (-8232853.487 4970081.63)><POINT (-8236539.472 4973633.6)>   │
│ <POINT (-8235006.638 4965817.34)><POINT (-8232536.205 4964183.464)> │
│ <POINT (-8235241.603 4977474.595)><POINT (-8232613.208 4978324.842)> │
│ <POINT (-8236303.583 4973386.377)><POINT (-8235125.009 4973799.125)> │
│ <POINT (-8237191.547 4967476.65)><POINT (-8234447.08 4967565.556)>  │
│                                   │
└────────────────────────────────────┴────────────────────────────────────┘

Using mutate we add two new columns to our biketrip table with transformed spatial points for pickup and dropoff locations, that are in the Web Mercator projection (EPSG:3857).

Explore trip patterns by user type

We can also calculate the average trip duration and distance traveled for each user type. According to the data dictionary, user type can be “customer” or “subscriber” where:

  • Customer = 24-hour pass or 3-day pass user
  • Subscriber = Annual Member
biketrip.group_by(_.usertype).aggregate(
    avg_duration=_.tripduration.mean(),
    avg_distance=_.pickup_point.distance(_.dropoff_point).mean()
)
┏━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ usertype    avg_duration  avg_distance ┃
┡━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ stringfloat64float64      │
├────────────┼──────────────┼──────────────┤
│ Customer  2619.6277973017.728172 │
│ Subscriber914.4377742457.477582 │
└────────────┴──────────────┴──────────────┘

Analyzing efficiency: trip duration vs linear distance

The original tutorial defines efficiency_ratio as the trip_duration / linear_distance, where a higher efficiency ratio could mean a more direct route or faster travel times.

# linear distance
trip_distance = biketrip.pickup_point.distance(biketrip.dropoff_point)

biketrip = biketrip.mutate(
    linear_distance=trip_distance,
    efficiency_ratio=_.tripduration / trip_distance,
)

biketrip[["pickup_point", "dropoff_point", "linear_distance", "efficiency_ratio"]]
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓
┃ pickup_point                        dropoff_point                       linear_distance  efficiency_ratio ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩
│ geospatial:geometrygeospatial:geometryfloat64float64          │
├────────────────────────────────────┼────────────────────────────────────┼─────────────────┼──────────────────┤
│ <POINT (-8238257.278 4969875.321)><POINT (-8233834.079 4964810.852)>6724.1010990.236314 │
│ <POINT (-8236643.369 4972628.277)><POINT (-8237636.375 4973746.028)>1495.1351180.260177 │
│ <POINT (-8236707.235 4975412.341)><POINT (-8237043.245 4977019.779)>1642.1810580.373893 │
│ <POINT (-8237746.848 4973467.317)><POINT (-8235943.322 4973515.398)>1804.1668040.330901 │
│ <POINT (-8236210.701 4972365.622)><POINT (-8232578.395 4975141.09)>4571.3093820.420011 │
│ <POINT (-8232853.487 4970081.63)><POINT (-8236539.472 4973633.6)>5118.8845690.401455 │
│ <POINT (-8235006.638 4965817.34)><POINT (-8232536.205 4964183.464)>2961.8561250.257946 │
│ <POINT (-8235241.603 4977474.595)><POINT (-8232613.208 4978324.842)>2762.4946380.622264 │
│ <POINT (-8236303.583 4973386.377)><POINT (-8235125.009 4973799.125)>1248.7583420.353151 │
│ <POINT (-8237191.547 4967476.65)><POINT (-8234447.08 4967565.556)>2745.9070460.218871 │
│  │
└────────────────────────────────────┴────────────────────────────────────┴─────────────────┴──────────────────┘

Let’s take take a look at the table in descending order for the linear_distance, for trips that are longer than 0 meters.

biketrip.filter(_.linear_distance > 0).order_by(ibis.desc("linear_distance"))
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓
┃ tripduration  starttime                 stoptime                  start_station_id  start_station_name                  start_station_latitude  start_station_longitude  end_station_id  end_station_name                     end_station_latitude  end_station_longitude  bikeid  usertype    birth_year  gender  pickup_point                        dropoff_point                       linear_distance  efficiency_ratio ┃
┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩
│ int64stringstringint64stringfloat64float64int64stringfloat64float64int64stringint64int64geospatial:geometrygeospatial:geometryfloat64float64          │
├──────────────┼──────────────────────────┼──────────────────────────┼──────────────────┼────────────────────────────────────┼────────────────────────┼─────────────────────────┼────────────────┼─────────────────────────────────────┼──────────────────────┼───────────────────────┼────────┼────────────┼────────────┼────────┼────────────────────────────────────┼────────────────────────────────────┼─────────────────┼──────────────────┤
│         76602020-03-20 19:12:59.02102020-03-20 21:20:39.506034034 Ave & 9 St                      40.670513-73.988766388112 Ave & W 125 St                  40.818299-73.96040530277Customer  19682<POINT (-8236391.739 4963863.283)><POINT (-8233234.623 4985577.637)>21942.6649210.349092 │
│         95362020-03-07 07:16:42.81002020-03-07 09:55:39.16303545Broadway & W 122 St               40.812056-73.9612553661Montgomery St & Franklin Ave       40.666439-73.96055633590Customer  19982<POINT (-8233329.212 4984659.395)><POINT (-8233251.476 4963265.338)>21394.1986530.445728 │
│         95412020-03-07 07:16:42.97302020-03-07 09:55:44.76803545Broadway & W 122 St               40.812056-73.9612553661Montgomery St & Franklin Ave       40.666439-73.96055630524Customer  20002<POINT (-8233329.212 4984659.395)><POINT (-8233251.476 4963265.338)>21394.1986530.445962 │
│         65572020-03-18 12:43:05.55102020-03-18 14:32:22.56703543Morningside Dr & Amsterdam Ave    40.810285-73.957365331710 St & 5 Ave                      40.668627-73.98700136139Subscriber19941<POINT (-8232896.163 4984398.898)><POINT (-8236195.224 4963586.452)>21072.2971580.311167 │
│         53612020-03-27 15:32:39.06502020-03-27 17:02:00.8680388112 Ave & W 125 St                 40.818299-73.9604053384Smith St & 3 St                    40.678724-73.99599127737Customer  19822<POINT (-8233234.623 4985577.637)><POINT (-8237196.038 4965068.429)>20888.2836610.256651 │
│         91642020-03-07 07:23:19.92502020-03-07 09:56:04.23703536W 116 St & Broadway               40.808200-73.9641003661Montgomery St & Franklin Ave       40.666439-73.96055638264Customer  19982<POINT (-8233645.949 4984092.238)><POINT (-8233251.476 4963265.338)>20830.6349480.439929 │
│         88982020-03-07 07:27:08.57002020-03-07 09:55:27.51903536W 116 St & Broadway               40.808200-73.9641003661Montgomery St & Franklin Ave       40.666439-73.96055621194Customer  19992<POINT (-8233645.949 4984092.238)><POINT (-8233251.476 4963265.338)>20830.6349480.427159 │
│         55042020-03-10 20:45:55.01202020-03-10 22:17:39.229034055 St & 6 Ave                      40.670484-73.9820903629Adam Clayton Powell Blvd & W 126 St40.809495-73.94776537653Customer  19792<POINT (-8235648.551 4963858.895)><POINT (-8231827.538 4984282.75)>20778.2095760.264893 │
│         59152020-03-10 15:59:38.51302020-03-10 17:38:13.87203534Frederick Douglass Blvd & W 117 St40.805159-73.9546923596Sullivan Pl & Bedford Ave          40.664241-73.95746937257Customer  19690<POINT (-8232598.655 4983645)><POINT (-8232907.745 4962942.662)>20704.6450890.285685 │
│         47552020-03-24 07:41:42.14402020-03-24 09:00:58.08203349Grand Army Plaza & Plaza St West  40.672968-73.9708803529Lenox Ave & W 130 St               40.810792-73.94306836100Subscriber19652<POINT (-8234400.677 4964223.518)><POINT (-8231304.689 4984473.487)>20485.2718590.232118 │
│             │
└──────────────┴──────────────────────────┴──────────────────────────┴──────────────────┴────────────────────────────────────┴────────────────────────┴─────────────────────────┴────────────────┴─────────────────────────────────────┴──────────────────────┴───────────────────────┴────────┴────────────┴────────────┴────────┴────────────────────────────────────┴────────────────────────────────────┴─────────────────┴──────────────────┘

Analyzing bike trips within a 500 meters radius

In the original tutorial, the author choses a point (first point on the table), and it creates a buffer of 500 m radius around it. In our table we already have the point in meters, since we converted them in a previous query.

The following query shows all the bike trips whose pickup point falls within a 500 meter radius of the first point of the table with long=-74.00552427 and lat=40.71146364.

# grab the first row of the data
first_point = biketrip.limit(1)

trips_within_500 = biketrip.filter(
    _.pickup_point.within(first_point.select(_.pickup_point.buffer(500)).to_array())
)

trips_within_500
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓
┃ tripduration  starttime                 stoptime                  start_station_id  start_station_name     start_station_latitude  start_station_longitude  end_station_id  end_station_name             end_station_latitude  end_station_longitude  bikeid  usertype    birth_year  gender  pickup_point                        dropoff_point                       linear_distance  efficiency_ratio ┃
┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩
│ int64stringstringint64stringfloat64float64int64stringfloat64float64int64stringint64int64geospatial:geometrygeospatial:geometryfloat64float64          │
├──────────────┼──────────────────────────┼──────────────────────────┼──────────────────┼───────────────────────┼────────────────────────┼─────────────────────────┼────────────────┼─────────────────────────────┼──────────────────────┼───────────────────────┼────────┼────────────┼────────────┼────────┼────────────────────────────────────┼────────────────────────────────────┼─────────────────┼──────────────────┤
│         15892020-03-01 00:00:03.64002020-03-01 00:26:32.9860224Spruce St & Nassau St40.711464-74.0055243574Prospect Pl & Underhill Ave40.676969-73.96579016214Subscriber19801<POINT (-8238257.278 4969875.321)><POINT (-8233834.079 4964810.852)>6724.1010990.236314 │
│         18132020-03-01 00:09:02.62602020-03-01 00:39:16.49503783Cliff St & Fulton St 40.708380-74.004950410Suffolk St & Stanton St    40.720664-73.98518041200Subscriber19951<POINT (-8238193.35 4969422.472)><POINT (-8235992.538 4971226.629)>2845.7963500.637080 │
│          4632020-03-01 00:24:52.78702020-03-01 00:32:36.6160330Reade St & Broadway  40.714505-74.005628311Norfolk St & Broome St     40.717227-73.98802127788Subscriber19991<POINT (-8238268.813 4970321.91)><POINT (-8236308.805 4970721.816)>2000.3889750.231455 │
│          4542020-03-01 00:25:06.95902020-03-01 00:32:41.9440330Reade St & Broadway  40.714505-74.005628311Norfolk St & Broome St     40.717227-73.98802134083Subscriber19681<POINT (-8238268.813 4970321.91)><POINT (-8236308.805 4970721.816)>2000.3889750.226956 │
│          4922020-03-01 00:40:27.30602020-03-01 00:48:40.2190330Reade St & Broadway  40.714505-74.005628309Murray St & West St        40.714979-74.01301237858Subscriber19751<POINT (-8238268.813 4970321.91)><POINT (-8239090.808 4970391.552)>824.9402650.596407 │
│         20202020-03-01 01:14:59.03002020-03-01 01:48:39.4420224Spruce St & Nassau St40.711464-74.005524236St Marks Pl & 2 Ave        40.728419-73.98714036388Subscriber19862<POINT (-8238257.278 4969875.321)><POINT (-8236210.701 4972365.622)>3223.3640130.626674 │
│          7942020-03-01 01:15:33.04602020-03-01 01:28:47.6180376John St & William St 40.708621-74.00722237466 Ave & Broome St          40.724308-74.00473037334Subscriber19981<POINT (-8238446.219 4969457.928)><POINT (-8238168.9 4971761.857)>2320.5589100.342159 │
│          8162020-03-01 01:16:07.44302020-03-01 01:29:43.7260376John St & William St 40.708621-74.00722237466 Ave & Broome St          40.724308-74.00473018888Customer  19690<POINT (-8238446.219 4969457.928)><POINT (-8238168.9 4971761.857)>2320.5589100.351639 │
│          2382020-03-01 01:28:46.24602020-03-01 01:32:44.7130376John St & William St 40.708621-74.007222415Pearl St & Hanover Square  40.704718-74.00926029327Subscriber19601<POINT (-8238446.219 4969457.928)><POINT (-8238673.167 4968884.671)>616.5461320.386021 │
│          1202020-03-01 01:33:37.79202020-03-01 01:35:38.2580330Reade St & Broadway  40.714505-74.005628146Hudson St & Reade St       40.716250-74.00910628153Subscriber19881<POINT (-8238268.813 4970321.91)><POINT (-8238655.983 4970578.277)>464.3544180.258423 │
│             │
└──────────────┴──────────────────────────┴──────────────────────────┴──────────────────┴───────────────────────┴────────────────────────┴─────────────────────────┴────────────────┴─────────────────────────────┴──────────────────────┴───────────────────────┴────────┴────────────┴────────────┴────────┴────────────────────────────────────┴────────────────────────────────────┴─────────────────┴──────────────────┘

Acknowledgements and resources

Thank you to Spatial Dev Guru, for the amazing tutorial showcasing DuckDB spatial features. It was fun to replicate the tutorial using Ibis.

If you are interested in learning more about Ibis-DuckDB geospatial support, here is another blog post bis + DuckDB geospatial: a match made on Earth.

Here are some resources to learn more about Ibis:

Chat with us on Zulip:

Back to top