Skip to content

Commit 0d72a4b

Browse files
feat(muix): add MUI X Charts (community, React/TSX) as a JavaScript entry (#8517)
Closes #8243. Adds the **community `@mui/x-charts`** package (MIT) as the catalog's **first React (`framework: react`) and first `.tsx`** library — the Tier-3 / Phase-4 entry from `docs/concepts/library-expansion.md`, pulled forward to validate the React/TSX render path end to end. `language_id` stays `javascript`: React is a runtime constraint, not a language (§6). ## The new surface: the harness `framework: react` branch The framework-agnostic JS libs (Chart.js/D3/ECharts/Highcharts) load a UMD global and draw imperatively. MUI X is different and gets its own branch in `automation/js-render/render.mjs`: - the `.tsx` snippet **default-exports a React component**; - the harness **esbuild-bundles** it with `react` / `react-dom` / `@mui/x-charts` / `@mui/material` / `@emotion`, wraps it in a **theme-aware MUI `ThemeProvider`** (mapped onto `ANYPLOT_TOKENS`), mounts it via `createRoot`, and Playwright-screenshots `#container` at the **exact** canvas size (3200×1800 / 2400×2400) + emits the self-contained interactive HTML — the same contract as the UMD libs; - it emulates **`prefers-reduced-motion: reduce`** so MUI X skips entrance animation and the screenshot is a deterministic *final* frame. Validated end-to-end locally with the real harness (Playwright + Chromium): light & dark, landscape **3200×1800** and square **2400×2400**, exact pixels from the PNG IHDR, first series in brand green `#009E73`, theme-adaptive chrome, no clipped legends. `setup-node` now smoke-tests the React path too (the sibling of the existing chartjs smoke test). ## What changed **Runtime** — `package.json` / lockfile pin `react@18.3.1`, `react-dom@18.3.1`, `@mui/x-charts@7.29.1`, `@mui/material@5.18.0`, `@emotion@11`. `render.mjs` gains the esbuild React branch. `npm ci --dry-run` clean. **Registry & backend** — `core/constants.py`: `muix` (`javascript`, `framework: react`, `.tsx` override), added to `INTERACTIVE_LIBRARIES`. `/libraries` surfaces `framework`. The debug matrix now builds per-library scores via a **registry spread** (also fixes the pre-existing bug where chartjs/d3/echarts columns were silently dropped). `seo` + `insights` counts and display names. **No alembic migration needed** — the `framework` column already exists and a brand-new row inserts via the existing `on_conflict_do_nothing` seed. **Frontend** — `LIB_TO_FRAMEWORK` + per-library extension override (`muix → tsx`); TSX syntax highlighting (`CodeHighlighter` + d.ts shim); `LibraryCard` React badge + MIT note; `LibrariesPage` generic **"React-compatible" filter** (built off `LIB_TO_FRAMEWORK` so Recharts/Vue/etc. slot in with no UI change); `PlotOfTheDay(Terminal)` `.tsx` runner; library-count meta copy bumped **14 → 15**. **Prompts / workflows / docs** — new `prompts/library/muix.md`; `muix` arms in the impl-generate/repair/review/merge case tables + workflow choices + `ALL_LIBRARIES`; canvas-gate hint; `plot-generator.md` / `impl-*-claude.md` updated; `library-expansion.md` §1/§8/§9, `project-guide.md`, `prompts/README.md`, `README.md`. ### Community-only hard rule (emphasized per request) Snippets use the **MIT community `@mui/x-charts` surface only** — `@mui/x-charts-pro` / Premium are **forbidden** (only the community package is installed, so a Pro import fails the build). `muix.md` and `plot-generator.md` state this prominently, while explicitly allowing the LLM to add richer chart features when they serve the spec, as long as every one comes from the community surface. ## Tests - `uv run pytest tests/unit` — **1496 passed** (new: muix registry assertions, `.tsx` discovery, framework checks). - Frontend `yarn vitest run` — **536 passed** (new: tsx-highlighting case, `?language=javascript` fetch, React-filter test, debug muix column); `yarn tsc --noEmit` + `yarn lint` clean (no TS7016 carry-forward). - `ruff check` / `ruff format --check` clean; workflow YAML validated. Integration tests (DB-backed) run in CI; the `/libraries` shape change only **adds** `framework`, which is safe against the existing fixtures. https://claude.ai/code/session_01HEs4b7jkqVUSTMt8mAo7in --- _Generated by [Claude Code](https://claude.ai/code/session_01HEs4b7jkqVUSTMt8mAo7in)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1e0cced commit 0d72a4b

41 files changed

Lines changed: 2572 additions & 228 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/actions/setup-node/action.yml

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
name: "Setup Node + JS render harness"
22
description: >-
33
Installs Node.js, the pinned JavaScript charting toolchain (Chart.js, D3,
4-
ECharts) and the headless-browser render harness (Playwright + Chromium) used
5-
by anyplot's JavaScript implementations. The toolchain is restored exactly
6-
from the committed top-level package-lock.json (`npm ci`) for reproducibility —
7-
the JS sibling of setup-r's Posit snapshot and setup-julia's Manifest.toml.
4+
ECharts, Highcharts, plus the React stack for MUI X — react, react-dom, @mui)
5+
and the headless-browser render harness (Playwright + Chromium) used by
6+
anyplot's JavaScript implementations. The toolchain is restored exactly from
7+
the committed top-level package-lock.json (`npm ci`) for reproducibility — the
8+
JS sibling of setup-r's Posit snapshot and setup-julia's Manifest.toml.
89
inputs:
910
node-version:
1011
description: "Node.js version to install"
@@ -63,3 +64,46 @@ runs:
6364
if (w !== 3200 || h !== 1800) { console.error(`smoke-test PNG is ${w}x${h}, expected 3200x1800`); process.exit(1); }
6465
console.log(`ok: ${process.argv[1]} (${w}x${h}, ${b.length} bytes)`);
6566
' "$PNG"
67+
68+
- name: Smoke-test the React (MUI X) render path
69+
# The framework=react branch is the only one that esbuild-bundles the
70+
# snippet (react + react-dom + @mui/x-charts) and mounts it in a MUI
71+
# ThemeProvider — a different code path from the UMD-global libs above.
72+
# Render a minimal default-exported @mui/x-charts component to guard it end
73+
# to end (esbuild bundle → Playwright → exact-pixel PNG + interactive HTML),
74+
# the React sibling of the chartjs smoke test.
75+
shell: bash
76+
run: |
77+
set -euo pipefail
78+
TMP="$(mktemp -d)"
79+
cat > "$TMP/muix.tsx" <<'TSX'
80+
import { BarChart } from "@mui/x-charts/BarChart";
81+
const t = window.ANYPLOT_TOKENS;
82+
export default function Chart() {
83+
return (
84+
<BarChart
85+
width={window.ANYPLOT_SIZE.width}
86+
height={window.ANYPLOT_SIZE.height}
87+
colors={t.palette}
88+
skipAnimation
89+
xAxis={[{ scaleType: "band", data: ["a", "b", "c"] }]}
90+
series={[{ data: [3, 1, 2], label: "demo" }]}
91+
/>
92+
);
93+
}
94+
TSX
95+
( cd "$TMP" && ANYPLOT_THEME=dark node "$GITHUB_WORKSPACE/automation/js-render/render.mjs" muix.tsx )
96+
PNG="$TMP/plot-dark.png"
97+
test -f "$PNG"
98+
test -s "$PNG"
99+
# The harness also writes the self-contained interactive page for the
100+
# detail view — assert it landed (MUI X is in INTERACTIVE_LIBRARIES).
101+
test -s "$TMP/plot-dark.html"
102+
# Confirm exact landscape pixels (3200×1800) straight from the PNG IHDR.
103+
node -e '
104+
const fs = require("fs");
105+
const b = fs.readFileSync(process.argv[1]);
106+
const w = b.readUInt32BE(16), h = b.readUInt32BE(20);
107+
if (w !== 3200 || h !== 1800) { console.error(`MUI X smoke-test PNG is ${w}x${h}, expected 3200x1800`); process.exit(1); }
108+
console.log(`ok: react path ${process.argv[1]} (${w}x${h}, ${b.length} bytes)`);
109+
' "$PNG"

