From 3e8a11127edd5a9fc94d99c8d87e0ad39169490a Mon Sep 17 00:00:00 2001 From: Ivan Cheung Date: Wed, 10 Jun 2026 18:58:34 +0000 Subject: [PATCH] =?UTF-8?q?fix(viewer):=20latency=20chart=20spilled=20off?= =?UTF-8?q?=20pane=20edge=20=E2=80=94=20use=20a=20legend,=20drop=20end-of-?= =?UTF-8?q?line=20labels=20(#161)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Latency by percentile" pane (sre/observability dashboard) rendered its p50/p95/p99 lines and end-of-line text labels past the right edge of the pane at narrow widths. Root cause: the chart labelled each line's end with a `text` layer at the last data point and reserved room with `x.scale.domainMax`. Vega's `fit` autosize (injected for `width:"container"`) contains the axes + legend but NOT a text mark whose pixel width extends past the data domain, and `domainMax` reserves room proportional to the x-range — so at a narrow pane width the fixed-pixel labels still overflowed. Fix: drop the `text` layer entirely and restore the merged color+dash legend (remove `color.legend:null` + `strokeDash.legend:null` + `x.scale.domainMax`). The fit-autosize always reserves room for a legend at any pane width, so the chart now stays inside the pane from 480px to 1440px (verified: 0px overflow). Applied to both the demo seed (packages/viewer/src/demo/observability.json) and the recipe example (observability-dashboard.panes.json). Reconciled the SKILL.md charting note to prefer a legend and warn against end-of-line text labels (they spill on narrow panes). --- packages/viewer/src/demo/observability.json | 2 +- plugin/skills/diagram-recipes/SKILL.md | 9 ++++++--- .../examples/observability-dashboard.panes.json | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/viewer/src/demo/observability.json b/packages/viewer/src/demo/observability.json index cad07d2..ed979b1 100644 --- a/packages/viewer/src/demo/observability.json +++ b/packages/viewer/src/demo/observability.json @@ -9,7 +9,7 @@ { "title": "Latency", "type": "vegalite", - "content": "{\"$schema\": \"https://vega.github.io/schema/vega-lite/v6.json\", \"title\": {\"text\": \"Latency by percentile (ms)\", \"subtitle\": \"last 24h · dash + label = percentile (color-independent)\", \"anchor\": \"start\"}, \"width\": \"container\", \"height\": 300, \"data\": {\"values\": [{\"h\": 0, \"ms\": 83, \"pct\": \"p50\"}, {\"h\": 1, \"ms\": 86, \"pct\": \"p50\"}, {\"h\": 2, \"ms\": 90, \"pct\": \"p50\"}, {\"h\": 3, \"ms\": 93, \"pct\": \"p50\"}, {\"h\": 4, \"ms\": 94, \"pct\": \"p50\"}, {\"h\": 5, \"ms\": 95, \"pct\": \"p50\"}, {\"h\": 6, \"ms\": 94, \"pct\": \"p50\"}, {\"h\": 7, \"ms\": 93, \"pct\": \"p50\"}, {\"h\": 8, \"ms\": 90, \"pct\": \"p50\"}, {\"h\": 9, \"ms\": 87, \"pct\": \"p50\"}, {\"h\": 10, \"ms\": 83, \"pct\": \"p50\"}, {\"h\": 11, \"ms\": 79, \"pct\": \"p50\"}, {\"h\": 12, \"ms\": 75, \"pct\": \"p50\"}, {\"h\": 13, \"ms\": 73, \"pct\": \"p50\"}, {\"h\": 14, \"ms\": 71, \"pct\": \"p50\"}, {\"h\": 15, \"ms\": 70, \"pct\": \"p50\"}, {\"h\": 16, \"ms\": 71, \"pct\": \"p50\"}, {\"h\": 17, \"ms\": 72, \"pct\": \"p50\"}, {\"h\": 18, \"ms\": 75, \"pct\": \"p50\"}, {\"h\": 19, \"ms\": 78, \"pct\": \"p50\"}, {\"h\": 20, \"ms\": 82, \"pct\": \"p50\"}, {\"h\": 21, \"ms\": 86, \"pct\": \"p50\"}, {\"h\": 22, \"ms\": 89, \"pct\": \"p50\"}, {\"h\": 23, \"ms\": 92, \"pct\": \"p50\"}, {\"h\": 0, \"ms\": 226, \"pct\": \"p95\"}, {\"h\": 1, \"ms\": 235, \"pct\": \"p95\"}, {\"h\": 2, \"ms\": 243, \"pct\": \"p95\"}, {\"h\": 3, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 4, \"ms\": 250, \"pct\": \"p95\"}, {\"h\": 5, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 6, \"ms\": 244, \"pct\": \"p95\"}, {\"h\": 7, \"ms\": 236, \"pct\": \"p95\"}, {\"h\": 8, \"ms\": 226, \"pct\": \"p95\"}, {\"h\": 9, \"ms\": 216, \"pct\": \"p95\"}, {\"h\": 10, \"ms\": 205, \"pct\": \"p95\"}, {\"h\": 11, \"ms\": 195, \"pct\": \"p95\"}, {\"h\": 12, \"ms\": 187, \"pct\": \"p95\"}, {\"h\": 13, \"ms\": 182, \"pct\": \"p95\"}, {\"h\": 14, \"ms\": 180, \"pct\": \"p95\"}, {\"h\": 15, \"ms\": 181, \"pct\": \"p95\"}, {\"h\": 16, \"ms\": 186, \"pct\": \"p95\"}, {\"h\": 17, \"ms\": 194, \"pct\": \"p95\"}, {\"h\": 18, \"ms\": 203, \"pct\": \"p95\"}, {\"h\": 19, \"ms\": 214, \"pct\": \"p95\"}, {\"h\": 20, \"ms\": 225, \"pct\": \"p95\"}, {\"h\": 21, \"ms\": 235, \"pct\": \"p95\"}, {\"h\": 22, \"ms\": 243, \"pct\": \"p95\"}, {\"h\": 23, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 0, \"ms\": 431, \"pct\": \"p99\"}, {\"h\": 1, \"ms\": 446, \"pct\": \"p99\"}, {\"h\": 2, \"ms\": 456, \"pct\": \"p99\"}, {\"h\": 3, \"ms\": 460, \"pct\": \"p99\"}, {\"h\": 4, \"ms\": 457, \"pct\": \"p99\"}, {\"h\": 5, \"ms\": 447, \"pct\": \"p99\"}, {\"h\": 6, \"ms\": 432, \"pct\": \"p99\"}, {\"h\": 7, \"ms\": 413, \"pct\": \"p99\"}, {\"h\": 8, \"ms\": 391, \"pct\": \"p99\"}, {\"h\": 9, \"ms\": 370, \"pct\": \"p99\"}, {\"h\": 10, \"ms\": 350, \"pct\": \"p99\"}, {\"h\": 11, \"ms\": 334, \"pct\": \"p99\"}, {\"h\": 12, \"ms\": 324, \"pct\": \"p99\"}, {\"h\": 13, \"ms\": 320, \"pct\": \"p99\"}, {\"h\": 14, \"ms\": 323, \"pct\": \"p99\"}, {\"h\": 15, \"ms\": 332, \"pct\": \"p99\"}, {\"h\": 16, \"ms\": 347, \"pct\": \"p99\"}, {\"h\": 17, \"ms\": 366, \"pct\": \"p99\"}, {\"h\": 18, \"ms\": 388, \"pct\": \"p99\"}, {\"h\": 19, \"ms\": 409, \"pct\": \"p99\"}, {\"h\": 20, \"ms\": 429, \"pct\": \"p99\"}, {\"h\": 21, \"ms\": 445, \"pct\": \"p99\"}, {\"h\": 22, \"ms\": 456, \"pct\": \"p99\"}, {\"h\": 23, \"ms\": 460, \"pct\": \"p99\"}]}, \"encoding\": {\"x\": {\"field\": \"h\", \"type\": \"quantitative\", \"title\": \"hour\", \"axis\": {\"tickMinStep\": 3}, \"scale\": {\"domainMax\": 25}}, \"color\": {\"field\": \"pct\", \"type\": \"nominal\", \"title\": null, \"scale\": {\"domain\": [\"p50\", \"p95\", \"p99\"], \"range\": [\"#22c55e\", \"#fbbf24\", \"#ef4444\"]}, \"legend\": null}}, \"layer\": [{\"mark\": {\"type\": \"line\", \"point\": false, \"tooltip\": true, \"interpolate\": \"monotone\", \"strokeWidth\": 2}, \"encoding\": {\"y\": {\"field\": \"ms\", \"type\": \"quantitative\", \"title\": \"ms\"}, \"strokeDash\": {\"field\": \"pct\", \"type\": \"nominal\", \"title\": null, \"scale\": {\"domain\": [\"p50\", \"p95\", \"p99\"], \"range\": [[1, 0], [6, 3], [2, 3]]}, \"legend\": null}}}, {\"transform\": [{\"window\": [{\"op\": \"last_value\", \"field\": \"h\", \"as\": \"lastH\"}], \"frame\": [null, null], \"groupby\": [\"pct\"]}, {\"filter\": \"datum.h === datum.lastH\"}], \"mark\": {\"type\": \"text\", \"align\": \"left\", \"baseline\": \"middle\", \"dx\": 6, \"fontWeight\": \"bold\", \"fontSize\": 12}, \"encoding\": {\"y\": {\"field\": \"ms\", \"type\": \"quantitative\"}, \"text\": {\"field\": \"pct\"}}}]}" + "content": "{\"$schema\": \"https://vega.github.io/schema/vega-lite/v6.json\", \"title\": {\"text\": \"Latency by percentile (ms)\", \"subtitle\": \"last 24h · percentile by color + dash (legend)\", \"anchor\": \"start\"}, \"width\": \"container\", \"height\": 300, \"data\": {\"values\": [{\"h\": 0, \"ms\": 83, \"pct\": \"p50\"}, {\"h\": 1, \"ms\": 86, \"pct\": \"p50\"}, {\"h\": 2, \"ms\": 90, \"pct\": \"p50\"}, {\"h\": 3, \"ms\": 93, \"pct\": \"p50\"}, {\"h\": 4, \"ms\": 94, \"pct\": \"p50\"}, {\"h\": 5, \"ms\": 95, \"pct\": \"p50\"}, {\"h\": 6, \"ms\": 94, \"pct\": \"p50\"}, {\"h\": 7, \"ms\": 93, \"pct\": \"p50\"}, {\"h\": 8, \"ms\": 90, \"pct\": \"p50\"}, {\"h\": 9, \"ms\": 87, \"pct\": \"p50\"}, {\"h\": 10, \"ms\": 83, \"pct\": \"p50\"}, {\"h\": 11, \"ms\": 79, \"pct\": \"p50\"}, {\"h\": 12, \"ms\": 75, \"pct\": \"p50\"}, {\"h\": 13, \"ms\": 73, \"pct\": \"p50\"}, {\"h\": 14, \"ms\": 71, \"pct\": \"p50\"}, {\"h\": 15, \"ms\": 70, \"pct\": \"p50\"}, {\"h\": 16, \"ms\": 71, \"pct\": \"p50\"}, {\"h\": 17, \"ms\": 72, \"pct\": \"p50\"}, {\"h\": 18, \"ms\": 75, \"pct\": \"p50\"}, {\"h\": 19, \"ms\": 78, \"pct\": \"p50\"}, {\"h\": 20, \"ms\": 82, \"pct\": \"p50\"}, {\"h\": 21, \"ms\": 86, \"pct\": \"p50\"}, {\"h\": 22, \"ms\": 89, \"pct\": \"p50\"}, {\"h\": 23, \"ms\": 92, \"pct\": \"p50\"}, {\"h\": 0, \"ms\": 226, \"pct\": \"p95\"}, {\"h\": 1, \"ms\": 235, \"pct\": \"p95\"}, {\"h\": 2, \"ms\": 243, \"pct\": \"p95\"}, {\"h\": 3, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 4, \"ms\": 250, \"pct\": \"p95\"}, {\"h\": 5, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 6, \"ms\": 244, \"pct\": \"p95\"}, {\"h\": 7, \"ms\": 236, \"pct\": \"p95\"}, {\"h\": 8, \"ms\": 226, \"pct\": \"p95\"}, {\"h\": 9, \"ms\": 216, \"pct\": \"p95\"}, {\"h\": 10, \"ms\": 205, \"pct\": \"p95\"}, {\"h\": 11, \"ms\": 195, \"pct\": \"p95\"}, {\"h\": 12, \"ms\": 187, \"pct\": \"p95\"}, {\"h\": 13, \"ms\": 182, \"pct\": \"p95\"}, {\"h\": 14, \"ms\": 180, \"pct\": \"p95\"}, {\"h\": 15, \"ms\": 181, \"pct\": \"p95\"}, {\"h\": 16, \"ms\": 186, \"pct\": \"p95\"}, {\"h\": 17, \"ms\": 194, \"pct\": \"p95\"}, {\"h\": 18, \"ms\": 203, \"pct\": \"p95\"}, {\"h\": 19, \"ms\": 214, \"pct\": \"p95\"}, {\"h\": 20, \"ms\": 225, \"pct\": \"p95\"}, {\"h\": 21, \"ms\": 235, \"pct\": \"p95\"}, {\"h\": 22, \"ms\": 243, \"pct\": \"p95\"}, {\"h\": 23, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 0, \"ms\": 431, \"pct\": \"p99\"}, {\"h\": 1, \"ms\": 446, \"pct\": \"p99\"}, {\"h\": 2, \"ms\": 456, \"pct\": \"p99\"}, {\"h\": 3, \"ms\": 460, \"pct\": \"p99\"}, {\"h\": 4, \"ms\": 457, \"pct\": \"p99\"}, {\"h\": 5, \"ms\": 447, \"pct\": \"p99\"}, {\"h\": 6, \"ms\": 432, \"pct\": \"p99\"}, {\"h\": 7, \"ms\": 413, \"pct\": \"p99\"}, {\"h\": 8, \"ms\": 391, \"pct\": \"p99\"}, {\"h\": 9, \"ms\": 370, \"pct\": \"p99\"}, {\"h\": 10, \"ms\": 350, \"pct\": \"p99\"}, {\"h\": 11, \"ms\": 334, \"pct\": \"p99\"}, {\"h\": 12, \"ms\": 324, \"pct\": \"p99\"}, {\"h\": 13, \"ms\": 320, \"pct\": \"p99\"}, {\"h\": 14, \"ms\": 323, \"pct\": \"p99\"}, {\"h\": 15, \"ms\": 332, \"pct\": \"p99\"}, {\"h\": 16, \"ms\": 347, \"pct\": \"p99\"}, {\"h\": 17, \"ms\": 366, \"pct\": \"p99\"}, {\"h\": 18, \"ms\": 388, \"pct\": \"p99\"}, {\"h\": 19, \"ms\": 409, \"pct\": \"p99\"}, {\"h\": 20, \"ms\": 429, \"pct\": \"p99\"}, {\"h\": 21, \"ms\": 445, \"pct\": \"p99\"}, {\"h\": 22, \"ms\": 456, \"pct\": \"p99\"}, {\"h\": 23, \"ms\": 460, \"pct\": \"p99\"}]}, \"encoding\": {\"x\": {\"field\": \"h\", \"type\": \"quantitative\", \"title\": \"hour\", \"axis\": {\"tickMinStep\": 3}}, \"color\": {\"field\": \"pct\", \"type\": \"nominal\", \"title\": null, \"scale\": {\"domain\": [\"p50\", \"p95\", \"p99\"], \"range\": [\"#22c55e\", \"#fbbf24\", \"#ef4444\"]}}}, \"layer\": [{\"mark\": {\"type\": \"line\", \"point\": false, \"tooltip\": true, \"interpolate\": \"monotone\", \"strokeWidth\": 2}, \"encoding\": {\"y\": {\"field\": \"ms\", \"type\": \"quantitative\", \"title\": \"ms\"}, \"strokeDash\": {\"field\": \"pct\", \"type\": \"nominal\", \"title\": null, \"scale\": {\"domain\": [\"p50\", \"p95\", \"p99\"], \"range\": [[1, 0], [6, 3], [2, 3]]}}}}]}" }, { "title": "Top errors", diff --git a/plugin/skills/diagram-recipes/SKILL.md b/plugin/skills/diagram-recipes/SKILL.md index 0e143bd..0c759c9 100644 --- a/plugin/skills/diagram-recipes/SKILL.md +++ b/plugin/skills/diagram-recipes/SKILL.md @@ -128,9 +128,12 @@ Compose the knobs; don't ship the bare minimum. - **Every chart gets context:** `title`+`subtitle`, axis `title`s, `tooltip:true`, and `width:"container"` — the viewer auto-fits the whole chart (axes + legend) to its pane, so **don't hardcode a fixed pixel `width`** (it bleeds out of the pane). **Never rely on red/green - alone** — add dashes, labels, or a second channel. If you label line **ends** directly (a text - layer at the last point), drop the now-redundant `legend` (`legend:null`) AND reserve room with - `x.scale.domainMax` past the last point, or the labels spill off the plot's right edge. + alone** — add dashes, labels, or a second channel. **Prefer a `legend`** to distinguish series + (e.g. `color`+`strokeDash` merged into one swatch): the fit-autosize always reserves room for a + legend at any pane width. **Avoid end-of-line text labels** (a `text` layer at the last point) — + the fit contains axes + legend but NOT text marks whose pixel width extends past the data domain, + so those labels spill off the plot's right edge on a narrow pane (no `x.scale.domainMax` reserves + enough at every width). - **Keep node `label`/`sub` concise.** The layout sizes each card to its content and spaces nodes to avoid overlap, so short, scannable text reads best (and the card stays compact). Pair the `label` with `icon`/`sub`/`meta` for context — don't ship a bare word. diff --git a/plugin/skills/diagram-recipes/examples/observability-dashboard.panes.json b/plugin/skills/diagram-recipes/examples/observability-dashboard.panes.json index cad07d2..ed979b1 100644 --- a/plugin/skills/diagram-recipes/examples/observability-dashboard.panes.json +++ b/plugin/skills/diagram-recipes/examples/observability-dashboard.panes.json @@ -9,7 +9,7 @@ { "title": "Latency", "type": "vegalite", - "content": "{\"$schema\": \"https://vega.github.io/schema/vega-lite/v6.json\", \"title\": {\"text\": \"Latency by percentile (ms)\", \"subtitle\": \"last 24h · dash + label = percentile (color-independent)\", \"anchor\": \"start\"}, \"width\": \"container\", \"height\": 300, \"data\": {\"values\": [{\"h\": 0, \"ms\": 83, \"pct\": \"p50\"}, {\"h\": 1, \"ms\": 86, \"pct\": \"p50\"}, {\"h\": 2, \"ms\": 90, \"pct\": \"p50\"}, {\"h\": 3, \"ms\": 93, \"pct\": \"p50\"}, {\"h\": 4, \"ms\": 94, \"pct\": \"p50\"}, {\"h\": 5, \"ms\": 95, \"pct\": \"p50\"}, {\"h\": 6, \"ms\": 94, \"pct\": \"p50\"}, {\"h\": 7, \"ms\": 93, \"pct\": \"p50\"}, {\"h\": 8, \"ms\": 90, \"pct\": \"p50\"}, {\"h\": 9, \"ms\": 87, \"pct\": \"p50\"}, {\"h\": 10, \"ms\": 83, \"pct\": \"p50\"}, {\"h\": 11, \"ms\": 79, \"pct\": \"p50\"}, {\"h\": 12, \"ms\": 75, \"pct\": \"p50\"}, {\"h\": 13, \"ms\": 73, \"pct\": \"p50\"}, {\"h\": 14, \"ms\": 71, \"pct\": \"p50\"}, {\"h\": 15, \"ms\": 70, \"pct\": \"p50\"}, {\"h\": 16, \"ms\": 71, \"pct\": \"p50\"}, {\"h\": 17, \"ms\": 72, \"pct\": \"p50\"}, {\"h\": 18, \"ms\": 75, \"pct\": \"p50\"}, {\"h\": 19, \"ms\": 78, \"pct\": \"p50\"}, {\"h\": 20, \"ms\": 82, \"pct\": \"p50\"}, {\"h\": 21, \"ms\": 86, \"pct\": \"p50\"}, {\"h\": 22, \"ms\": 89, \"pct\": \"p50\"}, {\"h\": 23, \"ms\": 92, \"pct\": \"p50\"}, {\"h\": 0, \"ms\": 226, \"pct\": \"p95\"}, {\"h\": 1, \"ms\": 235, \"pct\": \"p95\"}, {\"h\": 2, \"ms\": 243, \"pct\": \"p95\"}, {\"h\": 3, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 4, \"ms\": 250, \"pct\": \"p95\"}, {\"h\": 5, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 6, \"ms\": 244, \"pct\": \"p95\"}, {\"h\": 7, \"ms\": 236, \"pct\": \"p95\"}, {\"h\": 8, \"ms\": 226, \"pct\": \"p95\"}, {\"h\": 9, \"ms\": 216, \"pct\": \"p95\"}, {\"h\": 10, \"ms\": 205, \"pct\": \"p95\"}, {\"h\": 11, \"ms\": 195, \"pct\": \"p95\"}, {\"h\": 12, \"ms\": 187, \"pct\": \"p95\"}, {\"h\": 13, \"ms\": 182, \"pct\": \"p95\"}, {\"h\": 14, \"ms\": 180, \"pct\": \"p95\"}, {\"h\": 15, \"ms\": 181, \"pct\": \"p95\"}, {\"h\": 16, \"ms\": 186, \"pct\": \"p95\"}, {\"h\": 17, \"ms\": 194, \"pct\": \"p95\"}, {\"h\": 18, \"ms\": 203, \"pct\": \"p95\"}, {\"h\": 19, \"ms\": 214, \"pct\": \"p95\"}, {\"h\": 20, \"ms\": 225, \"pct\": \"p95\"}, {\"h\": 21, \"ms\": 235, \"pct\": \"p95\"}, {\"h\": 22, \"ms\": 243, \"pct\": \"p95\"}, {\"h\": 23, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 0, \"ms\": 431, \"pct\": \"p99\"}, {\"h\": 1, \"ms\": 446, \"pct\": \"p99\"}, {\"h\": 2, \"ms\": 456, \"pct\": \"p99\"}, {\"h\": 3, \"ms\": 460, \"pct\": \"p99\"}, {\"h\": 4, \"ms\": 457, \"pct\": \"p99\"}, {\"h\": 5, \"ms\": 447, \"pct\": \"p99\"}, {\"h\": 6, \"ms\": 432, \"pct\": \"p99\"}, {\"h\": 7, \"ms\": 413, \"pct\": \"p99\"}, {\"h\": 8, \"ms\": 391, \"pct\": \"p99\"}, {\"h\": 9, \"ms\": 370, \"pct\": \"p99\"}, {\"h\": 10, \"ms\": 350, \"pct\": \"p99\"}, {\"h\": 11, \"ms\": 334, \"pct\": \"p99\"}, {\"h\": 12, \"ms\": 324, \"pct\": \"p99\"}, {\"h\": 13, \"ms\": 320, \"pct\": \"p99\"}, {\"h\": 14, \"ms\": 323, \"pct\": \"p99\"}, {\"h\": 15, \"ms\": 332, \"pct\": \"p99\"}, {\"h\": 16, \"ms\": 347, \"pct\": \"p99\"}, {\"h\": 17, \"ms\": 366, \"pct\": \"p99\"}, {\"h\": 18, \"ms\": 388, \"pct\": \"p99\"}, {\"h\": 19, \"ms\": 409, \"pct\": \"p99\"}, {\"h\": 20, \"ms\": 429, \"pct\": \"p99\"}, {\"h\": 21, \"ms\": 445, \"pct\": \"p99\"}, {\"h\": 22, \"ms\": 456, \"pct\": \"p99\"}, {\"h\": 23, \"ms\": 460, \"pct\": \"p99\"}]}, \"encoding\": {\"x\": {\"field\": \"h\", \"type\": \"quantitative\", \"title\": \"hour\", \"axis\": {\"tickMinStep\": 3}, \"scale\": {\"domainMax\": 25}}, \"color\": {\"field\": \"pct\", \"type\": \"nominal\", \"title\": null, \"scale\": {\"domain\": [\"p50\", \"p95\", \"p99\"], \"range\": [\"#22c55e\", \"#fbbf24\", \"#ef4444\"]}, \"legend\": null}}, \"layer\": [{\"mark\": {\"type\": \"line\", \"point\": false, \"tooltip\": true, \"interpolate\": \"monotone\", \"strokeWidth\": 2}, \"encoding\": {\"y\": {\"field\": \"ms\", \"type\": \"quantitative\", \"title\": \"ms\"}, \"strokeDash\": {\"field\": \"pct\", \"type\": \"nominal\", \"title\": null, \"scale\": {\"domain\": [\"p50\", \"p95\", \"p99\"], \"range\": [[1, 0], [6, 3], [2, 3]]}, \"legend\": null}}}, {\"transform\": [{\"window\": [{\"op\": \"last_value\", \"field\": \"h\", \"as\": \"lastH\"}], \"frame\": [null, null], \"groupby\": [\"pct\"]}, {\"filter\": \"datum.h === datum.lastH\"}], \"mark\": {\"type\": \"text\", \"align\": \"left\", \"baseline\": \"middle\", \"dx\": 6, \"fontWeight\": \"bold\", \"fontSize\": 12}, \"encoding\": {\"y\": {\"field\": \"ms\", \"type\": \"quantitative\"}, \"text\": {\"field\": \"pct\"}}}]}" + "content": "{\"$schema\": \"https://vega.github.io/schema/vega-lite/v6.json\", \"title\": {\"text\": \"Latency by percentile (ms)\", \"subtitle\": \"last 24h · percentile by color + dash (legend)\", \"anchor\": \"start\"}, \"width\": \"container\", \"height\": 300, \"data\": {\"values\": [{\"h\": 0, \"ms\": 83, \"pct\": \"p50\"}, {\"h\": 1, \"ms\": 86, \"pct\": \"p50\"}, {\"h\": 2, \"ms\": 90, \"pct\": \"p50\"}, {\"h\": 3, \"ms\": 93, \"pct\": \"p50\"}, {\"h\": 4, \"ms\": 94, \"pct\": \"p50\"}, {\"h\": 5, \"ms\": 95, \"pct\": \"p50\"}, {\"h\": 6, \"ms\": 94, \"pct\": \"p50\"}, {\"h\": 7, \"ms\": 93, \"pct\": \"p50\"}, {\"h\": 8, \"ms\": 90, \"pct\": \"p50\"}, {\"h\": 9, \"ms\": 87, \"pct\": \"p50\"}, {\"h\": 10, \"ms\": 83, \"pct\": \"p50\"}, {\"h\": 11, \"ms\": 79, \"pct\": \"p50\"}, {\"h\": 12, \"ms\": 75, \"pct\": \"p50\"}, {\"h\": 13, \"ms\": 73, \"pct\": \"p50\"}, {\"h\": 14, \"ms\": 71, \"pct\": \"p50\"}, {\"h\": 15, \"ms\": 70, \"pct\": \"p50\"}, {\"h\": 16, \"ms\": 71, \"pct\": \"p50\"}, {\"h\": 17, \"ms\": 72, \"pct\": \"p50\"}, {\"h\": 18, \"ms\": 75, \"pct\": \"p50\"}, {\"h\": 19, \"ms\": 78, \"pct\": \"p50\"}, {\"h\": 20, \"ms\": 82, \"pct\": \"p50\"}, {\"h\": 21, \"ms\": 86, \"pct\": \"p50\"}, {\"h\": 22, \"ms\": 89, \"pct\": \"p50\"}, {\"h\": 23, \"ms\": 92, \"pct\": \"p50\"}, {\"h\": 0, \"ms\": 226, \"pct\": \"p95\"}, {\"h\": 1, \"ms\": 235, \"pct\": \"p95\"}, {\"h\": 2, \"ms\": 243, \"pct\": \"p95\"}, {\"h\": 3, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 4, \"ms\": 250, \"pct\": \"p95\"}, {\"h\": 5, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 6, \"ms\": 244, \"pct\": \"p95\"}, {\"h\": 7, \"ms\": 236, \"pct\": \"p95\"}, {\"h\": 8, \"ms\": 226, \"pct\": \"p95\"}, {\"h\": 9, \"ms\": 216, \"pct\": \"p95\"}, {\"h\": 10, \"ms\": 205, \"pct\": \"p95\"}, {\"h\": 11, \"ms\": 195, \"pct\": \"p95\"}, {\"h\": 12, \"ms\": 187, \"pct\": \"p95\"}, {\"h\": 13, \"ms\": 182, \"pct\": \"p95\"}, {\"h\": 14, \"ms\": 180, \"pct\": \"p95\"}, {\"h\": 15, \"ms\": 181, \"pct\": \"p95\"}, {\"h\": 16, \"ms\": 186, \"pct\": \"p95\"}, {\"h\": 17, \"ms\": 194, \"pct\": \"p95\"}, {\"h\": 18, \"ms\": 203, \"pct\": \"p95\"}, {\"h\": 19, \"ms\": 214, \"pct\": \"p95\"}, {\"h\": 20, \"ms\": 225, \"pct\": \"p95\"}, {\"h\": 21, \"ms\": 235, \"pct\": \"p95\"}, {\"h\": 22, \"ms\": 243, \"pct\": \"p95\"}, {\"h\": 23, \"ms\": 248, \"pct\": \"p95\"}, {\"h\": 0, \"ms\": 431, \"pct\": \"p99\"}, {\"h\": 1, \"ms\": 446, \"pct\": \"p99\"}, {\"h\": 2, \"ms\": 456, \"pct\": \"p99\"}, {\"h\": 3, \"ms\": 460, \"pct\": \"p99\"}, {\"h\": 4, \"ms\": 457, \"pct\": \"p99\"}, {\"h\": 5, \"ms\": 447, \"pct\": \"p99\"}, {\"h\": 6, \"ms\": 432, \"pct\": \"p99\"}, {\"h\": 7, \"ms\": 413, \"pct\": \"p99\"}, {\"h\": 8, \"ms\": 391, \"pct\": \"p99\"}, {\"h\": 9, \"ms\": 370, \"pct\": \"p99\"}, {\"h\": 10, \"ms\": 350, \"pct\": \"p99\"}, {\"h\": 11, \"ms\": 334, \"pct\": \"p99\"}, {\"h\": 12, \"ms\": 324, \"pct\": \"p99\"}, {\"h\": 13, \"ms\": 320, \"pct\": \"p99\"}, {\"h\": 14, \"ms\": 323, \"pct\": \"p99\"}, {\"h\": 15, \"ms\": 332, \"pct\": \"p99\"}, {\"h\": 16, \"ms\": 347, \"pct\": \"p99\"}, {\"h\": 17, \"ms\": 366, \"pct\": \"p99\"}, {\"h\": 18, \"ms\": 388, \"pct\": \"p99\"}, {\"h\": 19, \"ms\": 409, \"pct\": \"p99\"}, {\"h\": 20, \"ms\": 429, \"pct\": \"p99\"}, {\"h\": 21, \"ms\": 445, \"pct\": \"p99\"}, {\"h\": 22, \"ms\": 456, \"pct\": \"p99\"}, {\"h\": 23, \"ms\": 460, \"pct\": \"p99\"}]}, \"encoding\": {\"x\": {\"field\": \"h\", \"type\": \"quantitative\", \"title\": \"hour\", \"axis\": {\"tickMinStep\": 3}}, \"color\": {\"field\": \"pct\", \"type\": \"nominal\", \"title\": null, \"scale\": {\"domain\": [\"p50\", \"p95\", \"p99\"], \"range\": [\"#22c55e\", \"#fbbf24\", \"#ef4444\"]}}}, \"layer\": [{\"mark\": {\"type\": \"line\", \"point\": false, \"tooltip\": true, \"interpolate\": \"monotone\", \"strokeWidth\": 2}, \"encoding\": {\"y\": {\"field\": \"ms\", \"type\": \"quantitative\", \"title\": \"ms\"}, \"strokeDash\": {\"field\": \"pct\", \"type\": \"nominal\", \"title\": null, \"scale\": {\"domain\": [\"p50\", \"p95\", \"p99\"], \"range\": [[1, 0], [6, 3], [2, 3]]}}}}]}" }, { "title": "Top errors",