Dashboards

Dashboards

A dashboard is a .base file with a layout:. Every panel is an ordinary view of that file, placed on a 12-column grid; datasets: names more data files, links: says how their rows relate, one rail filters every panel, and a click in one panel can narrow the others. <data-dashboard src="x.base"> draws it.

On main now: <data-dashboard>, layout:, datasets:, links:, select: and rollup: (dist/dashboard.js, CONTRACT §17). Every block below is a real dashboard from the examples, live. The card catalog and the synced clock are still on lane/dashboard-cards: Lands with dashboard cards

The dashboard file

layout: sits next to views:. Panels are in reading order; w is the number of columns (of 12) and h the height in row units (110 px each). A panel is {view}, {views: [...]} (several views as tabs inside the panel) or {text} (markdown). Under 900 px the grid is one column. Obsidian opens the same file and shows the panels as tabs.

A dashboard, live layout:

Live

Vibe Tracks' track overview: a text panel, a strip of KPI cards, the track tree beside a bar chart, and one panel holding two views as tabs. Code is its layout:; every panel names a view of the same file.

The live dashboard starts when it scrolls into sight.

index.html
<script type="module" src="/vendor/data-ui/data-ui.js"></script>
<script type="module" src="/vendor/data-ui/dashboard.js"></script>

<data-dashboard src="views.base"></data-dashboard>

From the example Vibe Tracks · track overview dashboard · a page without a dashboard never loads dashboard.js

Several datasets, linked, and roll-ups

