Skip to content
2 changes: 0 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
- feat: Suppress JupyterLab context menu on Map right click by @kylebarron in https://github.com/developmentseed/lonboard/pull/889
- feat: Support two render modes: Standard/deck.gl-first and MapboxOverlay by @kylebarron in https://github.com/developmentseed/lonboard/pull/921
- feat: Create richer `Basemap` class and deprecate `basemap_style` arg by @kylebarron in https://github.com/developmentseed/lonboard/pull/935
- feat: Support globe view by @kylebarron in https://github.com/developmentseed/lonboard/pull/908
- feat: Move `TripsLayer` and `ArcLayer` out of experimental by @kylebarron in https://github.com/developmentseed/lonboard/pull/983
- feat: Support for map controls by @kylebarron in https://github.com/developmentseed/lonboard/pull/924
- feat: Provide default controls for Map by @kylebarron in https://github.com/developmentseed/lonboard/pull/992
Expand All @@ -16,7 +15,6 @@
- feat: Add A5Layer by @kylebarron in https://github.com/developmentseed/lonboard/pull/1001
- feat: Add geohash and s2 layers by @kylebarron in https://github.com/developmentseed/lonboard/pull/1007
- feat: Implement view state validation for non map-view states by @kylebarron in https://github.com/developmentseed/lonboard/pull/1008
- feat: Validate that GlobeView is only used with interleaved basemap mode by @kylebarron in https://github.com/developmentseed/lonboard/pull/1012
- feat: Add view parameter to viz by @kylebarron in https://github.com/developmentseed/lonboard/pull/1013

### Performance improvements :zap:
Expand Down
Binary file added assets/controls-example.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/interleaved-labels.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/blog/.authors.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
authors:
kylebarron:
name: Kyle Barron
description: Creator
avatar: https://github.com/kylebarron.png
Empty file added docs/blog/index.md
Empty file.
94 changes: 94 additions & 0 deletions docs/blog/posts/lonboard-0.13.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
draft: false
date: 2025-11-05
categories:
- Release
authors:
- kylebarron
links:
- CHANGELOG.md
---

# Releasing lonboard 0.13!

Lonboard is a Python library for fast, interactive geospatial vector data visualization in Jupyter.

This post gives an overview of what's new in Lonboard version 0.13.

<!-- more -->

Refer to the [changelog] for all updates.

## New layer types: H3, S2, Geohash, A5

Lonboard supports new layer types for [H3][h3], [S2][s2], [Geohash][geohash], and [A5][a5] data.

[h3]: https://h3geo.org/
[a5]: https://a5geo.org/
[s2]: http://s2geometry.io/
[geohash]: https://en.wikipedia.org/wiki/Geohash

- [`H3HexagonLayer`][lonboard.H3HexagonLayer]: render hexagons from the [H3][h3] geospatial indexing system
- [`S2Layer`][lonboard.S2Layer]: render polygons based on the [S2][s2] geospatial indexing system.
- [`A5Layer`][lonboard.A5Layer]: render polygons based on the [A5][a5] geospatial indexing system.
- [`GeohashLayer`][lonboard.GeohashLayer]: render polygons based on the [Geohash][geohash] geospatial indexing system.

![](../../assets/kontur-h3.jpg)

> Screenshot from [H3 Population](../../../../../examples/kontur_pop) example

