Live data: a new day¶
Build the page once. For each new day, give the roads their numbers and colours from the browser. There is no new style and no reload.
The idea¶
- Build the page with
live_data=True. - In the page, call
rs.setData(rows, options)with the numbers of a day. - A call for the next day replaces the values of the day before. The legend (in the toolbox box Colour by and legend) and the colours follow.
await rs.setData([{edge_id: 17, flow: 840}, {edge_id: 18, flow: 120}],
{colorBy: "flow", legend: {title: "Flow, 2026-10-29"}});
rs.clearData(); // take the data away
rows is an array of objects, an Arrow table, or the URL of a JSON file with such an array (rs.setData("flow-2026-10-29.json", ...)).
Each row has an edge_id and the columns that you name in the options. Write edge_id as text ("edge_id": "7203945719283746").
The ids of duckOSM are 64-bit numbers, and a JSON number above 2^53 is not exact in a browser: the road is not found, and matched is small. The call gives a Promise with {rows, matched, ms}, and the event
rs:datachange fires.
| Option | Meaning |
|---|---|
colorBy |
the column that gives the colour: a number goes in one of classes sets (see The colour sets), a text gets one colour for each value |
classes |
the number of sets for a number, default 7. classes: 0, or a vmin or vmax, gives a smooth ramp from vmin to vmax (the range of the data when you leave them out) |
breaks |
your own cut points, for example [200, 800] gives 3 sets. The same colours then mean the same numbers on every day |
widthBy, widthRange |
a column that gives a factor of the drawn width (from widthRange[0] to widthRange[1], default [1, 3]). Do not use it for numbers like the flow: the two carriageways of a street have the same width, and the factor makes one cover the other. Show the flow in the colour |
ramp, stepped |
your own list of colours (the default is data.live_ramp of the palette); stepped: true takes the nearest colour of a smooth ramp, with hard edges |
nodata |
the colour of a road with no row (default: the page's no-data colour) |
key |
the column that names the road (default edge_id; "row" for the number of the road's row) |
fields |
the columns of the rows that the popup, the tooltip and the panel show, for example ["flow"]. Default: every column except the key column |
legend |
false: no legend; {title: "..."}: change the legend |
The colour sets¶
A number goes in one of classes sets (default 7). The cut points are the natural breaks of the numbers you give (the Fisher–Jenks method):
the numbers inside a set are as close as possible, and the sets are as different as possible. The sets have different numbers of members. One very busy street does not
use up the colour bar: it gets a set of its own. Set 1 gets the first colour of the ramp, the last set gets the last colour.
The legend shows the lowest and the highest number of each set, and how many roads are in it: 100 – 400 (9).
The cut points come from the data of the call, so each day has its own. To compare two days by colour, give the same breaks to both. The default ramp goes
from blue through green and yellow to red. Its colours have a medium brightness, so they show on the light map and on the dark map.
Several ways to colour¶
A page that can show the same data in more than one way (for example the flow, then who was counted) gives the names to the legend box. The box shows them as its "Colour by" list, above the legend:
rs.colorModes.set(["Traffic", "Counted"], {onChange: name => show(name)}); // show() calls rs.setData with that mode's column
A day picker¶
The picker is a section of the panel (it follows both themes). Its code is the page's own script: page_script= adds it, with no edit of the HTML.
days = ["2026-10-27", "2026-10-28", "2026-10-29"]
picker = "<select id='day'>" + "".join(f"<option>{d}</option>" for d in days) + "</select>"
m = rs.render_dashboard(
edges, live_data=True, name="Flow by day",
dashboard={"panel": {"sections": [{"id": "day", "label": "Day", "html": picker}]}},
page_script="""
rs.ready(() => {
const pick = document.getElementById("day");
const show = day => rs.setData(`flow-${day}.json`, {colorBy: "flow", legend: {title: "Flow, " + day}});
pick.onchange = () => show(pick.value);
show(pick.value);
});
""",
)
m.save("flow.html")
Serve the page and the JSON files from one folder (python -m http.server): a page opened from disk cannot load files.
To add a new day, write its flow-<day>.json and add the day to days. The page does not change.
Good to know¶
- The call gives
{rows, matched}. Whenmatchedis much smaller thanrows, the ids do not match: check thatedge_idis text. - A click on a road shows the joined values in the popup, and in the road card when the page adds one (
{"part": "road_card"}). rs.ready(fn)runsfnwhenwindow.rsis there and the panel's sections (your picker) are in place, and at once if they already are. Apage_scriptruns before that, so it puts its code inrs.ready, as in the example. The eventrs:readyfires once.