Manual — using roadstyle, with live output¶
A hands-on walk-through of the library, with the actual rendered map embedded after each step so
you can see exactly what the code produces. Every map below is the real, self-contained output of
the snippet above it (the same backend="web" MapLibre map you'd .save(...)), regenerated by
docs/build_maps.py from the
bundled sample edges (notebooks/data/sodermalm_edges.gpkg, ~4,600 real road edges).
New here? Read Usage for install + the CLI, then come back. For every parameter, see the Parameter reference.
1. Your first map¶
Load road edges (any CRS; just needs a road-class column) and render. backend="web" is the
default — a self-contained MapLibre map you can ship as one file.
import geopandas as gpd
import roadstyle as rs
edges = gpd.read_file("sodermalm_edges.gpkg") # has a `highway` column
rs.render_edges(edges).save("first_map.html") # web backend, Voyager base (settings default)
You get the OSM "geometry sandwich" (coloured fills over casings), per-zoom widths, two-way lanes,
one-way arrows, street-name labels, hover/click, and a base-layer switcher — try them in the map.
Prefer a dark canvas? Pass basemap="dark_matter" (Dark Matter) or basemap="satellite".
Hover a road to highlight it; click it for its attributes; use the dropdown (top-left) to switch the base map.
2. Colour roads by your own data — switchable, in the browser¶
Bake several "colour by" options into one map and switch between them client-side, with no
re-render and no server. Pass color_options — an ordered {name: {styler kwargs}} mapping — and
roadstyle adds a Colour by dropdown. A neutral base reads best, so pair it with
palette="mono":
rs.render_edges(edges, backend="web", palette="mono",
color_options={
"Class": {}, # neutral mono base
"AADT": {"color_by": "aadt", "cmap": "viridis"},
"Speed": {"color_by": "speed_kph", "cmap": "magma"},
},
).save("recolor.html")
Use the Colour by dropdown (top-right) to switch between road class, AADT, and speed. The legend (bottom-left) follows the active option. Roads keep their width/casing/lanes — only the fill swaps.
Two things worth knowing:
- Blank edges keep the base colour. An edge with no value for a data option (NaN / unmapped) falls back to its base (mono) colour, not a flat grey — so "no data" roads blend into the base instead of reading as a separate category.
- Drive it from your own UI. The page exposes
window.rsSetColorField(name|index)and fires ars:colorchangeevent, so a custom control can switch colours and stay in sync (see §4).
3. Add your own overlay layers (zones, POIs, anything)¶
Bring extra geometry — zone polygons, POI points, any lines — as Overlays. Each becomes its own
layer drawn under or over the roads, clickable for a popup of the fields you list, and
toggled from a Layers control. Overlays are your data with your style; they don't go through
the road-styling compiler.
from shapely.geometry import box, Point
# (here: synthetic zones + POIs — in practice your own GeoDataFrames)
rs.render_edges(edges, backend="web", palette="mono",
overlays=[
rs.Overlay(taz, kind="fill", placement="under", color="#6aa9ff",
opacity=0.14, label="TAZ zones", popup=["taz_id", "name", "weight"]),
rs.Overlay(pois, kind="circle", placement="over", color="#ff5d5d",
radius=7, label="POIs", popup=["name", "type"]),
],
).save("overlays.html")
Translucent TAZ zones sit under the roads; red POIs sit on top. Click a zone or a POI for its popup; use the Layers control (bottom-right) to toggle each overlay. (Road clicks take precedence — an overlay is consulted only where the click misses every road.)
kind is auto-detected from the geometry (polygon → fill, point → circle, line → line) but can
be forced. See Overlay for every field.
4. Drive the map from your own UI¶
Both outputs let you build a custom panel instead of (or alongside) the built-in controls.
Web backend (render_edges(backend="web")). The page exposes globals you can call from any HTML
you add to it:
<button onclick="rsSetColorField('AADT')">AADT</button>
<script>
document.addEventListener("rs:colorchange", e => console.log("now showing", e.detail.option.name));
</script>
window.RS_COLOR_OPTIONS lists the baked options; window.rsSetColorField(name|index) recolours;
rs:colorchange fires on every switch. (A worked custom-panel page is in
examples/recolor_web_backend.py.)
roadstyle.js spec page (rs.save(...) / to_html). The richer RoadStyleMap API has a real
panel hook + event bus:
const m = RoadStyle.create("map", spec, { widgets: { colors: false } });
m.on("ready", map => {
map.addPanel({ title: "Colour by", position: "topright", render(body, map) {
map.getColorOptions().forEach((o, i) => {
const b = document.createElement("button");
b.textContent = o.name; b.onclick = () => map.setColorField(i);
body.appendChild(b);
});
}});
});
addPanel gives you styled, auto-stacking chrome; on("select"|"deselect"|"colorchange"|"ready", …)
is the event bus; setColorField / getColorOptions drive the recolour. See
Embedding in a website and
examples/recolor_custom_panel.py.
Where to next¶
- Usage — install, the CLI, every recipe.
- MapLibre web backend — the full feature list: grade separation, lanes,
color_options,overlays, offline delivery. - Parameter reference — every parameter, including
color_optionsandOverlay. - Embedding in a website — the JSON spec + the
RoadStyleMapJS API. - Examples — the runnable notebooks and example scripts.