diff --git a/plots/swarm-basic/implementations/javascript/muix.tsx b/plots/swarm-basic/implementations/javascript/muix.tsx new file mode 100644 index 0000000000..33b9f23db8 --- /dev/null +++ b/plots/swarm-basic/implementations/javascript/muix.tsx @@ -0,0 +1,202 @@ +// anyplot.ai +// swarm-basic: Basic Swarm Plot +// Library: muix 7.29.1 | JavaScript 22.23.1 +// Quality: 90/100 | Created: 2026-07-26 +//# anyplot-orientation: landscape +// anyplot.ai +// swarm-basic: Basic Swarm Plot +// Library: MUI X Charts | React | Node 22 +// License: @mui/x-charts — MIT (community). Pro/Premium are out of scope. +// Quality: pending | Created: 2026-07-26 + +import { ChartContainer } from "@mui/x-charts/ChartContainer"; +import { ChartsXAxis } from "@mui/x-charts/ChartsXAxis"; +import { ChartsYAxis } from "@mui/x-charts/ChartsYAxis"; +import { ChartsGrid } from "@mui/x-charts/ChartsGrid"; +import { ScatterPlot } from "@mui/x-charts/ScatterChart"; +import { useXScale, useYScale } from "@mui/x-charts/hooks"; + +const t = window.ANYPLOT_TOKENS; + +// --- Deterministic PRNG (LCG) + Box-Muller for approx-normal samples -------- +let seed = 42; +function nextUniform() { + seed = (seed * 1664525 + 1013904223) % 4294967296; + return seed / 4294967296; +} +function nextNormal(mean, stdDev) { + const u1 = Math.max(nextUniform(), 1e-9); + const u2 = nextUniform(); + const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); + return mean + z * stdDev; +} + +// --- Data: quarterly performance review scores by department --------------- +const DEPARTMENTS = ["Engineering", "Sales", "Marketing", "Support"]; +const MEANS = [78, 70, 74, 83]; +const STD_DEVS = [8, 12, 9, 6]; +const POINTS_PER_DEPT = 40; + +const rawPoints = DEPARTMENTS.flatMap((department, categoryIndex) => + Array.from({ length: POINTS_PER_DEPT }, () => ({ + department, + categoryIndex, + score: Math.min(99, Math.max(45, nextNormal(MEANS[categoryIndex], STD_DEVS[categoryIndex]))), + })), +); + +const median = (values) => { + const sorted = [...values].sort((a, b) => a - b); + const mid = Math.floor(sorted.length / 2); + return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid]; +}; + +const medianByDept = DEPARTMENTS.map((_, i) => + median(rawPoints.filter((p) => p.categoryIndex === i).map((p) => p.score)), +); + +// --- Layout geometry — must stay in sync with the ChartContainer margin ---- +const MARGIN = { left: 110, right: 60, top: 80, bottom: 100 }; +const SCORE_MIN = 40; +const SCORE_MAX = 100; +const X_MIN = -0.6; +const X_MAX = DEPARTMENTS.length - 1 + 0.6; +const MARKER_SIZE = 6; // circle radius, px +const MARKER_DIAMETER_PX = MARKER_SIZE * 2 + 1; + +// --- Beeswarm packing: spread points horizontally within each department so +// none overlap. Collisions are resolved in on-screen pixels (rather than data +// units) so the spread looks even regardless of the score axis' range. Each +// point keeps its true score on the y-axis; only the x-offset is adjusted. +function layoutSwarm(plotWidthPx, plotHeightPx) { + const pxPerScore = plotHeightPx / (SCORE_MAX - SCORE_MIN); + const pxPerX = plotWidthPx / (X_MAX - X_MIN); + + return DEPARTMENTS.flatMap((department, categoryIndex) => { + const points = rawPoints + .filter((p) => p.categoryIndex === categoryIndex) + .sort((a, b) => a.score - b.score); + + const placed = []; + points.forEach((point) => { + const nearby = placed.filter( + (p) => Math.abs((point.score - p.score) * pxPerScore) < MARKER_DIAMETER_PX, + ); + let offsetPx = 0; + if (nearby.length > 0) { + const step = MARKER_DIAMETER_PX * 0.92; + let k = 0; + let resolved = false; + while (!resolved && k < 200) { + const candidate = k === 0 ? 0 : (k % 2 === 1 ? Math.ceil(k / 2) : -Math.ceil(k / 2)) * step; + if ( + nearby.every( + (p) => Math.hypot(candidate - p.offsetPx, (point.score - p.score) * pxPerScore) >= MARKER_DIAMETER_PX * 0.95, + ) + ) { + offsetPx = candidate; + resolved = true; + } + k += 1; + } + } + placed.push({ ...point, offsetPx }); + }); + + return placed.map((p) => ({ + id: `${department}-${p.score.toFixed(3)}-${p.offsetPx.toFixed(2)}`, + x: categoryIndex + p.offsetPx / pxPerX, + y: p.score, + })); + }); +} + +// Short reference ticks at each department's median score. Rendered inside +// ChartContainer so it can read the live D3 scales. +function MedianTicks() { + const xScale = useXScale(); + const yScale = useYScale(); + const halfWidth = 0.34; + + return ( + + {DEPARTMENTS.map((department, i) => { + const x1 = xScale(i - halfWidth) ?? 0; + const x2 = xScale(i + halfWidth) ?? 0; + const y = yScale(medianByDept[i]) ?? 0; + return ( + + ); + })} + + ); +} + +const TITLE = "swarm-basic · javascript · muix · anyplot.ai"; + +export default function Chart() { + const W = window.ANYPLOT_SIZE.width; + const H = window.ANYPLOT_SIZE.height; + const plotWidthPx = W - MARGIN.left - MARGIN.right; + const plotHeightPx = H - MARGIN.top - MARGIN.bottom; + const scoreData = layoutSwarm(plotWidthPx, plotHeightPx); + + return ( + DEPARTMENTS[Math.round(v)] ?? "", + tickLabelStyle: { fontSize: 15, fill: t.inkSoft }, + label: "Department", + labelStyle: { fontSize: 16, fill: t.ink }, + }, + ]} + yAxis={[ + { + id: "yAxis", + min: SCORE_MIN, + max: SCORE_MAX, + label: "Performance Score", + tickLabelStyle: { fontSize: 15, fill: t.inkSoft }, + labelStyle: { fontSize: 16, fill: t.ink }, + }, + ]} + margin={MARGIN} + > + + + + + + + {TITLE} + + + ); +} diff --git a/plots/swarm-basic/metadata/javascript/muix.yaml b/plots/swarm-basic/metadata/javascript/muix.yaml new file mode 100644 index 0000000000..116f18621b --- /dev/null +++ b/plots/swarm-basic/metadata/javascript/muix.yaml @@ -0,0 +1,255 @@ +library: muix +language: javascript +specification_id: swarm-basic +created: '2026-07-26T07:30:24Z' +updated: '2026-07-26T07:36:06Z' +generated_by: claude-sonnet +workflow_run: 30192673222 +issue: 974 +language_version: 22.23.1 +library_version: 7.29.1 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/javascript/muix/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/javascript/muix/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/javascript/muix/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/javascript/muix/plot-dark.html +quality_score: 90 +review: + strengths: + - 'Genuine beeswarm layout: a pixel-space collision-resolution algorithm spreads + points horizontally so none overlap, matching the spec''s core requirement rather + than faking it with a plain jittered scatter' + - Subtle median reference line per department (drawn via live useXScale/useYScale + hooks) adds a clear, uncluttered point of comparison across groups + - Deterministic LCG + Box-Muller data generation with per-department mean/stddev + produces realistic, varied distributions including visible outliers (e.g. Engineering + ~56.5, Sales ~46.3) + - 'Theme handling is correct in both renders: identical brand-green (#009E73) data + points, correct #FAF8F1 / #1A1A17 backgrounds, and theme-adaptive ink for axis + text and the median line' + - Idiomatic, advanced MUI X composition — ChartContainer + ScatterPlot + ChartsGrid/Axis + components plus useXScale/useYScale to sync a custom SVG overlay to the chart's + live D3 scales, a genuinely MUI X-specific pattern + - Correct title format, single-series legend appropriately omitted, clean KISS-appropriate + code with explicit font sizes throughout + weaknesses: + - 'Design Excellence sits at the default level: a single flat brand-green fill with + no additional visual hierarchy beyond the median tick — e.g. a subtle callout + labeling the best/worst-performing department, or a slightly more refined grid/marker + treatment, would push this from ''well-configured default'' toward genuinely polished' + - Marker radius (6px / MARKER_SIZE) is adequate but on the smaller side for ~40 + points per department at the 3200px canvas — could be nudged up slightly for more + visual presence without reintroducing overlap + image_description: |- + Light render (plot-light.png): + Background: Warm off-white, matches the required #FAF8F1 surface — not pure white. + Chrome: Title "swarm-basic · javascript · muix · anyplot.ai" centered top in dark ink; "Department" (x-axis) and "Performance Score" (y-axis) labels in dark ink; tick labels (department names, 40-100 score ticks) in a slightly softer dark gray; a dark horizontal median-reference line per department; subtle horizontal gridlines. All text is clearly legible against the light background. + Data: All points are solid brand green (#009E73), spread in a beeswarm pattern within each of the 4 department columns (Engineering, Sales, Marketing, Support), packed tightly without overlapping. Distributions visibly differ per department (Sales has the widest spread and lowest median ~69.5; Support is tightest and highest ~84.5), with visible outliers at both tails. + Legibility verdict: PASS + + Dark render (plot-dark.png): + Background: Warm near-black, matches the required #1A1A17 surface — not pure black. + Chrome: Same title, axis labels, and tick labels now rendered in light ink/off-white, fully readable against the dark background — no dark-on-dark text anywhere. The median reference lines render in light gray/white. Gridlines are faint light lines, appropriately subtle. + Data: Points are the identical brand green (#009E73) as the light render — no shift in the data color, only the chrome (background, text, grid) flipped as expected. + Legibility verdict: PASS + criteria_checklist: + visual_quality: + score: 29 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 8 + max: 8 + passed: true + comment: All font sizes explicitly set (title 22, axis labels 16, ticks 15); + readable in both themes with no overflow or clipping + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: Collision-resolution swarm algorithm keeps points touching but never + overlapping; no text overlap anywhere + - id: VQ-03 + name: Element Visibility + score: 5 + max: 6 + passed: true + comment: Markers clearly visible and consistently sized; could be marginally + larger for the ~40-points-per-category density at this canvas size + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Single hue with good contrast against both surfaces, no reliance + on hue-only distinctions + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: Plot fills the canvas well with balanced margins; nothing cut off, + no isolated elements + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: '''Department'' and ''Performance Score'' are descriptive; the metric + is inherently unitless so no units to add' + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series is #009E73, identical across both themes; backgrounds + are the correct theme-adaptive #FAF8F1/#1A1A17' + design_excellence: + score: 12 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 4 + max: 8 + passed: false + comment: Well-configured library default — single flat color, no additional + palette or gradient work + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: false + comment: Subtle grid, L-shaped spines, generous whitespace — good refinement + but not maximally polished + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Median reference line per department creates a clear, immediate cross-group + comparison + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Genuine beeswarm/swarm plot via custom horizontal-offset collision + resolution, not a plain jittered scatter + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Consistent point sizes, no excessive overlap, median markers, clear + spacing between category groups — all present + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: Category on x-axis, continuous value on y-axis, axes show the full + data range + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title format is exactly correct; single-series legend appropriately + omitted + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: Distinct per-department distributions (mean/stddev vary) with visible + outliers at both tails + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Quarterly performance review scores by department — neutral, comprehensible + business scenario + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Score range (45-99, clamped) and department-level variation are realistic + for a performance metric + code_quality: + score: 9 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 2 + max: 3 + passed: true + comment: Helper functions are necessary for the swarm layout algorithm and + a React component export; appropriately minimal beyond that + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: Fixed-seed LCG (seed=42) for fully deterministic output + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: Only the MUI X components and hooks actually used are imported + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: No fake UI/functionality; complexity is justified by implementing + a swarm layout the library doesn't provide natively + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Default-exports the component per the harness contract; current MUI + X API (ChartContainer/hooks) + library_mastery: + score: 10 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 5 + max: 5 + passed: true + comment: Composable ChartContainer + ScatterPlot + ChartsGrid/Axis pattern, + the library's recommended advanced composition + - id: LM-02 + name: Distinctive Features + score: 5 + max: 5 + passed: true + comment: useXScale/useYScale hooks drive a custom SVG overlay synced to the + chart's live D3 scales — a genuinely MUI X-specific technique + verdict: APPROVED +impl_tags: + dependencies: [] + techniques: + - annotations + patterns: + - data-generation + - iteration-over-groups + dataprep: [] + styling: + - grid-styling