diff --git a/plots/scatter-basic/implementations/python/plotly.py b/plots/scatter-basic/implementations/python/plotly.py
index e3e96ec4b5..d818bbb01e 100644
--- a/plots/scatter-basic/implementations/python/plotly.py
+++ b/plots/scatter-basic/implementations/python/plotly.py
@@ -1,146 +1,83 @@
-""" pyplots.ai
+""" anyplot.ai
scatter-basic: Basic Scatter Plot
-Library: plotly 6.5.2 | Python 3.14
-Quality: 92/100 | Created: 2025-12-22
+Library: plotly 6.7.0 | Python 3.14.4
+Quality: 86/100 | Created: 2026-04-23
"""
+import os
+
import numpy as np
import plotly.graph_objects as go
-# Data: Study hours vs exam scores (realistic educational context)
+# Theme tokens (see prompts/default-style-guide.md "Theme-adaptive Chrome")
+THEME = os.getenv("ANYPLOT_THEME", "light")
+PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
+ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
+INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
+INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
+GRID = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)"
+BRAND = "#009E73" # Okabe-Ito position 1 — always first series
+
+# Data: study hours vs exam scores, moderate positive correlation
np.random.seed(42)
-n_students = 120
+n_students = 160
study_hours = np.random.uniform(1, 10, n_students)
-base_score = 45 + study_hours * 5
-exam_scores = base_score + np.random.randn(n_students) * 8
+exam_scores = 45 + study_hours * 5 + np.random.randn(n_students) * 8
exam_scores = np.clip(exam_scores, 0, 100)
-# Inject outliers to show scatter plot's outlier-detection value
-study_hours[0], exam_scores[0] = 8.5, 52.0 # High effort, low result
-study_hours[1], exam_scores[1] = 2.0, 78.0 # Low effort, high result
-study_hours[2], exam_scores[2] = 9.2, 55.0 # Another underperformer
-
-# Linear regression for trend line
-coeffs = np.polyfit(study_hours, exam_scores, 1)
-trend_x = np.array([0.5, 10.5])
-trend_y = np.polyval(coeffs, trend_x)
-r_value = np.corrcoef(study_hours, exam_scores)[0, 1]
-
-# Color palette
-python_blue = "#306998"
-accent_orange = "#D4782F"
-
-fig = go.Figure()
-
-# Trend line (behind markers)
-fig.add_trace(
- go.Scatter(
- x=trend_x,
- y=trend_y,
- mode="lines",
- line={"color": "rgba(48, 105, 152, 0.4)", "width": 2.5, "dash": "dash"},
- showlegend=False,
- hoverinfo="skip",
- )
-)
-
-# Main scatter — size 11 avoids congestion in dense regions
-fig.add_trace(
+# Plot
+fig = go.Figure(
go.Scatter(
x=study_hours,
y=exam_scores,
mode="markers",
- marker={"size": 11, "color": python_blue, "opacity": 0.6, "line": {"width": 1.2, "color": "white"}},
+ marker={"size": 13, "color": BRAND, "opacity": 0.7, "line": {"width": 1.2, "color": PAGE_BG}},
+ hovertemplate="Study: %{x:.1f} h
Score: %{y:.1f}%",
showlegend=False,
- hovertemplate="Student
Study: %{x:.1f} h
Score: %{y:.1f}%",
)
)
-# Outlier diamonds
-fig.add_trace(
- go.Scatter(
- x=[8.5, 2.0, 9.2],
- y=[52.0, 78.0, 55.0],
- mode="markers",
- marker={
- "size": 15,
- "color": accent_orange,
- "opacity": 0.9,
- "line": {"width": 2, "color": "white"},
- "symbol": "diamond",
- },
- showlegend=False,
- hoverinfo="skip",
- )
-)
-
-# Annotations — each outlier gets its own label for clarity
-ann_base = {
- "showarrow": True,
- "arrowhead": 2,
- "arrowsize": 1.2,
- "arrowwidth": 2,
- "arrowcolor": accent_orange,
- "align": "center",
- "font": {"size": 16, "color": accent_orange, "family": "Arial, sans-serif"},
- "bgcolor": "rgba(255,255,255,0.85)",
- "bordercolor": accent_orange,
- "borderwidth": 1.5,
- "borderpad": 5,
-}
-annotations = [
- {**ann_base, "x": 2.0, "y": 78.0, "text": "Low effort,
high score", "ax": -75, "ay": -45},
- {**ann_base, "x": 8.5, "y": 52.0, "text": "High effort,
low score", "ax": 80, "ay": 40},
- {**ann_base, "x": 9.2, "y": 55.0, "text": "Underperformer", "ax": 75, "ay": -35},
- # Correlation coefficient near trend line
- {
- "x": 8.5,
- "y": np.polyval(coeffs, 8.5) + 4,
- "text": f"r = {r_value:.2f}",
- "showarrow": False,
- "bgcolor": "rgba(255,255,255,0.8)",
- "borderpad": 4,
- "font": {"size": 17, "color": python_blue, "family": "Arial, sans-serif"},
- },
-]
-
+# Style
fig.update_layout(
title={
- "text": "scatter-basic · plotly · pyplots.ai",
- "font": {"size": 28, "color": "#2C3E50", "family": "Arial Black, Arial, sans-serif"},
+ "text": "scatter-basic · plotly · anyplot.ai",
+ "font": {"size": 28, "color": INK},
"x": 0.5,
"xanchor": "center",
"y": 0.95,
},
xaxis={
- "title": {"text": "Study Hours (h)", "font": {"size": 22, "family": "Arial, sans-serif"}, "standoff": 12},
- "tickfont": {"size": 18},
- "showgrid": True,
+ "title": {"text": "Study Hours per Day", "font": {"size": 22, "color": INK}, "standoff": 12},
+ "tickfont": {"size": 18, "color": INK_SOFT},
+ "gridcolor": GRID,
"gridwidth": 1,
- "gridcolor": "rgba(0,0,0,0.06)",
- "range": [0, 11],
+ "linecolor": INK_SOFT,
"zeroline": False,
+ "showline": True,
+ "mirror": False,
+ "range": [0, 11],
"dtick": 2,
},
yaxis={
- "title": {"text": "Exam Score (%)", "font": {"size": 22, "family": "Arial, sans-serif"}, "standoff": 12},
- "tickfont": {"size": 18},
- "showgrid": True,
+ "title": {"text": "Exam Score (%)", "font": {"size": 22, "color": INK}, "standoff": 12},
+ "tickfont": {"size": 18, "color": INK_SOFT},
+ "gridcolor": GRID,
"gridwidth": 1,
- "gridcolor": "rgba(0,0,0,0.06)",
- "range": [35, 105],
+ "linecolor": INK_SOFT,
"zeroline": False,
+ "showline": True,
+ "mirror": False,
+ "range": [35, 105],
"dtick": 10,
},
- template="plotly_white",
- showlegend=False,
- margin={"l": 80, "r": 40, "t": 90, "b": 70},
- annotations=annotations,
- plot_bgcolor="white",
- paper_bgcolor="#FAFBFC",
- hoverlabel={"bgcolor": "white", "font_size": 14, "font_color": python_blue},
+ paper_bgcolor=PAGE_BG,
+ plot_bgcolor=PAGE_BG,
+ font={"color": INK},
+ margin={"l": 90, "r": 60, "t": 100, "b": 80},
+ hoverlabel={"bgcolor": ELEVATED_BG, "bordercolor": INK_SOFT, "font": {"color": INK}},
)
-fig.write_image("plot.png", width=1600, height=900, scale=3)
-fig.write_html("plot.html")
+# Save
+fig.write_image(f"plot-{THEME}.png", width=1600, height=900, scale=3)
+fig.write_html(f"plot-{THEME}.html", include_plotlyjs="cdn")
diff --git a/plots/scatter-basic/metadata/python/plotly.yaml b/plots/scatter-basic/metadata/python/plotly.yaml
index 7c4410b254..5bef72bab2 100644
--- a/plots/scatter-basic/metadata/python/plotly.yaml
+++ b/plots/scatter-basic/metadata/python/plotly.yaml
@@ -1,59 +1,55 @@
library: plotly
+language: python
specification_id: scatter-basic
-created: '2025-12-22T23:36:07Z'
-updated: '2026-02-14T14:47:56Z'
-generated_by: claude-opus-4-6
-workflow_run: 20446831781
-issue: 0
-python_version: '3.14'
-library_version: 6.5.2
-preview_url: https://storage.googleapis.com/anyplot-images/plots/scatter-basic/plotly/plot.png
-preview_html: https://storage.googleapis.com/anyplot-images/plots/scatter-basic/plotly/plot.html
-quality_score: 92
-impl_tags:
- dependencies: []
- techniques:
- - annotations
- - hover-tooltips
- - html-export
- patterns:
- - data-generation
- dataprep:
- - regression
- styling:
- - alpha-blending
- - edge-highlighting
- - grid-styling
+created: '2026-04-23T19:20:55Z'
+updated: '2026-04-23T19:26:44Z'
+generated_by: claude-opus-4-5-20251101
+workflow_run: 24853790187
+issue: 611
+python_version: 3.14.4
+library_version: 6.7.0
+preview_url_light: https://storage.googleapis.com/anyplot-images/plots/scatter-basic/python/plotly/plot-light.png
+preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/scatter-basic/python/plotly/plot-dark.png
+preview_html_light: https://storage.googleapis.com/anyplot-images/plots/scatter-basic/python/plotly/plot-light.html
+preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/scatter-basic/python/plotly/plot-dark.html
+quality_score: 86
review:
strengths:
- - Excellent data storytelling with three annotated outliers and correlation coefficient
- — goes well beyond just plotting points
- - 'Professional aesthetic: custom blue/orange palette, white marker edges, subtle
- grid, off-white paper background'
- - All font sizes explicitly set and well-calibrated for 4800×2700 output
- - Plotly-distinctive features used effectively (hovertemplate, HTML export, hoverlabel
- styling)
- - Clean, well-structured code with elegant annotation dict-spread pattern
+ - 'Perfect spec compliance: correct scatter type, opacity 0.7, descriptive labels,
+ grid lines all present'
+ - 'Excellent code quality: KISS structure, seed set, clean imports, correct plot-{THEME}.png
+ + HTML output'
+ - All font sizes explicitly set (title=28px, axis=22px, ticks=18px) meeting the
+ pixel-based requirements
+ - 'Full theme-adaptive chrome: #FAF8F1/#1A1A17 backgrounds, INK/INK_SOFT tokens
+ throughout, both renders pass legibility check'
+ - Realistic educational data (study hours vs exam scores) with clipped scores and
+ proper correlation (~0.7)
weaknesses:
- - Minor annotation congestion in the bottom-right between 'High effort, low score'
- (8.5, 52) and 'Underperformer' (9.2, 55) — arrows nearly overlap
- - Layout margins asymmetric (L=80 vs R=40) leading to slightly unbalanced whitespace
- distribution
- image_description: 'The plot displays a scatter plot of "Study Hours (h)" (x-axis,
- range 0–11) vs "Exam Score (%)" (y-axis, range ~35–105) with 120 blue circular
- markers (#306998) at opacity 0.6 with white edge outlines on a white background
- with very subtle gray grid lines. A dashed blue trend line shows the positive
- correlation. Three orange (#D4782F) diamond markers highlight outliers: "Low effort,
- high score" at (~2h, 78%), "High effort, low score" at (~8.5h, 52%), and "Underperformer"
- at (~9.2h, 55%). Each outlier has a bordered orange annotation box with an arrow
- pointing to the marker. The correlation coefficient "r = 0.79" is displayed in
- blue near the upper portion of the trend line. The title "scatter-basic · plotly
- · pyplots.ai" is centered at the top in dark bold text. The paper background is
- a light off-white (#FAFBFC). Overall the plot has a clean, professional appearance
- with clear data storytelling.'
+ - 'DE-03 LOW (2/6): No visual hierarchy or data storytelling — the positive correlation
+ is visible but nothing guides the viewer''s eye or provides interpretive context;
+ adding a trend line (go.Scatter mode=''lines'' with regression) would score +2'
+ - 'DE-01 moderate (4/8): Design is a well-configured default, not exceptional —
+ lacks the sophistication of a publication-ready plot; could add a subtle annotation
+ showing the correlation coefficient or vary marker opacity by density'
+ - 'LM-02 LOW (2/5): Only basic Plotly features used (hovertemplate, HTML export);
+ could leverage Plotly-specific capabilities like shapes for a trend line, updatemenus,
+ or custom hover with formatted statistics to score distinctively'
+ image_description: |-
+ Light render (plot-light.png):
+ Background: Warm off-white, visually consistent with #FAF8F1 — not pure white
+ Chrome: Title "scatter-basic · plotly · anyplot.ai" in dark ink, centered at top; "Study Hours per Day" x-axis label and "Exam Score (%)" y-axis label both dark and clearly readable; tick labels (0,2,4,6,8,10 on x; 40,50,...,100 on y) in dark secondary ink, all legible; subtle grid lines nearly invisible at 10% opacity
+ Data: 160 scatter markers in #009E73 (brand green) at opacity 0.7 with white marker edges; moderate clustering in the 3–5 hour range; clear upward trend from lower-left to upper-right; no pure-black or pure-white markers
+ Legibility verdict: PASS — all chrome elements readable, no light-on-light issues
+
+ Dark render (plot-dark.png):
+ Background: Warm near-black, visually consistent with #1A1A17 — not pure black
+ Chrome: Title in light off-white text, clearly readable against dark background; axis labels and tick labels in lighter secondary ink (#B8B7B0 tokens), all clearly legible; grid lines very subtle at 10% opacity on dark surface; no dark-on-dark failure observed
+ Data: Marker color identical to light render — same #009E73 brand green with same white edges; data distribution matches light render exactly; brand green reads well on near-black background
+ Legibility verdict: PASS — all chrome adapts correctly to dark theme, no dark-on-dark failures
criteria_checklist:
visual_quality:
- score: 27
+ score: 30
max: 30
items:
- id: VQ-01
@@ -61,65 +57,74 @@ review:
score: 8
max: 8
passed: true
- comment: 'All font sizes explicitly set: title 28pt, axis labels 22pt, ticks
- 18pt, annotations 16-17pt'
+ comment: 'All font sizes explicitly set: title=28px, axis=22px, ticks=18px;
+ readable in both themes'
- id: VQ-02
name: No Overlap
- score: 5
+ score: 6
max: 6
passed: true
- comment: Minor congestion between bottom-right annotations — arrows nearly
- overlap
+ comment: No text or label overlap; no legend; tick labels well-spaced
- id: VQ-03
name: Element Visibility
score: 6
max: 6
passed: true
- comment: 120 points at size 11 with opacity 0.6, outlier diamonds at size
- 15 — well adapted to density
+ comment: Marker size 13 with opacity 0.7 appropriate for 160 points; white
+ edge aids definition in dense regions
- id: VQ-04
name: Color Accessibility
- score: 4
- max: 4
+ score: 2
+ max: 2
passed: true
- comment: Blue/orange pair is colorblind-safe with good contrast
+ comment: 'Single series in CVD-safe #009E73; good contrast on both light and
+ dark backgrounds'
- id: VQ-05
- name: Layout Balance
- score: 2
+ name: Layout & Canvas
+ score: 4
max: 4
- passed: false
- comment: Asymmetric margins (L=80, R=40); slightly unbalanced whitespace distribution
+ passed: true
+ comment: Balanced margins (l=90, r=60, t=100, b=80), data fills chart area
+ well
- id: VQ-06
name: Axis Labels & Title
score: 2
max: 2
passed: true
- comment: 'Descriptive labels with units: Study Hours (h), Exam Score (%)'
+ comment: Study Hours per Day (x) and Exam Score (%) (y) — descriptive with
+ units
+ - id: VQ-07
+ name: Palette Compliance
+ score: 2
+ max: 2
+ passed: true
+ comment: '#009E73 as single series; #FAF8F1 light and #1A1A17 dark backgrounds;
+ all chrome tokens theme-correct'
design_excellence:
- score: 17
+ score: 10
max: 20
items:
- id: DE-01
name: Aesthetic Sophistication
- score: 7
+ score: 4
max: 8
- passed: true
- comment: Custom palette, intentional typography hierarchy, white marker edges,
- subtle grid, off-white paper
+ passed: false
+ comment: 'Well-configured library default: brand color, warm background, marker
+ edges — not exceptional; lacks trend line or design hierarchy'
- id: DE-02
name: Visual Refinement
- score: 5
+ score: 4
max: 6
passed: true
- comment: plotly_white template, 0.06 opacity grid, zeroline removed, generous
- standoff
+ comment: Very subtle grid (10% opacity), L-shaped spines, generous margins;
+ clearly above defaults
- id: DE-03
name: Data Storytelling
- score: 5
+ score: 2
max: 6
- passed: true
- comment: Three annotated outliers with descriptive labels, trend line with
- r=0.79 guides interpretation
+ passed: false
+ comment: Positive correlation visible from data distribution but no visual
+ hierarchy, trend line, or focal point guides the viewer
spec_compliance:
score: 15
max: 15
@@ -129,26 +134,28 @@ review:
score: 5
max: 5
passed: true
- comment: Correct 2D scatter plot
+ comment: Correct basic scatter plot
- id: SC-02
name: Required Features
score: 4
max: 4
passed: true
- comment: Transparency, axis labels, title, grid lines, appropriate point size
- all present
+ comment: Transparency (0.7), axis labels, grid lines, balanced point size
+ — all spec requirements met
- id: SC-03
name: Data Mapping
score: 3
max: 3
passed: true
- comment: X=study hours, Y=exam scores correctly assigned
+ comment: Study hours on x (independent), exam scores on y (dependent); full
+ data range visible
- id: SC-04
- name: Title Format
+ name: Title & Legend
score: 3
max: 3
passed: true
- comment: scatter-basic · plotly · pyplots.ai correct format
+ comment: Title 'scatter-basic · plotly · anyplot.ai' correct; no legend needed
+ for single series
data_quality:
score: 15
max: 15
@@ -158,19 +165,21 @@ review:
score: 6
max: 6
passed: true
- comment: Shows correlation, scatter distribution, outliers, and trend line
+ comment: Shows correlation, scatter distribution, clustering, and outliers
+ — full coverage of basic scatter features
- id: DQ-02
name: Realistic Context
score: 5
max: 5
passed: true
- comment: Study hours vs exam scores — neutral educational scenario
+ comment: Study hours vs exam scores — real, neutral, educational scenario
- id: DQ-03
name: Appropriate Scale
score: 4
max: 4
passed: true
- comment: Hours 1-10, scores 0-100% — perfectly realistic ranges
+ comment: 1–10 hours/day, 40–100% scores; clipped at 100; realistic linear
+ relationship with noise
code_quality:
score: 10
max: 10
@@ -180,7 +189,7 @@ review:
score: 3
max: 3
passed: true
- comment: Imports → Data → Plot → Save, no functions/classes
+ comment: Linear imports→data→plot→save, no functions or classes
- id: CQ-02
name: Reproducibility
score: 2
@@ -192,21 +201,21 @@ review:
score: 2
max: 2
passed: true
- comment: Only numpy and plotly.graph_objects
+ comment: os, numpy, plotly.graph_objects — all used
- id: CQ-04
name: Code Elegance
score: 2
max: 2
passed: true
- comment: Clean dict-spread pattern for annotations, appropriate complexity
+ comment: Clean, Pythonic, appropriate complexity
- id: CQ-05
name: Output & API
score: 1
max: 1
passed: true
- comment: Saves plot.png at 4800×2700 via write_image
- library_features:
- score: 8
+ comment: plot-{THEME}.png and plot-{THEME}.html; current Plotly API
+ library_mastery:
+ score: 6
max: 10
items:
- id: LM-01
@@ -214,13 +223,24 @@ review:
score: 4
max: 5
passed: true
- comment: Good Graph Objects API usage with proper modes, hovertemplate, and
- update_layout
+ comment: Correct go.Figure + go.Scatter pattern, proper update_layout, hovertemplate
+ — idiomatic but not advanced
- id: LM-02
name: Distinctive Features
- score: 4
+ score: 2
max: 5
- passed: true
- comment: hovertemplate, write_html, hoverlabel styling — Plotly-distinctive
- features
- verdict: APPROVED
+ passed: false
+ comment: hovertemplate and HTML export are Plotly-specific but basic; no use
+ of shapes, updatemenus, or other distinctive Plotly capabilities
+ verdict: REJECTED
+impl_tags:
+ dependencies: []
+ techniques:
+ - hover-tooltips
+ - html-export
+ patterns:
+ - data-generation
+ dataprep: []
+ styling:
+ - alpha-blending
+ - edge-highlighting