.github/workflows/bulk-generate.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ on:
3333
- chartjs
3434
- d3
3535
- echarts
36+
- muix
3637
dry_run:
3738
description: "List what would be generated without executing"
3839
type: boolean
@@ -57,7 +58,7 @@ on:
5758
default: '{}'
5859

5960
env:
60-
ALL_LIBRARIES: "matplotlib seaborn plotly bokeh altair plotnine pygal highcharts letsplot ggplot2 makie chartjs d3 echarts"
61+
ALL_LIBRARIES: "matplotlib seaborn plotly bokeh altair plotnine pygal highcharts letsplot ggplot2 makie chartjs d3 echarts muix"
6162

6263
# Serialise bulk-generate runs. Each run paces its own dispatches with
6364
# `pace_seconds`; letting two runs overlap would interleave their

.github/workflows/impl-generate.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ on:
3434
- chartjs
3535
- d3
3636
- echarts
37+
- muix
3738
issue_number:
3839
description: "Issue number (optional, for tracking)"
3940
required: false
@@ -131,6 +132,12 @@ jobs:
131132
LANGUAGE="javascript"
132133
EXT=".js"
133134
;;
135+
muix)
136+
# MUI X — JavaScript with framework=react, authored as TSX and
137+
# bundled through the render harness's esbuild React branch.
138+
LANGUAGE="javascript"
139+
EXT=".tsx"
140+
;;
134141
*)
135142
LANGUAGE="python"
136143
EXT=".py"
@@ -601,12 +608,16 @@ jobs:
601608
;;
602609
esac
603610
elif [ "$LANGUAGE" = "javascript" ]; then
604-
# Catalogue id `chartjs` maps to the npm package `chart.js`; `d3` and
611+
# Catalogue id `chartjs` maps to the npm package `chart.js` and
612+
# `muix` to the scoped community package `@mui/x-charts`; `d3` and
605613
# `echarts` match their npm names directly.
606614
case "$LIBRARY" in
607615
chartjs)
608616
LIBRARY_VERSION=$(get_npm_version "chart.js")
609617
;;
618+
muix)
619+
LIBRARY_VERSION=$(get_npm_version "@mui/x-charts")
620+
;;
610621
*)
611622
LIBRARY_VERSION=$(get_npm_version "$LIBRARY")
612623
;;

