A CounterWidget drives a lonboard ScatterplotLayer’s point radius via a WidgetBinder. All wiring is JS-only — no kernel running on the static page. Click the counter’s + / - and watch the dots grow / shrink.
Why radius rather than view zoom: lonboard’s Map uses deck.gl’s initialViewState (uncontrolled) so external view_state changes don’t propagate to the rendered map. Layer-level props like get_radius re-render correctly because the layer model fires change:* events that lonboard’s React layer hook subscribes to.
import sys
import pathlib
sys.path.insert(0, str(pathlib.Path().absolute().parent))
import geopandas as gpd
from shapely.geometry import Point
from lonboard import Map, ScatterplotLayer
from widgets.counter_widget import CounterWidget
from widgets.widget_binder import WidgetBinder
from IPython.display import display1. The map¶
Five points around San Francisco. Default zoom 12; we’ll override that from the counter.
points = [
Point(-122.4194, 37.7749),
Point(-122.4313, 37.7849),
Point(-122.4094, 37.7649),
Point(-122.4214, 37.7949),
Point(-122.4394, 37.7549),
]
gdf = gpd.GeoDataFrame({'geometry': points}, crs='EPSG:4326')
layer = ScatterplotLayer.from_geopandas(
gdf,
get_radius=300,
get_fill_color=[40, 110, 220, 200],
)
m = Map(
layers=[layer],
view_state={
'longitude': -122.4194,
'latitude': 37.7749,
'zoom': 12,
'pitch': 0,
'bearing': 0,
},
height=400,
)
m2. The counter¶
An ordinary CounterWidget. Initial value 5 → starting radius 5 × 100 = 500m. widget_id lets the binder find it.
radius_counter = CounterWidget(
label="Point radius (× 100 m)",
widget_id="radius_ctrl",
value=5,
)
radius_counter3. The binder¶
source = the counter (radius_ctrl). target = the scatterplot layer, looked up by its _layer_type alias (_layer_type:scatterplot). The plugin’s shim registers each lonboard sub-model under multiple keys — model_id (UUID), _anywidget_id, widget_id, and (for layers) _layer_type:<type> — so binders can target a layer without knowing its UUID.
target_field="get_radius" — when the model fires change:get_radius, lonboard’s React layer hook re-reads it and rebuilds the deck.gl layer. With multiplier=100, counter value 5 → radius 500m.
binder = WidgetBinder(
source_widget_id="radius_ctrl",
source_field="value",
target_widget_id="_layer_type:scatterplot",
target_field="get_radius",
multiplier=100.0,
offset=0.0,
label="counter.value → layer.get_radius",
)
binder