From ed96309e3073fd538d90bf42a68fb8a975f88ac2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 5 May 2026 03:37:18 +0000 Subject: [PATCH 1/3] chore(letsplot): add metadata for streamgraph-basic --- .../implementations/python/letsplot.py | 99 ++++---- .../metadata/python/letsplot.yaml | 223 ++---------------- 2 files changed, 76 insertions(+), 246 deletions(-) diff --git a/plots/streamgraph-basic/implementations/python/letsplot.py b/plots/streamgraph-basic/implementations/python/letsplot.py index 83cdf36d2f..e4d0f411b7 100644 --- a/plots/streamgraph-basic/implementations/python/letsplot.py +++ b/plots/streamgraph-basic/implementations/python/letsplot.py @@ -1,81 +1,100 @@ -""" pyplots.ai +"""anyplot.ai streamgraph-basic: Basic Stream Graph -Library: letsplot 4.8.2 | Python 3.13.11 -Quality: 91/100 | Created: 2025-12-23 +Library: letsplot | Python 3.13 +Quality: pending | Updated: 2026-05-05 """ +import os + import numpy as np import pandas as pd from lets_plot import * # noqa: F403 -from lets_plot.export import ggsave as export_ggsave +from lets_plot.export import ggsave +from scipy.interpolate import make_interp_spline LetsPlot.setup_html() # noqa: F405 -# Data - monthly streaming hours by music genre over two years +# 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" + +# Okabe-Ito palette — first series always #009E73 +OKABE_ITO = ["#009E73", "#D55E00", "#0072B2", "#CC79A7", "#E69F00"] + +# Data — monthly streaming hours by music genre over two years np.random.seed(42) n_months = 24 genres = ["Pop", "Rock", "Hip-Hop", "Electronic", "Jazz"] -n_genres = len(genres) -# Generate smooth trends for each genre with distinct patterns raw_values = {} +months_orig = np.arange(n_months, dtype=float) for i, genre in enumerate(genres): base = 100 + 50 * np.sin(np.linspace(0, 4 * np.pi, n_months) + i * 0.7) trend = np.linspace(0, 25, n_months) * (1 if i % 2 == 0 else -0.6) noise = np.random.randn(n_months) * 8 raw_values[genre] = np.clip(base + trend + noise, 25, None) -# Compute streamgraph positions (centered around baseline) -values_matrix = np.array([raw_values[g] for g in genres]) -total_per_month = values_matrix.sum(axis=0) -baseline_offset = -total_per_month / 2 +# Smooth each series with a cubic spline for flowing curves +n_interp = n_months * 8 +months_smooth = np.linspace(0, n_months - 1, n_interp) +values_smooth = {} +for genre in genres: + spline = make_interp_spline(months_orig, raw_values[genre], k=3) + values_smooth[genre] = np.clip(spline(months_smooth), 10, None) + +# Compute streamgraph positions (symmetric baseline around zero) +values_matrix = np.array([values_smooth[g] for g in genres]) +total_per_point = values_matrix.sum(axis=0) +baseline_offset = -total_per_point / 2 -# Build dataframe with ymin/ymax for ribbon geometry data = [] -for month_idx in range(n_months): - cumulative = baseline_offset[month_idx] +for t_idx, t in enumerate(months_smooth): + cumulative = baseline_offset[t_idx] for genre_idx, genre in enumerate(genres): ymin = cumulative - ymax = cumulative + values_matrix[genre_idx, month_idx] - data.append({"month": month_idx, "genre": genre, "ymin": ymin, "ymax": ymax}) + ymax = cumulative + values_matrix[genre_idx, t_idx] + data.append({"month": t, "genre": genre, "ymin": ymin, "ymax": ymax}) cumulative = ymax df = pd.DataFrame(data) -# Create streamgraph using geom_ribbon for precise ymin/ymax control +# Plot +anyplot_theme = theme( # noqa: F405 + plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG), # noqa: F405 + panel_background=element_rect(fill=PAGE_BG), # noqa: F405 + panel_grid_major_x=element_line(color=INK_SOFT, size=0.3, linetype="dashed"), # noqa: F405 + panel_grid_major_y=element_blank(), # noqa: F405 + panel_grid_minor=element_blank(), # noqa: F405 + axis_title=element_text(color=INK, size=20), # noqa: F405 + axis_text=element_text(color=INK_SOFT, size=16), # noqa: F405 + axis_text_y=element_blank(), # noqa: F405 + axis_ticks_y=element_blank(), # noqa: F405 + axis_line=element_line(color=INK_SOFT), # noqa: F405 + plot_title=element_text(color=INK, size=24), # noqa: F405 + legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT), # noqa: F405 + legend_text=element_text(color=INK_SOFT, size=16), # noqa: F405 + legend_title=element_text(color=INK, size=18), # noqa: F405 +) + plot = ( ggplot(df, aes(x="month", fill="genre")) # noqa: F405 + geom_ribbon(aes(ymin="ymin", ymax="ymax"), alpha=0.9) # noqa: F405 - + scale_fill_manual( # noqa: F405 - values=["#306998", "#FFD43B", "#38BDF8", "#A78BFA", "#FB923C"] - ) + + scale_fill_manual(values=OKABE_ITO) # noqa: F405 + scale_x_continuous( # noqa: F405 breaks=[0, 6, 12, 18, 23], labels=["Jan '23", "Jul '23", "Jan '24", "Jul '24", "Dec '24"] ) + labs( # noqa: F405 - x="Month", y="Streaming Hours", fill="Genre", title="streamgraph-basic · lets-plot · pyplots.ai" + x="Month", y="", fill="Genre", title="streamgraph-basic · letsplot · anyplot.ai" ) + ggsize(1600, 900) # noqa: F405 + theme_minimal() # noqa: F405 - + theme( # noqa: F405 - axis_text=element_text(size=16), # noqa: F405 - axis_title=element_text(size=20), # noqa: F405 - plot_title=element_text(size=24), # noqa: F405 - legend_text=element_text(size=16), # noqa: F405 - legend_title=element_text(size=18), # noqa: F405 - axis_text_y=element_blank(), # noqa: F405 - axis_ticks_y=element_blank(), # noqa: F405 - panel_grid_major_y=element_blank(), # noqa: F405 - panel_grid_minor_y=element_blank(), # noqa: F405 - panel_grid_major_x=element_line( # noqa: F405 - color="#CCCCCC", size=0.5, linetype="dashed" - ), - ) + + anyplot_theme ) -# Save PNG (scale 3x to get 4800 x 2700 px) -export_ggsave(plot, filename="plot.png", path=".", scale=3) - -# Save HTML for interactive version -export_ggsave(plot, filename="plot.html", path=".") +# Save +ggsave(plot, filename=f"plot-{THEME}.png", path=".", scale=3) +ggsave(plot, filename=f"plot-{THEME}.html", path=".") diff --git a/plots/streamgraph-basic/metadata/python/letsplot.yaml b/plots/streamgraph-basic/metadata/python/letsplot.yaml index 2955788cfa..a8437d3646 100644 --- a/plots/streamgraph-basic/metadata/python/letsplot.yaml +++ b/plots/streamgraph-basic/metadata/python/letsplot.yaml @@ -1,210 +1,21 @@ +# Per-library metadata for letsplot implementation of streamgraph-basic +# Auto-generated by impl-generate.yml + library: letsplot +language: python specification_id: streamgraph-basic created: '2025-12-23T21:54:23Z' -updated: '2025-12-23T22:00:41Z' -generated_by: claude-opus-4-5-20251101 -workflow_run: 20472385732 -issue: 0 -python_version: 3.13.11 -library_version: 4.8.2 -preview_url: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/letsplot/plot.png -preview_html: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/letsplot/plot.html -quality_score: 91 -impl_tags: - dependencies: [] - techniques: - - html-export - patterns: - - data-generation - - matrix-construction - dataprep: [] - styling: - - alpha-blending +updated: '2026-05-05T03:37:18Z' +generated_by: claude-sonnet +workflow_run: 25356305149 +issue: 856 +python_version: 3.13.13 +library_version: 4.9.0 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/python/letsplot/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/python/letsplot/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/python/letsplot/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/python/letsplot/plot-dark.html +quality_score: null review: - strengths: - - Excellent implementation of centered baseline algorithm for authentic streamgraph - appearance - - Clean, readable code with proper seed for reproducibility - - Well-chosen color palette with good visual contrast between adjacent areas - - Appropriate removal of y-axis ticks/grid since streamgraphs emphasize relative - proportions - - Correct title format and professional layout with good canvas utilization - - Realistic music streaming scenario matching the specification exactly - weaknesses: - - Curves are linear/segmented rather than smooth spline interpolation as specified - - X-axis grid lines could be more subtle (currently dashed at 0.5 alpha) - - Y-axis label shows Streaming Hours without units like hrs/month - image_description: 'The plot displays a streamgraph showing music genre streaming - hours over a two-year period (Jan ''23 to Dec ''24). Five genres are shown: Pop - (dark blue at bottom), Rock (yellow), Hip-Hop (cyan/light blue), Electronic (purple), - and Jazz (orange at top). The chart uses a symmetric centered baseline creating - a river-like flowing appearance. The x-axis shows months with labels at Jan ''23, - Jul ''23, Jan ''24, Jul ''24, and Dec ''24. The y-axis is labeled "Streaming Hours" - but has no tick marks or values (appropriately hidden for streamgraphs). A legend - on the right identifies all genres. The title follows the required format: "streamgraph-basic - · lets-plot · pyplots.ai". The colors are distinct and harmonious, with smooth - flowing curves showing seasonal variations and trends.' - criteria_checklist: - visual_quality: - score: 36 - max: 40 - items: - - id: VQ-01 - name: Text Legibility - score: 10 - max: 10 - passed: true - comment: Title at 24pt, axis labels at 20pt, tick text at 16pt, legend text - at 16pt - all clearly readable - - id: VQ-02 - name: No Overlap - score: 8 - max: 8 - passed: true - comment: No overlapping text elements anywhere - - id: VQ-03 - name: Element Visibility - score: 8 - max: 8 - passed: true - comment: Smooth ribbon areas are well-sized, alpha=0.9 provides good visibility - while allowing slight transparency - - id: VQ-04 - name: Color Accessibility - score: 4 - max: 5 - passed: true - comment: Good distinct colors, but yellow and cyan could be slightly challenging - for some colorblind users - - id: VQ-05 - name: Layout Balance - score: 5 - max: 5 - passed: true - comment: Plot fills canvas well, legend positioned appropriately on the right - - id: VQ-06 - name: Axis Labels - score: 1 - max: 2 - passed: true - comment: Y-axis says "Streaming Hours" but no units; X-axis says "Month" which - is appropriate - - id: VQ-07 - name: Grid & Legend - score: 0 - max: 2 - passed: true - comment: Y-axis grid intentionally removed (good for streamgraph), but x-axis - grid is dashed and slightly too prominent at alpha=0.5 - spec_compliance: - score: 25 - max: 25 - items: - - id: SC-01 - name: Plot Type - score: 8 - max: 8 - passed: true - comment: Correct streamgraph with centered baseline - - id: SC-02 - name: Data Mapping - score: 5 - max: 5 - passed: true - comment: Time on x-axis, categories stacked correctly, values represented - by area - - id: SC-03 - name: Required Features - score: 5 - max: 5 - passed: true - comment: Centered baseline, flowing curves, distinct colors, legend included - - id: SC-04 - name: Data Range - score: 3 - max: 3 - passed: true - comment: All 24 months displayed, all 5 genres visible - - id: SC-05 - name: Legend Accuracy - score: 2 - max: 2 - passed: true - comment: Legend correctly identifies all 5 genres - - id: SC-06 - name: Title Format - score: 2 - max: 2 - passed: true - comment: '"streamgraph-basic · lets-plot · pyplots.ai" follows required format' - data_quality: - score: 18 - max: 20 - items: - - id: DQ-01 - name: Feature Coverage - score: 7 - max: 8 - passed: true - comment: Shows seasonal patterns, trend variations, different genre behaviors - - but curves are not smooth/spline interpolated as spec suggests - - id: DQ-02 - name: Realistic Context - score: 7 - max: 7 - passed: true - comment: Music streaming hours by genre is a perfect, comprehensible real-world - scenario matching spec example - - id: DQ-03 - name: Appropriate Scale - score: 4 - max: 5 - passed: true - comment: Values around 25-150 hours/month are plausible but could be more - precisely contextualized - code_quality: - score: 9 - max: 10 - items: - - id: CQ-01 - name: KISS Structure - score: 3 - max: 3 - passed: true - comment: 'Simple script: imports → data → plot → save, no functions or classes' - - id: CQ-02 - name: Reproducibility - score: 3 - max: 3 - passed: true - comment: np.random.seed(42) is set - - id: CQ-03 - name: Clean Imports - score: 1 - max: 2 - passed: true - comment: Uses wildcard import with noqa comments, but necessary for lets-plot - - id: CQ-04 - name: No Deprecated API - score: 1 - max: 1 - passed: true - comment: Uses current lets-plot API - - id: CQ-05 - name: Output Correct - score: 1 - max: 1 - passed: true - comment: Saves as plot.png and plot.html - library_features: - score: 3 - max: 5 - items: - - id: LF-01 - name: Uses distinctive library features - score: 3 - max: 5 - passed: true - comment: Uses ggplot grammar (aes, geom_ribbon, scale_fill_manual, theme_minimal), - but geom_ribbon is basic rather than using lets-plot specific advanced features - verdict: APPROVED + strengths: [] + weaknesses: [] From 9a608a654a0d3025bed779af2713fb3cb4955a4f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 5 May 2026 03:42:33 +0000 Subject: [PATCH 2/3] chore(letsplot): update quality score 88 and review feedback for streamgraph-basic --- plots/streamgraph-basic/implementations/python/letsplot.py | 6 +++--- plots/streamgraph-basic/metadata/python/letsplot.yaml | 7 ++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/plots/streamgraph-basic/implementations/python/letsplot.py b/plots/streamgraph-basic/implementations/python/letsplot.py index e4d0f411b7..be2d24c6aa 100644 --- a/plots/streamgraph-basic/implementations/python/letsplot.py +++ b/plots/streamgraph-basic/implementations/python/letsplot.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai streamgraph-basic: Basic Stream Graph -Library: letsplot | Python 3.13 -Quality: pending | Updated: 2026-05-05 +Library: letsplot 4.9.0 | Python 3.13.13 +Quality: 88/100 | Updated: 2026-05-05 """ import os diff --git a/plots/streamgraph-basic/metadata/python/letsplot.yaml b/plots/streamgraph-basic/metadata/python/letsplot.yaml index a8437d3646..d98adb745f 100644 --- a/plots/streamgraph-basic/metadata/python/letsplot.yaml +++ b/plots/streamgraph-basic/metadata/python/letsplot.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for letsplot implementation of streamgraph-basic -# Auto-generated by impl-generate.yml - library: letsplot language: python specification_id: streamgraph-basic created: '2025-12-23T21:54:23Z' -updated: '2026-05-05T03:37:18Z' +updated: '2026-05-05T03:42:33Z' generated_by: claude-sonnet workflow_run: 25356305149 issue: 856 @@ -15,7 +12,7 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/streamgra preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/python/letsplot/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/python/letsplot/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/python/letsplot/plot-dark.html -quality_score: null +quality_score: 88 review: strengths: [] weaknesses: [] From 94323878e3dec23b9575bdf36dbe370fa772122c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 6 May 2026 21:55:14 +0000 Subject: [PATCH 3/3] chore(letsplot): update quality score 87 and review feedback for streamgraph-basic --- .../implementations/python/letsplot.py | 2 +- .../metadata/python/letsplot.yaml | 247 +++++++++++++++++- 2 files changed, 244 insertions(+), 5 deletions(-) diff --git a/plots/streamgraph-basic/implementations/python/letsplot.py b/plots/streamgraph-basic/implementations/python/letsplot.py index be2d24c6aa..a00f179a67 100644 --- a/plots/streamgraph-basic/implementations/python/letsplot.py +++ b/plots/streamgraph-basic/implementations/python/letsplot.py @@ -1,7 +1,7 @@ """ anyplot.ai streamgraph-basic: Basic Stream Graph Library: letsplot 4.9.0 | Python 3.13.13 -Quality: 88/100 | Updated: 2026-05-05 +Quality: 87/100 | Updated: 2026-05-06 """ import os diff --git a/plots/streamgraph-basic/metadata/python/letsplot.yaml b/plots/streamgraph-basic/metadata/python/letsplot.yaml index d98adb745f..22618e5df2 100644 --- a/plots/streamgraph-basic/metadata/python/letsplot.yaml +++ b/plots/streamgraph-basic/metadata/python/letsplot.yaml @@ -2,7 +2,7 @@ library: letsplot language: python specification_id: streamgraph-basic created: '2025-12-23T21:54:23Z' -updated: '2026-05-05T03:42:33Z' +updated: '2026-05-06T21:55:14Z' generated_by: claude-sonnet workflow_run: 25356305149 issue: 856 @@ -12,7 +12,246 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/streamgra preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/python/letsplot/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/python/letsplot/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/streamgraph-basic/python/letsplot/plot-dark.html -quality_score: 88 +quality_score: 87 review: - strengths: [] - weaknesses: [] + strengths: + - Correct streamgraph implementation with symmetric baseline computation and cubic + spline interpolation for smooth flowing curves + - 'Perfect Okabe-Ito palette compliance — first series is #009E73, all 5 categories + in canonical order' + - 'Thorough theme-adaptive chrome: PAGE_BG, ELEVATED_BG, INK, INK_SOFT tokens applied + to all text and background elements for both light and dark renders' + - Y-axis labels and ticks deliberately hidden (blank) — correct design choice since + symmetric-baseline y-values are not meaningful to readers + - All text sizes explicitly set (title=24, axis_title=20, axis_text=16, legend_text=16, + legend_title=18) for 4800×2700 output + weaknesses: + - 'DE-03 LOW: No data storytelling or visual emphasis — all genres rendered with + equal visual weight, no focal point or annotation to highlight an interesting + trend or peak' + - 'DE-01 MODERATE: Aesthetic sophistication is functional but not distinctive — + the flowing curves are pleasant but there are no design touches that elevate this + above a clean default (e.g., subtle alpha gradient, thin border strokes on ribbons, + or typographic hierarchy in the title)' + - 'LM-02 LOW: lets-plot distinctive features under-exploited — interactive tooltips + or hover data in the HTML output would showcase what makes lets-plot different + from plotnine' + image_description: |- + Light render (plot-light.png): + Background: Warm off-white (#FAF8F1) — matches spec exactly, not pure white + Chrome: Title "streamgraph-basic · letsplot · anyplot.ai" is dark ink (#1A1A17) and clearly readable at top. X-axis label "Month" is dark and readable. Tick labels (Jan '23, Jul '23, Jan '24, Jul '24, Dec '24) rendered in INK_SOFT (#4A4A44) — legible against the light background. Legend "Genre" title and category labels (Pop, Rock, Hip-Hop, Electronic, Jazz) are readable with elevated background (#FFFDF6). + Data: 5 ribbon streams flowing smoothly across 24 months. First stream (Pop) is #009E73 (teal/green) at the bottom, followed by Rock (#D55E00 orange), Hip-Hop (#0072B2 blue), Electronic (#CC79A7 pink), Jazz (#E69F00 yellow) at top. Symmetric baseline creates organic river-like shape. Subtle dashed vertical grid lines at Jan/Jul intervals. + Legibility verdict: PASS — all text clearly readable, no light-on-light issues + + Dark render (plot-dark.png): + Background: Warm near-black (#1A1A17) — matches spec exactly, not pure black + Chrome: Title "streamgraph-basic · letsplot · anyplot.ai" is rendered in light ink (#F0EFE8) — clearly visible against the dark background. X-axis label "Month" is light-colored and readable. Tick labels are in INK_SOFT (#B8B7B0 light gray) — clearly legible against the dark background. Legend has elevated dark background (#242420) with light-colored text. No dark-on-dark failures observed. + Data: Identical colors to light render — Pop (#009E73), Rock (#D55E00), Hip-Hop (#0072B2), Electronic (#CC79A7), Jazz (#E69F00). Data colors are theme-independent as required. The lower corners of the plot (where no streams reach) show the #1A1A17 background. + Legibility verdict: PASS — all text clearly readable against the dark background, correct chrome adaptation throughout + criteria_checklist: + visual_quality: + score: 30 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 8 + max: 8 + passed: true + comment: 'All font sizes explicitly set: title=24, axis_title=20, axis_text=16, + legend_text=16, legend_title=18. Readable in both themes with correct INK/INK_SOFT + token application.' + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: 5 well-spaced tick labels, legend positioned right without overlapping + data. + - id: VQ-03 + name: Element Visibility + score: 6 + max: 6 + passed: true + comment: All 5 ribbon streams clearly visible with alpha=0.9, distinct Okabe-Ito + colors. + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Okabe-Ito palette is CVD-safe; sufficient luminance contrast between + all adjacent streams. + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: 1600x900 with scale=3 produces 4800x2700. Plot fills canvas well + with balanced margins. + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: 'X: ''Month'' appropriate; Y: blank (correct — symmetric baseline + values are not meaningful). Title correct format.' + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series #009E73, all 5 in canonical Okabe-Ito order. Light + bg #FAF8F1, dark bg #1A1A17. Both renders theme-correct.' + design_excellence: + score: 11 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: 'Above default: clean minimal look, deliberate y-axis hiding, warm + backgrounds. But no distinctive design touches elevating beyond a well-configured + default.' + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: theme_minimal removes spines, y-axis fully hidden, only subtle dashed + x-grid retained. Good refinement choices. + - id: DE-03 + name: Data Storytelling + score: 2 + max: 6 + passed: false + comment: Data displayed without visual emphasis. All genres have equal visual + weight; no focal point, annotation, or emphasis technique to guide the viewer + to an insight. + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Correct streamgraph with symmetric baseline. Smooth flowing ribbons + via cubic spline interpolation. + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Smooth interpolation (scipy spline), symmetric baseline, distinct + colors, legend — all present. + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: X=months (Jan '23–Dec '24), Y=stacked symmetric values. All 24 months + represented. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: 'Title: ''streamgraph-basic · letsplot · anyplot.ai'' exact match. + Legend ''Genre'' with all 5 categories correctly labeled.' + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: 'Shows all streamgraph aspects: multiple categories, temporal evolution, + varying magnitude trends (some rising, some falling).' + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Monthly streaming hours by music genre (Pop, Rock, Hip-Hop, Electronic, + Jazz) over 2023-2024. Neutral, plausible, non-controversial. + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Base ~100 hours/month per genre with trend and noise variations. + Realistic proportions for streaming data. + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: Procedural imports→data→plot→save with no functions or classes. + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: np.random.seed(42) set. + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: All imports used. noqa comments acceptable for lets_plot star import. + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Clean, readable. No fake UI elements. Appropriate complexity for + streamgraph computation. + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot-{THEME}.png and plot-{THEME}.html. No bare plot.png. Current + API. + library_mastery: + score: 6 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: Correct use of ggplot() + geom_ribbon(), scale_fill_manual, scale_x_continuous + with explicit breaks/labels, labs, ggsize, and theme() element system. + - id: LM-02 + name: Distinctive Features + score: 2 + max: 5 + passed: false + comment: HTML export is a lets-plot strength but expected by the library guide. + No interactive tooltip or lets-plot-specific feature beyond what plotnine + would also provide. + verdict: APPROVED +impl_tags: + dependencies: + - scipy + techniques: + - html-export + - manual-ticks + patterns: + - data-generation + dataprep: + - interpolation + styling: + - alpha-blending