.github/workflows/impl-merge.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ jobs:
117117
LANGUAGE="javascript"
118118
EXT=".js"
119119
;;
120+
muix)
121+
# MUI X — JavaScript with framework=react, authored as TSX and
122+
# bundled through the render harness's esbuild React branch.
123+
LANGUAGE="javascript"
124+
EXT=".tsx"
125+
;;
120126
*)
121127
LANGUAGE="python"
122128
EXT=".py"

.github/workflows/impl-repair.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ jobs:
8383
LANGUAGE="javascript"
8484
EXT=".js"
8585
;;
86+
muix)
87+
# MUI X — JavaScript with framework=react, authored as TSX and
88+
# bundled through the render harness's esbuild React branch.
89+
LANGUAGE="javascript"
90+
EXT=".tsx"
91+
;;
8692
*)
8793
LANGUAGE="python"
8894
EXT=".py"

.github/workflows/impl-review.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ jobs:
113113
LANGUAGE="javascript"
114114
EXT=".js"
115115
;;
116+
muix)
117+
# MUI X — JavaScript with framework=react, authored as TSX and
118+
# bundled through the render harness's esbuild React branch.
119+
LANGUAGE="javascript"
120+
EXT=".tsx"
121+
;;
116122
*)
117123
LANGUAGE="python"
118124
EXT=".py"
@@ -275,6 +281,7 @@ jobs:
275281
"chartjs": "The harness owns exact pixels (Playwright deviceScaleFactor 2 over a fixed mount). Drift means the snippet forced its own canvas size: set `responsive: true` + `maintainAspectRatio: false` and let the canvas fill `#container` — do NOT set canvas width/height. Use `//# anyplot-orientation: square` only for square specs.",
276282
"d3": "The harness owns exact pixels (Playwright deviceScaleFactor 2 over a fixed mount). Size the `<svg>` to `window.ANYPLOT_SIZE` (1600×900 landscape / 1200×1200 square) — never hard-code other dimensions. Use `//# anyplot-orientation: square` only for square specs.",
277283
"echarts": "The harness owns exact pixels (Playwright deviceScaleFactor 2 over a fixed mount). Call `echarts.init(document.getElementById('container'))` with no explicit width/height so it fills the mount; do not pass a `devicePixelRatio` (the page already runs at 2×). Use `//# anyplot-orientation: square` only for square specs.",
284+
"muix": "The harness owns exact pixels (Playwright deviceScaleFactor 2 over a fixed mount via a MUI ThemeProvider). Size the chart with `width={window.ANYPLOT_SIZE.width}` / `height={window.ANYPLOT_SIZE.height}` (1600×900 landscape / 1200×1200 square) — never hard-code other dimensions. Use `//# anyplot-orientation: square` only for square specs.",
278285
}
279286
cause = causes.get(LIBRARY, f"Review `prompts/library/{LIBRARY}.md` 'Canvas — hard rule' section.")
280287

