A small lonboard map driven by
manywidgets.lonboard controls — a LayerToggle, a FilterBinder
(RangeSlider → filter_range), and a LayerFilter (category checkboxes) —
laid out beside the map with Column. Works live and in static export (no
kernel); the carto basemap tiles load from the network when you view the page.
import geopandas as gpd
import numpy as np
from shapely.geometry import Point
from lonboard import Map, ScatterplotLayer, BitmapTileLayer
from lonboard.layer_extension import DataFilterExtension
from manywidgets import RangeSlider, Column, Legend
from manywidgets.lonboard import LayerToggle, FilterBinder, LayerFiltern = 6
vals = np.arange(n, dtype="float64")
cats = np.array([0, 1, 2, 0, 1, 2], dtype="uint8")
pts = [Point(-122.42 + 0.01 * i, 37.77 + 0.01 * i) for i in range(n)]
gdf = gpd.GeoDataFrame(geometry=pts, crs="EPSG:4326") # accessors passed as arrays below
layer = ScatterplotLayer.from_geopandas(
gdf,
get_radius=300,
radius_units="meters",
get_fill_color=[200, 30, 30],
extensions=[DataFilterExtension(filter_size=1, category_size=1)],
get_filter_value=vals,
filter_range=(0, 5),
get_filter_category=cats,
filter_categories=[0, 1, 2],
)
# Default carto basemap (tiles fetched from the network at view time). Pass
# basemap=None for a fully-offline page.
m = Map(layer, view_state={"longitude": -122.4, "latitude": 37.8, "zoom": 11})Controls beside the map¶
Toggle visibility, filter by value range, and filter by category.
toggle = LayerToggle(layer, label="Points", value=True)
rng = RangeSlider(label="Value range", min=0, max=5, low=0, high=5, step=1)
fb = FilterBinder(rng, layer) # rng.low/high -> layer.filter_range
cat_filter = LayerFilter(layer, categories=[[0, "A"], [1, "B"], [2, "C"]], label="Category")
Column(toggle, rng, fb, cat_filter, m, gap="10px")Data-driven styling + legend¶
Colour the points by a data attribute (here, category) with a per-row
get_fill_color array, and show a matching Legend built from the same
palette so the map and legend stay consistent.
palette = np.array([[230, 30, 30], [30, 160, 30], [30, 90, 230]], dtype="uint8")
labels = ["A", "B", "C"]
styled = ScatterplotLayer.from_geopandas(
gdf,
get_radius=400,
radius_units="meters",
get_fill_color=palette[cats], # data-driven: one colour per row, by category
)
styled_map = Map(styled, view_state={"longitude": -122.4, "latitude": 37.8, "zoom": 11})
legend = Legend(
[[palette[i].tolist(), labels[i]] for i in range(len(labels))],
title="Category",
)
Column(legend, styled_map, gap="10px")Raster layer switcher¶
A Map can hold several raster (BitmapTileLayer) layers; a LayerToggle per
layer makes a layer switcher — just stack the toggles in a Column. Each toggle
writes its layer’s visible, so this works live and in static export (the raster
tiles load from the network when viewed).
osm = BitmapTileLayer(
data="https://tile.openstreetmap.org/{z}/{x}/{y}.png",
tile_size=256, max_zoom=19, visible=True,
)
topo = BitmapTileLayer(
data="https://a.tile.opentopomap.org/{z}/{x}/{y}.png",
tile_size=256, max_zoom=17, opacity=0.7, visible=False,
)
raster_map = Map(
[osm, topo],
basemap=None, # the raster layers are the imagery
view_state={"longitude": -122.4, "latitude": 37.8, "zoom": 10},
)
switcher = Column(
LayerToggle(osm, label="OpenStreetMap", value=True),
LayerToggle(topo, label="OpenTopoMap", value=False),
gap="4px",
)
Column(switcher, raster_map, gap="10px")Fly to presets¶
MapFlyer repositions an already-rendered map from the browser — no kernel, so it works in this statically-exported page. Click a button to fly.
from manywidgets.lonboard import MapFlyer
fly_layer = ScatterplotLayer.from_geopandas(
gdf, get_radius=300, radius_units="meters", get_fill_color=[30, 90, 230]
)
fly_map = Map(fly_layer, view_state={"longitude": -122.4, "latitude": 37.8, "zoom": 11})
flyer = MapFlyer(fly_map, locations=[
{"label": "San Francisco", "longitude": -122.42, "latitude": 37.77, "zoom": 12},
{"label": "New York", "longitude": -74.0, "latitude": 40.70, "zoom": 11},
{"label": "London", "longitude": -0.12, "latitude": 51.50, "zoom": 10},
], duration=3000)
Column(flyer, fly_map, gap="10px")