diff --git a/plots/rose-basic/implementations/python/plotly.py b/plots/rose-basic/implementations/python/plotly.py
index 4110d34575..29940b8517 100644
--- a/plots/rose-basic/implementations/python/plotly.py
+++ b/plots/rose-basic/implementations/python/plotly.py
@@ -1,64 +1,75 @@
-""" pyplots.ai
+""" anyplot.ai
rose-basic: Basic Rose Chart
-Library: plotly 6.5.0 | Python 3.13.11
-Quality: 91/100 | Created: 2025-12-23
+Library: plotly 6.7.0 | Python 3.13.13
+Quality: 90/100 | Updated: 2026-04-30
"""
+import os
+
import plotly.graph_objects as go
-# Data - Monthly rainfall (mm) showing seasonal pattern
+# Theme tokens
+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)"
+
+# Data - Monthly rainfall (mm) showing pronounced seasonal pattern
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
-rainfall = [78, 62, 55, 48, 42, 38, 35, 40, 52, 68, 82, 85]
+rainfall = [92, 74, 60, 45, 32, 18, 12, 22, 48, 75, 98, 105]
-# Create the rose chart using barpolar
-# Using month names directly as theta (categorical) for proper label placement
+# Plot
fig = go.Figure()
fig.add_trace(
go.Barpolar(
r=rainfall,
theta=months,
- width=0.9, # Slight gap between bars for visual clarity
+ width=0.9,
marker={
"color": rainfall,
- "colorscale": [[0, "#FFD43B"], [1, "#306998"]], # Python Yellow to Blue
- "line": {"color": "white", "width": 2},
- "cmin": min(rainfall),
+ "colorscale": "viridis",
+ "line": {"color": PAGE_BG, "width": 2},
+ "cmin": 0,
"cmax": max(rainfall),
},
hovertemplate="%{theta}
Rainfall: %{r} mm",
)
)
-# Update layout for 4800x2700 px output
fig.update_layout(
- title={"text": "rose-basic · plotly · pyplots.ai", "font": {"size": 48}, "x": 0.5, "xanchor": "center"},
- template="plotly_white",
+ title={
+ "text": "rose-basic · plotly · anyplot.ai",
+ "font": {"size": 48, "color": INK},
+ "x": 0.5,
+ "xanchor": "center",
+ },
+ paper_bgcolor=PAGE_BG,
polar={
+ "bgcolor": PAGE_BG,
"angularaxis": {
- "tickfont": {"size": 28},
+ "tickfont": {"size": 28, "color": INK_SOFT},
"direction": "clockwise",
- "rotation": 90, # Start at top (12 o'clock)
- "gridcolor": "rgba(0,0,0,0.1)",
- "linecolor": "rgba(0,0,0,0.3)",
+ "rotation": 90,
+ "gridcolor": GRID,
+ "linecolor": INK_SOFT,
},
"radialaxis": {
- "tickfont": {"size": 22},
- "gridcolor": "rgba(0,0,0,0.15)",
- "linecolor": "rgba(0,0,0,0.3)",
+ "tickfont": {"size": 22, "color": INK_SOFT},
+ "gridcolor": GRID,
+ "linecolor": INK_SOFT,
"ticksuffix": " mm",
"angle": 45,
- "dtick": 20,
+ "dtick": 25,
},
- "bgcolor": "white",
},
showlegend=False,
margin={"l": 100, "r": 100, "t": 150, "b": 100},
)
-# Save as PNG (4800 x 2700 px)
-fig.write_image("plot.png", width=1600, height=900, scale=3)
-
-# Save interactive HTML version
-fig.write_html("plot.html", include_plotlyjs="cdn")
+# 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/rose-basic/metadata/python/plotly.yaml b/plots/rose-basic/metadata/python/plotly.yaml
index 994131e6c6..8e194a59d8 100644
--- a/plots/rose-basic/metadata/python/plotly.yaml
+++ b/plots/rose-basic/metadata/python/plotly.yaml
@@ -1,169 +1,182 @@
library: plotly
+language: python
specification_id: rose-basic
created: '2025-12-23T19:43:10Z'
-updated: '2025-12-23T19:50:42Z'
-generated_by: claude-opus-4-5-20251101
-workflow_run: 20469992414
-issue: 0
-python_version: 3.13.11
-library_version: 6.5.0
-preview_url: https://storage.googleapis.com/anyplot-images/plots/rose-basic/plotly/plot.png
-preview_html: https://storage.googleapis.com/anyplot-images/plots/rose-basic/plotly/plot.html
-quality_score: 91
-impl_tags:
- dependencies: []
- techniques:
- - html-export
- - hover-tooltips
- - custom-colormap
- patterns:
- - data-generation
- dataprep: []
- styling: []
+updated: '2026-04-30T07:07:15Z'
+generated_by: claude-sonnet
+workflow_run: 25151743773
+issue: 1003
+python_version: 3.13.13
+library_version: 6.7.0
+preview_url_light: https://storage.googleapis.com/anyplot-images/plots/rose-basic/python/plotly/plot-light.png
+preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/rose-basic/python/plotly/plot-dark.png
+preview_html_light: https://storage.googleapis.com/anyplot-images/plots/rose-basic/python/plotly/plot-light.html
+preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/rose-basic/python/plotly/plot-dark.html
+quality_score: 90
review:
strengths:
- - Excellent use of plotly's barpolar trace type for creating the rose chart
- - Proper clockwise direction with rotation starting at 12 o'clock position (as spec
- recommends for time data)
- - Beautiful Python-themed color gradient (yellow to blue) that is colorblind-accessible
- - White borders between segments enhance visual distinction
- - Includes both PNG and interactive HTML output, leveraging plotly's interactivity
- - Custom hover template with mm units provides useful tooltip information
- - Radial axis tick suffix mm makes values self-documenting
+ - Native go.Barpolar trace with full polar axis configuration; idiomatic and correct
+ Plotly usage
+ - Viridis double-encoding (both radius and color encode rainfall value) is a thoughtful
+ design choice that reinforces the seasonal pattern
+ - 'Complete theme adaptation: correct backgrounds (#FAF8F1/#1A1A17), all chrome
+ tokens applied to polar axis, legend, title'
+ - Deterministic Mediterranean rainfall data is a textbook-quality rose chart example
+ with clear cyclical insight
+ - 'Full Plotly interactivity preserved: rich hovertemplate, HTML export alongside
+ PNG'
weaknesses:
- - Radial axis label text is angled and slightly harder to read than if horizontal
- - Data range is somewhat narrow (35-85mm); more extreme variation would better showcase
- the plot type
- - Could add a subtitle or annotation explaining the data context
- image_description: The plot displays a rose/coxcomb chart showing monthly rainfall
- data. It features 12 wedge-shaped segments arranged in a circle, one for each
- month (Jan through Dec), starting from the top at 12 o'clock position and proceeding
- clockwise. The segments' radii correspond to rainfall values in mm. The color
- scheme transitions from yellow (Python Yellow, ~#FFD43B) for lower values to blue
- (Python Blue, ~#306998) for higher values. July has the smallest radius (~35mm,
- yellow), while December has the largest (~85mm, blue). Radial gridlines at 0,
- 20, 40, 60, and 80 mm help gauge values. The title "rose-basic · plotly · pyplots.ai"
- appears centered at the top. Month labels are positioned around the outer edge
- of the chart. The overall layout is clean with a white background.
+ - Landscape (16:9) format introduces minor side whitespace for a circular chart;
+ square format (3600x3600) would better utilize canvas
+ - Radial tick labels slightly stacked near chart center at 45 degree angle; could
+ be improved with fewer ticks or adjusted label placement
+ image_description: |-
+ Light render (plot-light.png):
+ Background: Warm off-white consistent with #FAF8F1 — not pure white
+ Chrome: Title 'rose-basic · plotly · anyplot.ai' in dark ink (size 48) fully readable; month labels at 28px in INK_SOFT fully readable around perimeter; radial tick labels (0–100 mm) at 22px readable though somewhat stacked near center
+ Data: Viridis colorscale applied continuously — dark blue/teal for low-rainfall months (Jun=12mm, Jul=12mm), through teal-green, to yellow for high-rainfall months (Dec=105mm, Nov=98mm); bar edges use PAGE_BG color for clean separation
+ Legibility verdict: PASS — all text clearly readable against warm off-white background; no light-on-light issues
+
+ Dark render (plot-dark.png):
+ Background: Warm near-black consistent with #1A1A17 — not pure black
+ Chrome: Title in light INK (#F0EFE8) clearly readable; month labels in INK_SOFT (#B8B7B0) readable; radial tick labels in INK_SOFT readable; no dark-on-dark failures observed; all text is light-colored on dark background
+ Data: Viridis colorscale colors are identical to light render — same teal-to-yellow gradient; bar edges use dark PAGE_BG color for definition; data visual is indistinguishable from light render in terms of color identity
+ Legibility verdict: PASS — all text clearly readable against near-black background; no dark-on-dark issues
criteria_checklist:
visual_quality:
- score: 36
- max: 40
+ score: 28
+ max: 30
items:
- id: VQ-01
name: Text Legibility
- score: 10
- max: 10
+ score: 8
+ max: 8
passed: true
- comment: Title is large and clear, month labels are easily readable, radial
- axis labels are legible
+ comment: 'All font sizes explicitly set: title 48px, angular ticks 28px, radial
+ ticks 22px; fully readable in both themes'
- id: VQ-02
name: No Overlap
- score: 8
- max: 8
+ score: 5
+ max: 6
passed: true
- comment: No overlapping text elements; month labels well-spaced around the
- perimeter
+ comment: Month labels well-spaced; radial labels slightly cramped near center
+ but readable
- id: VQ-03
name: Element Visibility
- score: 7
- max: 8
+ score: 6
+ max: 6
passed: true
- comment: Wedges are clearly visible with good sizing; white borders between
- segments aid distinction
+ comment: Bars clearly visible, seasonal pattern immediately apparent
- id: VQ-04
name: Color Accessibility
- score: 4
- max: 5
+ score: 2
+ max: 2
passed: true
- comment: Yellow-to-blue gradient is colorblind-friendly (avoids red-green);
- good choice
+ comment: Viridis is CVD-safe and perceptually uniform
- id: VQ-05
- name: Layout Balance
- score: 4
- max: 5
+ name: Layout & Canvas
+ score: 3
+ max: 4
passed: true
- comment: Good proportions; chart utilizes canvas well though slightly more
- centered vertically than ideal
+ comment: Chart fills canvas well but landscape 16:9 format introduces side
+ whitespace for circular plot
- id: VQ-06
- name: Axis Labels
+ name: Axis Labels & Title
score: 2
max: 2
passed: true
- comment: Radial axis includes unit "mm" suffix; month labels are descriptive
+ comment: Radial tick suffix mm provides units; title gives context
- id: VQ-07
- name: Grid & Legend
- score: 1
+ name: Palette Compliance
+ score: 2
max: 2
passed: true
- comment: Subtle radial gridlines present; no legend needed for single-series
+ comment: 'Viridis used correctly for continuous value-mapped data; backgrounds
+ are #FAF8F1/#1A1A17; all chrome is theme-adaptive'
+ design_excellence:
+ score: 13
+ max: 20
+ items:
+ - id: DE-01
+ name: Aesthetic Sophistication
+ score: 5
+ max: 8
+ passed: true
+ comment: 'Above well-configured defaults: viridis double-encoding is thoughtful,
+ PAGE_BG separator edges create clean definition, explicit typography; not
+ yet at strong design level'
+ - id: DE-02
+ name: Visual Refinement
+ score: 4
+ max: 6
+ passed: true
+ comment: Subtle 10% opacity grid, custom bar width 0.9, adaptive edge colors,
+ explicit generous margins, clockwise orientation from north
+ - id: DE-03
+ name: Data Storytelling
+ score: 4
+ max: 6
+ passed: true
+ comment: Seasonal pattern immediately clear through double-encoding; viewer
+ instantly sees Nov-Jan wet, Jun-Aug dry
spec_compliance:
- score: 25
- max: 25
+ score: 15
+ max: 15
items:
- id: SC-01
name: Plot Type
- score: 8
- max: 8
- passed: true
- comment: Correct rose/coxcomb chart using barpolar
- - id: SC-02
- name: Data Mapping
score: 5
max: 5
passed: true
- comment: Categories (months) on angular axis, values (rainfall) as radius
- - correct
- - id: SC-03
+ comment: go.Barpolar is Plotly's native polar bar (rose) chart type
+ - id: SC-02
name: Required Features
- score: 5
- max: 5
+ score: 4
+ max: 4
passed: true
- comment: Equal-angle wedges, radius proportional to value, circular arrangement
- - id: SC-04
- name: Data Range
+ comment: Circular format, radius proportional to value, radial gridlines,
+ 12 monthly categories, consistent colorscheme
+ - id: SC-03
+ name: Data Mapping
score: 3
max: 3
passed: true
- comment: All data visible, radial axis shows full range (0-80+ mm)
- - id: SC-05
- name: Legend Accuracy
- score: 2
- max: 2
- passed: true
- comment: No legend needed; color scale implicit and appropriate
- - id: SC-06
- name: Title Format
- score: 2
- max: 2
+ comment: Months on angular axis, rainfall on radial axis; clockwise from north
+ (rotation=90) correct for calendar data
+ - id: SC-04
+ name: Title & Legend
+ score: 3
+ max: 3
passed: true
- comment: 'Correct format: "rose-basic · plotly · pyplots.ai"'
+ comment: Title rose-basic · plotly · anyplot.ai correct; no legend needed
+ for single-series
data_quality:
- score: 18
- max: 20
+ score: 15
+ max: 15
items:
- id: DQ-01
name: Feature Coverage
- score: 7
- max: 8
+ score: 6
+ max: 6
passed: true
- comment: Shows seasonal variation in rainfall; demonstrates high winter/low
- summer pattern; could show more extreme outliers
+ comment: Full range 12-105 mm demonstrates cyclical patterns with prominent
+ seasonal variation
- id: DQ-02
name: Realistic Context
- score: 7
- max: 7
+ score: 5
+ max: 5
passed: true
- comment: Monthly rainfall data is a classic rose chart application; values
- are realistic for temperate climate
+ comment: Monthly rainfall is the canonical neutral rose chart example with
+ clear real-world meaning
- id: DQ-03
name: Appropriate Scale
score: 4
- max: 5
+ max: 4
passed: true
- comment: Values 35-85mm are plausible; perhaps slightly narrow range
+ comment: Annual total ~681 mm with winter-peak pattern consistent with Mediterranean
+ climate
code_quality:
- score: 9
+ score: 10
max: 10
items:
- id: CQ-01
@@ -171,42 +184,60 @@ review:
score: 3
max: 3
passed: true
- comment: 'Clean linear flow: imports → data → plot → save'
+ comment: 'Linear: imports, theme tokens, data, plot, save; no functions or
+ classes'
- id: CQ-02
name: Reproducibility
score: 2
- max: 3
- passed: false
- comment: Data is deterministic (hardcoded values) but no random seed statement
- even though not needed
+ max: 2
+ passed: true
+ comment: Hardcoded deterministic data; no randomness
- id: CQ-03
name: Clean Imports
score: 2
max: 2
passed: true
- comment: Only plotly.graph_objects imported, and used
+ comment: Only os and plotly.graph_objects imported, both used
- id: CQ-04
- name: No Deprecated API
- score: 1
- max: 1
+ name: Code Elegance
+ score: 2
+ max: 2
passed: true
- comment: Uses current plotly API (go.Barpolar)
+ comment: Clean Pythonic dict-based marker config; appropriate complexity
- id: CQ-05
- name: Output Correct
+ name: Output & API
score: 1
max: 1
passed: true
- comment: Saves as plot.png with correct dimensions
- library_features:
- score: 3
- max: 5
+ comment: Saves plot-{THEME}.png and plot-{THEME}.html; current Plotly API
+ library_mastery:
+ score: 9
+ max: 10
items:
- - id: LF-01
- name: Uses distinctive library features
- score: 3
+ - id: LM-01
+ name: Idiomatic Usage
+ score: 5
+ max: 5
+ passed: true
+ comment: go.Barpolar with proper polar axis config (angularaxis, radialaxis,
+ direction, rotation) is idiomatic Plotly
+ - id: LM-02
+ name: Distinctive Features
+ score: 4
max: 5
passed: true
- comment: Uses barpolar for rose chart, hover template for interactivity, and
- exports HTML version; could leverage more plotly-specific features like
- animations or custom hover data
+ comment: 'Plotly-distinctive: go.Barpolar trace, hovertemplate for rich interactive
+ tooltips, write_html for interactive export'
verdict: APPROVED
+impl_tags:
+ dependencies: []
+ techniques:
+ - polar-projection
+ - hover-tooltips
+ - html-export
+ patterns:
+ - data-generation
+ dataprep: []
+ styling:
+ - custom-colormap
+ - edge-highlighting