README.md

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
## What is anyplot?
1616

1717
**anyplot** is an AI-powered platform for data visualization that automatically discovers, generates, tests, and
18-
maintains plotting examples. Browse hundreds of plots across 11 major visualization libraries in Python, R, and Julia
19-
matplotlib, seaborn, plotly, bokeh, altair, plotnine, pygal, highcharts, lets-plot, ggplot2, and Makie.jl — with an
20-
architecture ready to welcome additional ecosystems over time.
18+
maintains plotting examples. Browse hundreds of plots across 15 major visualization libraries in Python, R, Julia, and
19+
JavaScript — matplotlib, seaborn, plotly, bokeh, altair, plotnine, pygal, lets-plot, ggplot2, Makie.jl, Chart.js, D3.js,
20+
ECharts, Highcharts, and MUI X Charts (React) — with an architecture ready to welcome additional ecosystems over time.
2121

2222
**Community-driven, AI-maintained** - Propose plot ideas via GitHub Issues, AI generates the code, automated quality
2323
checks ensure excellence. Zero manual coding required.
@@ -38,22 +38,31 @@ checks ensure excellence. Zero manual coding required.
3838
## Architecture
3939

4040
**Specification-first design**: Every plot starts as a Markdown spec (library-agnostic), then AI generates
41-
implementations for all 11 supported libraries across Python, R, and Julia.
41+
implementations for all 15 supported libraries across Python, R, Julia, and JavaScript.
4242

4343
```
4444
plots/scatter-basic/
4545
├── specification.md # Library-agnostic specification
4646
├── specification.yaml # Tags, created, issue, suggested
4747
├── metadata/ # Per-library metadata (quality scores, preview URLs)
48-
│ └── python/
49-
│ ├── matplotlib.yaml
50-
│ └── ...
51-
└── implementations/
52-
└── python/
53-
├── matplotlib.py
54-
├── seaborn.py
55-
├── plotly.py
56-
└── ... (6 more)
48+
│ ├── python/
49+
│ │ ├── matplotlib.yaml
50+
│ │ └── ...
51+
│ └── javascript/
52+
│ └── muix.yaml
53+
└── implementations/ # Grouped by language; one file per library
54+
├── python/
55+
│ ├── matplotlib.py
56+
│ ├── seaborn.py
57+
│ └── ... (6 more)
58+
├── r/ggplot2.R
59+
├── julia/makie.jl
60+
└── javascript/
61+
├── chartjs.js # framework-agnostic JS libs → .js
62+
├── d3.js
63+
├── echarts.js
64+
├── highcharts.js
65+
└── muix.tsx # MUI X — React, authored as .tsx
5766
```
5867

5968
**Issue-based workflow**: GitHub Issues as state machine for plot lifecycle. Status tracked via live-updating table (no sub-issues). Each library generates in parallel, creating PRs to a feature branch.
@@ -70,9 +79,10 @@ See [docs/reference/](docs/reference/) for details.
7079

7180
**Frontend**: React 19 • Vite • TypeScript • MUI
7281

73-
**Plotting (Python)**: matplotlib • seaborn • plotly • bokeh • altair • plotnine • pygal • highcharts • lets-plot
82+
**Plotting (Python)**: matplotlib • seaborn • plotly • bokeh • altair • plotnine • pygal • lets-plot
7483
**Plotting (R)**: ggplot2
7584
**Plotting (Julia)**: Makie.jl
85+
**Plotting (JavaScript)**: Chart.js • D3.js • ECharts • Highcharts • MUI X Charts (React)
7686

7787
**Infrastructure**: Google Cloud Run • Cloud SQL • Cloud Storage
7888

agentic/docs/project-guide.md

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@ This document contains comprehensive project documentation for AI agents working
66

