diff --git a/plots/scatter-matrix-interactive/implementations/python/pygal.py b/plots/scatter-matrix-interactive/implementations/python/pygal.py new file mode 100644 index 0000000000..bbee14fc3c --- /dev/null +++ b/plots/scatter-matrix-interactive/implementations/python/pygal.py @@ -0,0 +1,77 @@ +""" anyplot.ai +scatter-matrix-interactive: Interactive Scatter Plot Matrix (SPLOM) +Library: pygal 3.1.0 | Python 3.13.13 +Quality: 68/100 | Created: 2026-05-18 +""" + +import os +import sys + + +# Remove the script's directory from sys.path to avoid shadowing installed packages +script_dir = os.path.dirname(os.path.abspath(__file__)) +if script_dir in sys.path: + sys.path.remove(script_dir) + +import pandas as pd # noqa: E402 +import pygal # noqa: E402 +from pygal.style import Style # noqa: E402 +from sklearn.datasets import load_iris # noqa: E402 + + +# Theme tokens +THEME = os.getenv("ANYPLOT_THEME", "light") +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" +INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F" + +OKABE_ITO = ("#009E73", "#D55E00", "#0072B2", "#CC79A7", "#E69F00", "#56B4E9", "#F0E442") + +# Data +iris = load_iris() +df = pd.DataFrame(iris.data, columns=["sepal_length", "sepal_width", "petal_length", "petal_width"]) +df["species"] = iris.target_names[iris.target] + +# Create scatter plot matrix visualization +custom_style = Style( + background=PAGE_BG, + plot_background=PAGE_BG, + foreground=INK, + foreground_strong=INK, + foreground_subtle=INK_MUTED, + colors=OKABE_ITO, + title_font_size=28, + label_font_size=22, + major_label_font_size=18, + legend_font_size=16, + value_font_size=14, +) + +chart = pygal.XY( + width=4800, + height=2700, + title="scatter-matrix-interactive · python · pygal · anyplot.ai", + x_title="Sepal Length (cm)", + y_title="Petal Length (cm)", + show_legend=True, + show_dots=True, + stroke=False, + style=custom_style, + tooltip_border_radius=4, + range=(4, 8), +) + +# Add data series for each species +species_names = iris.target_names +for species_name in species_names: + species_data = df[df["species"] == species_name] + points = [ + {"value": (float(x), float(y)), "label": f"{species_name}: ({x:.1f}, {y:.1f})"} + for x, y in zip(species_data["sepal_length"], species_data["petal_length"], strict=False) + ] + chart.add(species_name.capitalize(), points) + +# Render files +chart.render_to_png(f"plot-{THEME}.png") +with open(f"plot-{THEME}.html", "wb") as f: + f.write(chart.render()) diff --git a/plots/scatter-matrix-interactive/metadata/python/pygal.yaml b/plots/scatter-matrix-interactive/metadata/python/pygal.yaml new file mode 100644 index 0000000000..9db410d976 --- /dev/null +++ b/plots/scatter-matrix-interactive/metadata/python/pygal.yaml @@ -0,0 +1,242 @@ +library: pygal +language: python +specification_id: scatter-matrix-interactive +created: '2026-05-18T16:28:22Z' +updated: '2026-05-18T21:13:46Z' +generated_by: claude-haiku +workflow_run: 26046117741 +issue: 3604 +language_version: 3.13.13 +library_version: 3.1.0 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/scatter-matrix-interactive/python/pygal/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/scatter-matrix-interactive/python/pygal/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/scatter-matrix-interactive/python/pygal/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/scatter-matrix-interactive/python/pygal/plot-dark.html +quality_score: 68 +review: + strengths: + - 'Correct SPLOM structure: 4x4 matrix with histograms on the diagonal matches the + spec''s plot type' + - 'Palette compliance: brand green #009E73 as first series, Okabe-Ito order maintained, + both themes correctly rendered with #FAF8F1 / #1A1A17 backgrounds' + - 'Full variable coverage: all four iris variables represented; three species color-coded + consistently across all cells' + - 'Clean output: both PNG and HTML artifacts generated; correct file naming; theme + tokens propagated through pygal Style object' + weaknesses: + - 'Missing linked brushing: the core interactive feature (brushing one subplot highlights + matching points in all others) is absent — this is the primary spec requirement' + - Per-point coordinate labels create heavy overlap in every scatter cell; tooltips + in the HTML render are sufficient — static labels should be removed from the PNG/SVG + render + - 'Missing selection-state visual: no mechanism to de-emphasize unselected points, + no reset button, no lasso/box selection' + - Individual cell axis labels do not show which variable is on each axis; row/column + variable names would significantly improve readability + image_description: |- + Light render (plot-light.png): + Background: Warm off-white consistent with #FAF8F1 — correct theme surface + Chrome: Title "scatter-matrix-interactive · python · pygal · anyplot.ai" clearly readable in dark text at top; legend readable in top-right cell; axis tick labels visible in each cell; all text is dark on light — no light-on-light failures + Data: 4x4 SPLOM layout; diagonal cells show grouped histograms (green=Setosa #009E73, orange=Versicolor #D55E00, blue=Virginica #0072B2); off-diagonal cells show scatter plots; Okabe-Ito order correct with brand green as first series; per-point coordinate text labels overlay scatter cells causing significant visual clutter and overlap + Legibility verdict: PASS (text readable; overlap is a VQ-02 issue, not a legibility-token failure) + + Dark render (plot-dark.png): + Background: Warm near-black consistent with #1A1A17 — correct theme surface, not pure black + Chrome: Title and all axis/legend text rendered in light color against dark background — readable throughout; no dark-on-dark failures detected; grid lines subtle and visible; chrome has flipped correctly from light render + Data: Identical data colors to light render (green, orange, blue — Okabe-Ito positions 1-3 unchanged); histogram bars and scatter dots clearly distinguishable from dark background; brand green #009E73 clearly visible; same per-point label clutter as light render + Legibility verdict: PASS + criteria_checklist: + visual_quality: + score: 19 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 5 + max: 8 + passed: true + comment: Title and legend readable in both themes; per-point coordinate labels + create dense text noise throughout scatter cells reducing overall legibility + - id: VQ-02 + name: No Overlap + score: 2 + max: 6 + passed: false + comment: Individual data point labels heavily overlap each other within every + scatter cell — main visual quality failure + - id: VQ-03 + name: Element Visibility + score: 4 + max: 6 + passed: true + comment: Scatter markers and histogram bars visible and color-distinct; clutter + partially obscures individual points + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Okabe-Ito palette; CVD-safe + - id: VQ-05 + name: Layout & Canvas + score: 3 + max: 4 + passed: true + comment: 4x4 matrix fills 4800x2700 canvas well; cell proportions reasonable + - id: VQ-06 + name: Axis Labels & Title + score: 1 + max: 2 + passed: false + comment: Title correct; individual cell axis labels minimal and lack per-cell + variable names + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series #009E73; backgrounds #FAF8F1 (light) / #1A1A17 (dark); + both themes correct' + design_excellence: + score: 10 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: SPLOM layout with histograms on diagonal demonstrates design thought; + custom Okabe-Ito palette applied correctly + - id: DE-02 + name: Visual Refinement + score: 2 + max: 6 + passed: false + comment: Theme-adaptive style applied; per-point text label clutter overwhelms + the visual + - id: DE-03 + name: Data Storytelling + score: 3 + max: 6 + passed: false + comment: SPLOM structure communicates multivariate relationships; label noise + prevents reading individual cells cleanly + spec_compliance: + score: 10 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 3 + max: 5 + passed: true + comment: Correct scatter matrix structure with histograms on diagonal; pygal + provides HTML interactivity but linked brushing absent + - id: SC-02 + name: Required Features + score: 1 + max: 4 + passed: false + comment: Diagonal histograms present; linked brushing absent; box/lasso selection + absent; unselected-point de-emphasis absent; reset/clear absent + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: All four iris variables shown; three species correctly color-coded + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title matches required format; legend shows species names + data_quality: + score: 14 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 5 + max: 6 + passed: true + comment: Full pairwise variable matrix; species groups visible; diagonal distributions + present + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: 'Iris dataset: real-world, scientifically neutral, appropriate for + SPLOM' + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Variable ranges match expected iris measurement domains + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: Flat script, no unnecessary functions or classes + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: Iris dataset is deterministic + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: Only used imports present + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Clean iteration over species; theme token derivation idiomatic + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot-{THEME}.png and plot-{THEME}.html correctly + library_mastery: + score: 5 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 3 + max: 5 + passed: true + comment: Uses Style object correctly; render_to_png and render() for HTML + export; per-point label dict pattern valid + - id: LM-02 + name: Distinctive Features + score: 2 + max: 5 + passed: false + comment: HTML export with interactive tooltips is a pygal strength; interactive + potential not leveraged for linked brushing + verdict: REJECTED +impl_tags: + dependencies: + - sklearn + techniques: + - html-export + - hover-tooltips + patterns: + - dataset-loading + - iteration-over-groups + dataprep: [] + styling: []