datasets: names each data file; a view picks one with from: (default: the file's own data:). links: says which property of one dataset holds the ids of another's rows. A link filters, it never adds a column: "show the runs of the tracks that pass the rail" reaches the runs panel as an ordinary filter on track, visible in that panel's Filter menu. Links work both ways and chain (kpis → tracks → runs).

Two datasets, one link, a roll-up datasets: · links: · rollup:

Live

Vibe Tracks' run explorer. The runs are the file's own data:; tracks is a second dataset, linked by runs.track → tracks.id. The Leaderboard panel reads tracks' roll-up: each track's newest run per suite, summed through its child tracks. Hover a pass rate there: the cell says it is derived and from how many rows. Tick an area in the rail (a tracks facet) and the runs follow through the link.

The live dashboard starts when it scrolls into sight.

From the example Vibe Tracks · run explorer

  • A roll-up is a computed column on a dataset with a tree:: rollup: {from, latest: {by, per}, values: {<column>: {property, summary, per}}}. It reads one direct link to from, keeps the newest row per per when latest: says so, and sums through the tree, so a parent shows its children's numbers.
  • summary is a Bases summary name, or Ratio: Σproperty / Σper, a ratio of sums, never a mean of ratios.
  • Its cells say what they are: {value, basis: derived, n, note}, drawn hollow like an estimate. A producer's own headline number is never recomputed.
  • A roll-up reads only its source dataset's own filters, so ticking a track in the rail does not shrink the totals it is ranked by.

One rail, click to filter

  • One rail. Each dataset's facets: is its part of the rail. Its counts include every other restriction, so a count says what a tick would leave. The rail's edge drags, like every side panel.
  • What a panel shows: its dataset's rail filter, every selection other panels made on it, and a semi-join from every other restricted dataset that has a link path to it. Its own filters: still apply.
  • Click to filter. select: <property> on a view: a click on a bar, a card or a row selects that property's values for the whole dashboard; clicking again clears it. The panel you clicked ignores its own selection, so you can click another bar (Superset's and Mosaic's rule). Chips above the grid show each selection.
  • Drill down. A click on a panel without select: opens one side peek for the whole dashboard, resizable like every side panel.
  • The URL holds it all: ?health=green&runs.kind=tests for the rails, #s.<panel>=track:a,b for selections, #p.<panel>=<view> for a panel's tab. Reload and Back restore it. (The demos here are no-url, so they leave this page's address alone.)

Cross-filtering with select: select:

Live

pidtuna's four-rung ladder on nine simulated robots. Click a KPI card or a point: select: robot_id narrows every panel over the gains to that robot, and a chip above the grid says so (click the chip to clear it). Click a bar in Error by rung to select a rung as well. The rack's data at the bottom has no link to the robots, so their rail and selections leave its two panels alone.

The live dashboard starts when it scrolls into sight.

From the example PID tuning results · simulated robots with illustrative parameters, and said so on the dashboard

The card catalog

A card is a view: every card is a type: in views:, placed by layout: like a table or a chart. Only its own keys are new.

Every card type

Lands with dashboard cards
type:DrawsStock partFollows the clock
kpia stat with its delta, coloured by which way is better, and a sparklineours (exists today)
gaugea bar or semicircle against a target or gateours (SVG/CSS)
bulleta value bar, a target tick and qualitative bandsours (SVG)
barlista ranked bar list, a leaderboardours (CSS)
statusone cell per row, coloured by a state (a tracker grid)ours (CSS)
timeserieslines or areas over t: bands, rules, a log axis, brush-zoom, a shared crosshair, the playheadVega-Liteyes
chartbar, histogram, scatter, heatmap: any Vega-LiteVega-Lite (exists today)
trajectorya 2D path against its target, equal aspect, coloured by error, a tolerance tubeVega-Liteyes
scene3d3D paths, a moving marker, an optional stick robotthree.jsyes
videoone video that seeks to the clockthe browseryes
video-comparetwo videos: wipe, onion skin, difference or side by sidethe browser + CSSyes
imagean image, or a strip of them from rowsthe browser
playbackthe clock's control: play, scrub, speed, loop, step a frame, a rangeoursis the clock
gallery/dashboard-cards/views.base · four cards (planned syntax)
views:
  - type: playback
    name: Playback
    playback: { speeds: [0.25, 0.5, 1, 2], range: true, readout: true }
  - type: timeseries
    name: Error over time
    filters: 'joint == "elbow_joint" && situation != "target"'
    timeseries:
      x: t
      y: err_mrad
      series: situation
      unit: mrad
      rules: [{ y: 5, label: "gate 5 mrad", tone: bad }, { y: -5, tone: bad }]
      bands: [{ y: [-5, 5], label: tolerance, tone: good }]
  - type: video-compare
    name: Overlay
    from: media
    overlay: { by: situation, a: tuned, b: factory, mode: wipe, split: 0.5 }
  - type: trajectory
    name: Tool path (XZ)
    from: tool
    trajectory: { x: px, y: pz, series: situation, target: target, t: t, trail: true, tolerance: 0.005 }

Planned syntax, from lane/dashboard-cards @ 4ceda4d (docs/peps/0005-dashboard-cards.md, gallery/examples/dashboard-cards). Not on main yet: this block becomes live when that lane lands.

One clock, synced

Time is one more piece of dashboard state. One clock per dashboard sets t; every time-aware card follows it: a video seeks, a time series draws its playhead, a trajectory and a 3D scene move their marker. The playback card is its control. #t=3.20 in the URL lands a shared link on the same instant.

The clock and the dashboard's look

Lands with dashboard cards

Playing, a primary video drives the clock and the other videos follow it (a jump when more than 0.1 s off, a ±5 % nudge when close). Paused, a seek places every video, playhead and marker in the same task. Keys: Space, ← / → a frame, Shift+← / → a second, J / K / L, [ and ] for the range. style: sets about ten dashboard-wide knobs (surface, radius, gaps, titles, chart chrome, number format, a colour per series name); a panel may override any of them.

gallery/dashboard-cards/views.base · style: and clock: (planned syntax)
style:
  chrome: minimal
  numbers: { digits: 3, compact: true }
  palette: { target: "#8b9099", factory: "#e8743b", tuned: "#2a78d6", oracle: "#19a979" }
clock:
  data: samples
  time: t
  loop: true
  fps: 30

Planned syntax, from lane/dashboard-cards @ 4ceda4d (docs/peps/0005-dashboard-cards.md, gallery/examples/dashboard-cards). Not on main yet: this block becomes live when that lane lands.