77
**anyplot** is an AI-powered platform for Python data visualization that automatically discovers, generates, tests, and maintains plotting examples. The platform is specification-driven: every plot starts as a library-agnostic Markdown spec, then AI generates implementations for all supported libraries.
88

9-
**Supported Libraries** (10 total):
9+
**Supported Libraries** (15 total):
1010

11-
*Python (9):*
11+
*Python (8):*
1212
- **matplotlib** - The classic standard, maximum flexibility
1313
- **seaborn** - Statistical visualizations, beautiful defaults
1414
- **plotly** - Interactive web plots, dashboards, 3D
1515
- **bokeh** - Interactive, streaming data, large datasets
1616
- **altair** - Declarative/Vega-Lite, elegant exploration
1717
- **plotnine** - ggplot2 syntax for R users
1818
- **pygal** - Minimalistic SVG charts
19-
- **highcharts** - Interactive web charts, stock charts (requires license for commercial use)
2019
- **lets-plot** - ggplot2 grammar of graphics by JetBrains, interactive
2120

2221
*R (1):*
@@ -25,6 +24,13 @@ This document contains comprehensive project documentation for AI agents working
2524
*Julia (1):*
2625
- **Makie.jl** - High-performance Julia visualization. CairoMakie ships publication-quality static PNG via a pure-Cairo backend.
2726

27+
*JavaScript (5):* — rendered through the Node 22 + Playwright browser harness (`automation/js-render/render.mjs`)
28+
- **Chart.js** - Simple, flexible HTML5-canvas charts; the popular JS default
29+
- **D3.js** - Data-driven SVG, low-level and maximally flexible
30+
- **Apache ECharts** - Powerful interactive charts, vast catalog
31+
- **highcharts** - Industry-standard SVG charts (commercial license, free for non-commercial use); migrated Python → JavaScript in Phase 2
32+
- **MUI X Charts** - Charts for the MUI / Material UI **React** ecosystem (`framework: react`, authored as `.tsx`). Community `@mui/x-charts` (MIT) only; Pro/Premium out of scope. The first React entry — bundled via the harness's esbuild React branch.
33+
2834
**Core Principle**: Community proposes plot ideas via GitHub Issues -> AI generates code -> AI quality review -> Deployed.
2935

3036
## Essential Commands
@@ -125,22 +131,23 @@ Everything for one plot type lives in a single directory:
125131

126132
```
127133
plots/{specification-id}/
128-
├── specification.md # Description, Applications, Data, Notes
129-
├── specification.yaml # Spec-level metadata (tags, created, issue, suggested, updates)
130-
├── metadata/ # Per-library metadata (one file per library)
131-
│ ├── matplotlib.yaml
132-
│ ├── seaborn.yaml
133-
│ └── ...
134-
└── implementations/ # Library implementations
135-
├── matplotlib.py
136-
├── seaborn.py
137-
├── plotly.py
138-
├── bokeh.py
139-
├── altair.py
140-
├── plotnine.py
141-
├── pygal.py
142-
├── highcharts.py
143-
└── letsplot.py
134+
├── specification.md # Description, Applications, Data, Notes
135+
├── specification.yaml # Spec-level metadata (tags, created, issue, suggested, updates)
136+
├── metadata/ # Per-library metadata, grouped by language
137+
│ ├── python/{matplotlib,seaborn,…}.yaml
138+
│ ├── r/ggplot2.yaml
139+
│ ├── julia/makie.yaml
140+
│ └── javascript/{chartjs,d3,echarts,highcharts,muix}.yaml
141+
└── implementations/ # Library implementations, grouped by language
142+
├── python/{matplotlib,seaborn,plotly,bokeh,altair,plotnine,pygal,letsplot}.py
143+
├── r/ggplot2.R
144+
├── julia/makie.jl
145+
└── javascript/
146+
├── chartjs.js # framework-agnostic JS libs are .js
147+
├── d3.js
148+
├── echarts.js
149+
├── highcharts.js
150+
└── muix.tsx # MUI X — React, authored as .tsx
144151
```
145152

146153
Example: `plots/scatter-basic/` contains everything for the basic scatter plot.
@@ -329,14 +336,16 @@ gs://anyplot-images/
329336
2. `impl-review.yml` reads from staging for AI evaluation
330337
3. `impl-merge.yml` promotes staging -> production when PR merges to main
331338