Additionally, the [HeatmapLayer][lonboard.HeatmapLayer], which has been broken since Lonboard v0.10 due to upstream changes in deck.gl, has been fixed and is now functional again. (Thanks to @felixpalmer for [fixing this upstream](https://github.com/visgl/deck.gl/pull/9787)!).

## Interleaved rendering with Maplibre

When rendering dense visualizations, the data can obscure helpful elements of the basemap, removing spatial context from the visualization.

It's now possible to render Lonboard data layers interleaved in the Maplibre layer stack. This means Maplibre text labels can be rendered above your Lonboard-rendered data.

![](../../assets/interleaved-labels.jpg)

> Screenshot from [H3 Population](../../../../../examples/interleaved-labels) example

To do this:

- Set [`before_id`](../../../../../api/layers/base-layer#lonboard.BaseLayer.before_id) on your layer as the value of the Maplibre layer `id` you want the Lonboard layer to be under. See [`before_id`](../../../../../api/layers/base-layer#lonboard.BaseLayer.before_id) for more information.
- Create a new basemap [set to `interleaved` mode][lonboard.basemap.MaplibreBasemap.mode]:
- Pass the basemap to the `Map` constructor.

```py
from lonboard.basemap import MaplibreBasemap
from lonboard import Map, ScatterplotLayer

# Example layer ID when using Carto basemap styles
layer = ScatterplotLayer(..., before_id="watername_ocean")
basemap = MaplibreBasemap(mode="interleaved")
m = Map(layer, basemap=basemap)
```

## Map controls: scale, fullscreen, navigation

Common UI elements that we call "Controls" are now supported in Lonboard maps. In this release, this includes three types of controls:

- Scale control: shows a scale bar on the map
- Fullscreen control: button to toggle fullscreen mode
- Navigation control: zoom in/out buttons and a compass

These three controls are rendered on the map by default, but can be customized via the [`Map.controls`][lonboard.Map.controls] attribute. See [`lonboard.controls`][] for more information.

![](../../assets/controls-example.jpg)

## Performance improvements

First and foremost, I learned there was _severe bug_ in which the string representation (aka `repr`) of the [`table` attribute][lonboard.BaseArrowLayer.table] was being generated during map display. In conjunction with [an upstream issue](https://github.com/kylebarron/arro3/issues/432), this made it _very slow_ to render a map for datasets with many coordinates in a single row (such as polygons representing administrative boundaries). https://github.com/developmentseed/lonboard/pull/1015 **improved the Python-side of rendering by 99% in this case**, from 12 seconds to 5 milliseconds.

In https://github.com/developmentseed/lonboard/pull/902 we now fully parallelize the Parquet file generation in a thread pool on the Python side, leading to 4x faster Parquet serialization.

In https://github.com/developmentseed/lonboard/pull/954 we improve the Polygon rendering performance on the JavaScript side and remove a network request for a dependency needed to perform multi-threaded preparation for Polygon data rendering.

In general, Lonboard data rendering should feel instantaneous. If it's especially slow, on the order of ~10 seconds, [open an issue](https://github.com/developmentseed/lonboard/issues/new/choose) with your dataset to discuss.

## All updates

Refer to the [changelog] for all updates.

[changelog]: ../../CHANGELOG.md/#0130-2025-11-05
39 changes: 20 additions & 19 deletions examples/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@

<div class="grid cards" markdown>

- [Speedtest data ![](../assets/scatterplot-layer-network-speeds.jpg)](../examples/internet-speeds) using [`ScatterplotLayer`](../api/layers/scatterplot-layer)
- [North America roads ![](../assets/path-layer-roads.jpg)](../examples/north-america-roads) using [`PathLayer`](../api/layers/path-layer)
- [Spatially-Partitioned GeoParquet ![](../assets/spatially-partitioned-geoparquet.jpg)](../examples/overture-geoparquet) using [`PolygonLayer`](../api/layers/polygon-layer)
- [Overture Maps buildings ![](../assets/overture.jpg)](../examples/overture-maps) using [`PolygonLayer`](../api/layers/polygon-layer)
- [Air Traffic Control animation ![](../assets/air-traffic-control.gif)](../examples/air-traffic-control) using [`TripsLayer`](../api/layers/trips-layer)
- [Global boundaries ![](../assets/boundaries.png)](../examples/global-boundaries) using [`PolygonLayer`](../api/layers/polygon-layer)
- [H3 Population Data ![](../assets/kontur-h3.jpg)](../examples/kontur_pop) using [`H3HexagonLayer`](../api/layers/h3-hexagon-layer)
- [U.S. County-to-County Migration ![](../assets/arc-layer-migration-example.gif)](../examples/migration) using [`ArcLayer`](../api/layers/arc-layer) and [`BrushingExtension`](../api/layer-extensions/brushing-extension)
- [Scatterplot with GPU data filtering ![](../assets/data-filter-extension.gif)](../examples/data-filter-extension) using [`ScatterplotLayer`](../api/layers/scatterplot-layer) and [`DataFilterExtension`](../api/layer-extensions/data-filter-extension)
- [Motor Vehicle Crashes in NYC ![](../assets/motor-vehicle-crashes-nyc.jpg)](../examples/map_challenge/1-points) using [`ScatterplotLayer`](../api/layers/scatterplot-layer)
- [Rivers in Asia ![](../assets/rivers-asia.jpg)](../examples/map_challenge/6-asia/) using [`PathLayer`](../api/layers/path-layer)
- [Inflation Reduction Act Projects ![](../assets/column-layer.jpg)](../examples/column-layer/) using [`ColumnLayer`](../api/layers/column-layer)
- [Speedtest data ![](../assets/scatterplot-layer-network-speeds.jpg)](../examples/internet-speeds) using [`ScatterplotLayer`][lonboard.ScatterplotLayer]
- [North America roads ![](../assets/path-layer-roads.jpg)](../examples/north-america-roads) using [`PathLayer`][lonboard.PathLayer]
- [Spatially-Partitioned GeoParquet ![](../assets/spatially-partitioned-geoparquet.jpg)](../examples/overture-geoparquet) using [`PolygonLayer`][lonboard.PolygonLayer]
- [Overture Maps buildings ![](../assets/overture.jpg)](../examples/overture-maps) using [`PolygonLayer`][lonboard.PolygonLayer]
- [Air Traffic Control animation ![](../assets/air-traffic-control.gif)](../examples/air-traffic-control) using [`TripsLayer`][lonboard.TripsLayer]
- [Global boundaries ![](../assets/boundaries.png)](../examples/global-boundaries) using [`PolygonLayer`][lonboard.PolygonLayer]
- [H3 Population Data ![](../assets/kontur-h3.jpg)](../examples/kontur_pop) using [`H3HexagonLayer`][lonboard.H3HexagonLayer]
- [U.S. County-to-County Migration ![](../assets/arc-layer-migration-example.gif)](../examples/migration) using [`ArcLayer`][lonboard.ArcLayer] and [`BrushingExtension`][lonboard.layer_extension.BrushingExtension]
- [Scatterplot with GPU data filtering ![](../assets/data-filter-extension.gif)](../examples/data-filter-extension) using [`ScatterplotLayer`][lonboard.ScatterplotLayer] and [`DataFilterExtension`][lonboard.layer_extension.DataFilterExtension]
- [Motor Vehicle Crashes in NYC ![](../assets/motor-vehicle-crashes-nyc.jpg)](../examples/map_challenge/1-points) using [`ScatterplotLayer`][lonboard.ScatterplotLayer]
- [Rivers in Asia ![](../assets/rivers-asia.jpg)](../examples/map_challenge/6-asia/) using [`PathLayer`][lonboard.PathLayer]
- [Inflation Reduction Act Projects ![](../assets/column-layer.jpg)](../examples/column-layer/) using [`ColumnLayer`][lonboard.ColumnLayer]
- [Interleaved Maplibre Labels ![](../assets/interleaved-labels.jpg)](../examples/interleaved-labels/) using [`BitmapLayer`][lonboard.BitmapLayer] and [`MaplibreBasemap`][lonboard.basemap.MaplibreBasemap]
- [Linked Maps ![](../assets/linked-maps.gif)](../examples/linked-maps/)
- [Clicked Point ![](../assets/clicked-point.png)](../examples/clicked-point/)
</div>
Expand All @@ -26,11 +27,11 @@
<video controls autoplay loop>
<source src="https://github.com/user-attachments/assets/77f6a2b3-80c9-4524-8be2-79152746da1d" type="video/mp4">
</video>
](../examples/marimo/nyc_taxi_trips/) using [`ArcLayer`](../api/layers/arc-layer) & [GeoDataFusion](https://github.com/datafusion-contrib/datafusion-geo)
- [DuckDB Spatial ![](../assets/duckdb-heatmap.jpg)](../examples/duckdb) using [`HeatmapLayer`](../api/layers/heatmap-layer)
- [Color picker integration ![](../assets/color-picker.jpg)](../examples/integrations/color-picker) using [`SolidPolygonLayer`](../api/layers/solid-polygon-layer)
- [JupyterLab Sidecar integration ![](../assets/jupyter-sidecar.jpg)](../examples/integrations/sidecar/) using [`ScatterplotLayer`](../api/layers/scatterplot-layer) and [`JupyterLab Sidecar`](https://github.com/jupyter-widgets/jupyterlab-sidecar)
- [MovingPandas ![](../assets/ais-movingpandas.gif)](../examples/ais-movingpandas) using [`TripsLayer`](../api/layers/trips-layer)
](../examples/marimo/nyc_taxi_trips/) using [`ArcLayer`][lonboard.ArcLayer] & [GeoDataFusion](https://github.com/datafusion-contrib/datafusion-geo)
- [DuckDB Spatial ![](../assets/duckdb-heatmap.jpg)](../examples/duckdb) using [`HeatmapLayer`][lonboard.HeatmapLayer]
- [Color picker integration ![](../assets/color-picker.jpg)](../examples/integrations/color-picker) using [`SolidPolygonLayer`][lonboard.SolidPolygonLayer]
- [JupyterLab Sidecar integration ![](../assets/jupyter-sidecar.jpg)](../examples/integrations/sidecar/) using [`ScatterplotLayer`][lonboard.ScatterplotLayer] and [`JupyterLab Sidecar`](https://github.com/jupyter-widgets/jupyterlab-sidecar)
- [MovingPandas ![](../assets/ais-movingpandas.gif)](../examples/ais-movingpandas) using [`TripsLayer`][lonboard.TripsLayer]


</div>
Expand All @@ -41,8 +42,8 @@ These examples are maintained by external contributors.

<div class="grid cards" markdown>

- [Using Lonboard to visualize graph flows ![](../assets/longraph.jpg)](https://knaaptime.com/longraph/) using [`ArcLayer`](../api/layers/arc-layer), [`PolygonLayer`](../api/layers/polygon-layer), and [`BrushingExtension`](../api/layer-extensions/brushing-extension) by [@knaaptime](https://github.com/knaaptime).
- [American Community Survey exploration](https://github.com/jaanli/lonboard/blob/1af815ea586121dbbe0d8cae70f7814a642ad165/examples/american-community-survey.ipynb) using [`ScatterplotLayer`](../api/layers/scatterplot-layer) and [`DataFilterExtension`](../api/layer-extensions/data-filter-extension) by [@jaanli](https://github.com/jaanli).
- [Using Lonboard to visualize graph flows ![](../assets/longraph.jpg)](https://knaaptime.com/longraph/) using [`ArcLayer`][lonboard.ArcLayer], [`PolygonLayer`][lonboard.PolygonLayer], and [`BrushingExtension`][lonboard.layer_extension.BrushingExtension] by [@knaaptime](https://github.com/knaaptime).
- [American Community Survey exploration](https://github.com/jaanli/lonboard/blob/1af815ea586121dbbe0d8cae70f7814a642ad165/examples/american-community-survey.ipynb) using [`ScatterplotLayer`][lonboard.ScatterplotLayer] and [`DataFilterExtension`][lonboard.layer_extension.DataFilterExtension] by [@jaanli](https://github.com/jaanli).

</div>

Expand Down
131 changes: 131 additions & 0 deletions examples/interleaved-labels.ipynb

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion lonboard/layer/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ def _add_extension_traits(self, extensions: Sequence[BaseExtension]) -> None:
So if you pass `before_id="background"`, you won't see your deck.gl layer because it
will be rendered below **all** layers in the Maplibre basemap.

A common choice for Carto-based styles is to use `before_id="waterway-label"` so
A common choice for Carto-based styles is to use `before_id="watername_ocean"` so
that your deck.gl layer is rendered above the core basemap elements but below all
text labels.

Expand Down Expand Up @@ -326,6 +326,12 @@ class BaseArrowLayer(BaseLayer):
# The following traitlets **are** serialized to JS

table: ArrowTableTrait
"""An Arrow table with data for this layer.

Some downstream layers will require this table to have a geospatial column. Other
layers, such as the [`H3HexagonLayer`][lonboard.layer.H3HexagonLayer] will accept
non-geospatial data in conjunction with other accessors.
"""

def _repr_keys(self) -> Generator[str, Any, None]:
# Avoid rendering `table` in the string repr
Expand Down
13 changes: 11 additions & 2 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ nav:
- examples/overture-geoparquet.ipynb
- examples/air-traffic-control.ipynb
- examples/global-boundaries.ipynb
- examples/kontur_pop.ipynb
- examples/migration.ipynb
- examples/data-filter-extension.ipynb
- examples/column-layer.ipynb
- examples/interleaved-labels.ipynb
- examples/linked-maps.ipynb
- examples/clicked-point.ipynb
- NYC Taxi Trips: examples/marimo/nyc_taxi_trips.md
- Integrations:
- examples/duckdb.ipynb
Expand All @@ -57,6 +60,8 @@ nav:
- 30 Day Map Challenge:
- "Day 1: Points": examples/map_challenge/1-points.ipynb
- "Day 6: Asia": examples/map_challenge/6-asia.ipynb
- Blog:
- blog/index.md
- API Reference:
- api/viz.md
- api/map.md
Expand Down Expand Up @@ -146,8 +151,6 @@ theme:
text: Roboto
code: Roboto Mono

# logo: img/geopolars_logo.svg

features:
- content.code.annotate
- content.code.copy
Expand All @@ -158,6 +161,9 @@ theme:
- search.share

plugins:
- autorefs:
resolve_closest: true
- blog
- search
- social
- mike:
Expand Down Expand Up @@ -241,6 +247,9 @@ markdown_extensions:
- pymdownx.magiclink:
hide_protocol: true
repo_url_shortener: true
repo_url_shorthand: true
repo: lonboard
user: developmentseed
- pymdownx.smartsymbols
- pymdownx.superfences
- pymdownx.tasklist:
Expand Down