Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
973ca8c
feat(pygal): implement scatter-matrix-interactive
github-actions[bot] May 18, 2026
87f7f59
chore(pygal): add metadata for scatter-matrix-interactive
github-actions[bot] May 18, 2026
0b92e41
chore(pygal): update quality score 40 and review feedback for scatter…
github-actions[bot] May 18, 2026
959f732
chore(pygal): update quality score 40 and review feedback for scatter…
github-actions[bot] May 18, 2026
787eefc
chore(pygal): update quality score 40 and review feedback for scatter…
github-actions[bot] May 18, 2026
741111c
chore(pygal): update quality score 40 and review feedback for scatter…
github-actions[bot] May 18, 2026
f248f6f
chore(pygal): update quality score 40 and review feedback for scatter…
github-actions[bot] May 18, 2026
f126033
chore(pygal): update quality score 40 and review feedback for scatter…
github-actions[bot] May 18, 2026
3252c6e
chore(pygal): update quality score 40 and review feedback for scatter…
github-actions[bot] May 18, 2026
682a74a
chore(pygal): update quality score 40 and review feedback for scatter…
github-actions[bot] May 18, 2026
2a3fcc7
chore(pygal): update quality score 40 and review feedback for scatter…
github-actions[bot] May 18, 2026
c22ee06
chore(pygal): update quality score 40 and review feedback for scatter…
github-actions[bot] May 18, 2026
e39d173
chore(pygal): update quality score 68 and review feedback for scatter…
github-actions[bot] May 18, 2026
7f29ea7
Merge branch 'main' into implementation/scatter-matrix-interactive/pygal
MarkusNeusinger May 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions plots/scatter-matrix-interactive/implementations/python/pygal.py
Original file line number Diff line number Diff line change
@@ -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())
242 changes: 242 additions & 0 deletions plots/scatter-matrix-interactive/metadata/python/pygal.yaml
Original file line number Diff line number Diff line change
@@ -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: []
Loading