332-
**Interactive libraries** (generate `.html`): plotly, bokeh, altair, highcharts, pygal, letsplot
339+
**Interactive libraries** (generate `.html`): plotly, bokeh, altair, highcharts, pygal, letsplot, chartjs, d3, echarts, muix
333340
**PNG only**: matplotlib, seaborn, plotnine, ggplot2, makie
334341

335342
## Tech Stack
336343

337344
- **Backend**: FastAPI, SQLAlchemy (async), PostgreSQL, Python 3.13+
338345
- **Frontend**: React 19, Vite 8, TypeScript 6, MUI 9
339-
- **Plotting**: matplotlib, seaborn, plotly, bokeh, altair, plotnine, pygal, highcharts, lets-plot, ggplot2, Makie.jl
346+
- **Plotting (Python)**: matplotlib, seaborn, plotly, bokeh, altair, plotnine, pygal, lets-plot
347+
- **Plotting (R)**: ggplot2 · **Plotting (Julia)**: Makie.jl
348+
- **Plotting (JavaScript)**: Chart.js, D3.js, ECharts, Highcharts, MUI X Charts (React)
340349
- **Package Manager**: uv (fast Python installer)
341350
- **Infrastructure**: Google Cloud Run, Cloud SQL, Cloud Storage
342351
- **Automation**: GitHub Actions

api/routers/debug.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,22 @@ class SpecStatusItem(BaseModel):
111111
title: str
112112
updated: str | None
113113
avg_score: float | None = None
114-
# Library scores - None means no implementation
114+
# Library scores - None means no implementation. One field per library in
115+
# SUPPORTED_LIBRARIES (the values are populated via a dict-spread below, so
116+
# this list must stay in sync with the registry — every supported library,
117+
# including the JavaScript ones and the React muix entry, needs a field here
118+
# or its column would silently disappear from the debug matrix).
115119
altair: float | None = None
116120
bokeh: float | None = None
121+
chartjs: float | None = None
122+
d3: float | None = None
123+
echarts: float | None = None
117124
ggplot2: float | None = None
118125
highcharts: float | None = None
119126
letsplot: float | None = None
120127
makie: float | None = None
121128
matplotlib: float | None = None
129+
muix: float | None = None
122130
plotly: float | None = None
123131
plotnine: float | None = None
124132
pygal: float | None = None
@@ -311,17 +319,10 @@ async def get_debug_status(request: Request, db: AsyncSession = Depends(require_
311319
title=spec.title,
312320
updated=most_recent.isoformat() if most_recent else None,
313321
avg_score=round(avg_score, 1) if avg_score else None,
314-
altair=spec_scores.get("altair"),
315-
bokeh=spec_scores.get("bokeh"),
316-
ggplot2=spec_scores.get("ggplot2"),
317-
highcharts=spec_scores.get("highcharts"),
318-
letsplot=spec_scores.get("letsplot"),
319-
makie=spec_scores.get("makie"),
320-
matplotlib=spec_scores.get("matplotlib"),
321-
plotly=spec_scores.get("plotly"),
322-
plotnine=spec_scores.get("plotnine"),
323-
pygal=spec_scores.get("pygal"),
324-
seaborn=spec_scores.get("seaborn"),
322+
# One score field per supported library — spread so the set can
323+
# never drift out of sync with the registry (the old hand-listed
324+
# kwargs silently dropped chartjs/d3/echarts).
325+
**{lib: spec_scores.get(lib) for lib in SUPPORTED_LIBRARIES},
325326
)
326327
)
327328

api/routers/insights.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,15 @@ class RelatedSpecsResponse(BaseModel):
180180
LIBRARY_NAMES = {
181181
"altair": "Altair",
182182
"bokeh": "Bokeh",
183+
"chartjs": "Chart.js",
184+
"d3": "D3.js",
185+
"echarts": "Apache ECharts",
186+
"ggplot2": "ggplot2",
183187
"highcharts": "Highcharts",
184188
"letsplot": "lets-plot",
189+
"makie": "Makie.jl",
185190
"matplotlib": "Matplotlib",
191+
"muix": "MUI X Charts",
186192
"plotly": "Plotly",
187193
"plotnine": "plotnine",
188194
"pygal": "Pygal",

0 commit comments

Comments
 (0)