From f35f94376021307d0ab0a974a75e6f4e260d44ab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 25 Jul 2026 23:41:52 +0000 Subject: [PATCH 1/5] feat(letsplot): implement slope-basic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regen from quality 85. Addressed: - Canvas drift: previous ggsize(1600, 900)/scale=3 rendered at 4800x2700, outside the ±16px gate. Reset to canonical ggsize(800, 450)/scale=4 -> 3200x1800. - Title missing the mandated language token; now "slope-basic · python · letsplot · anyplot.ai". - Label crowding (VQ-02): re-spread Q1/Q4 values so both endpoints keep a >=20-unit gap between adjacent entities instead of the previous ~10-unit clusters. - Endpoint labels were overlapping their point markers because hjust alone doesn't create data-space clearance from a pixel-sized marker; added nudge_x to push labels a real distance away from each point. - Re-tuned theme/geom_text sizes to the canonical canvas per the library prompt's sizing table (geom_text kept in the ~3-5mm annotation range instead of reusing the theme's pt scale). Kept unchanged: Okabe-Ito-style increase/decrease coloring via the Imprint palette, top-3 mover emphasis (bold vs. dimmed segments), layer_tooltips() interactivity, and the consumer-electronics data scenario. --- .../implementations/python/letsplot.py | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/plots/slope-basic/implementations/python/letsplot.py b/plots/slope-basic/implementations/python/letsplot.py index 4eb2af679b..7dfdb14cbd 100644 --- a/plots/slope-basic/implementations/python/letsplot.py +++ b/plots/slope-basic/implementations/python/letsplot.py @@ -1,7 +1,7 @@ -""" anyplot.ai +"""anyplot.ai slope-basic: Basic Slope Chart (Slopegraph) Library: letsplot 4.9.0 | Python 3.13.13 -Quality: 85/100 | Updated: 2026-04-30 +Quality: pending | Updated: 2026-07-25 """ import os @@ -40,26 +40,28 @@ INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" GRID_COLOR = "#C8C7BF" if THEME == "light" else "#333330" -# Okabe-Ito: green = increase, orange = decrease +# Imprint palette: brand green = increase, matte red = decrease COLOR_INCREASE = "#009E73" -COLOR_DECREASE = "#AE3030" # imprint red — decrease +COLOR_DECREASE = "#AE3030" -# Consumer electronics quarterly sales ($K): Q1 vs Q4 +# Consumer electronics quarterly sales ($K): Q1 vs Q4. +# Values are spread with a minimum gap of ~20 at both endpoints so the +# entity + value labels never sit close enough to overlap. data = { "entity": [ + "Streaming Devices", + "Gaming Consoles", "Laptops", - "Smartphones", + "Tablets", "Smart TVs", - "Monitors", "Headphones", - "Cameras", - "Streaming Devices", + "Monitors", "Speakers", - "Tablets", - "Gaming Consoles", + "Cameras", + "Smartphones", ], - "Q1": [80, 210, 120, 155, 140, 195, 55, 175, 105, 90], - "Q4": [130, 175, 160, 120, 185, 215, 95, 140, 150, 60], + "Q1": [50, 72, 95, 118, 140, 162, 184, 206, 228, 250], + "Q4": [55, 90, 140, 160, 222, 245, 115, 200, 270, 180], } df = pd.DataFrame(data) df["change"] = df["Q4"] - df["Q1"] @@ -89,7 +91,7 @@ {"entity": df["entity"].tolist() * 2, "value": df["Q1"].tolist() + df["Q4"].tolist(), "x": [0] * 10 + [1] * 10} ).merge(df[["entity", "direction"]], on="entity") -# Endpoint labels: entity name + value for legibility in crowded regions +# Endpoint labels: entity name + value for legibility df_left = pd.DataFrame( { "entity": df["entity"].values, @@ -133,7 +135,7 @@ alpha=0.40, tooltips=_tooltip_normal, ) - # Top-mover lines: bold, fully opaque — emphasises biggest Q1→Q4 changes + # Top-mover lines: bold, fully opaque — emphasises the biggest Q1→Q4 changes + geom_segment( data=seg_top, mapping=aes(x="x_start", y="y_start", xend="x_end", yend="y_end", color="direction"), @@ -142,12 +144,16 @@ tooltips=_tooltip_top, ) + geom_point(data=df_long, mapping=aes(x="x", y="value", color="direction"), size=6) - + geom_text(data=df_left, mapping=aes(x="x", y="value", label="label"), hjust=1.08, size=10, color=INK_SOFT) - + geom_text(data=df_right, mapping=aes(x="x", y="value", label="label"), hjust=-0.08, size=10, color=INK_SOFT) + + geom_text( + data=df_left, mapping=aes(x="x", y="value", label="label"), hjust=1, nudge_x=-0.07, size=4.2, color=INK_SOFT + ) + + geom_text( + data=df_right, mapping=aes(x="x", y="value", label="label"), hjust=0, nudge_x=0.07, size=4.2, color=INK_SOFT + ) + scale_color_manual(values={"Increase": COLOR_INCREASE, "Decrease": COLOR_DECREASE}) + scale_x_continuous(breaks=[0, 1], labels=["Q1 Sales ($K)", "Q4 Sales ($K)"], limits=[-1.05, 2.05]) - + scale_y_continuous(limits=[25, 245]) - + labs(title="slope-basic · letsplot · anyplot.ai", x="", y="Sales ($K)", color="Change") + + scale_y_continuous(limits=[20, 300]) + + labs(title="slope-basic · python · letsplot · anyplot.ai", x="", y="Sales ($K)", color="Change") + theme_minimal() + theme( plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG), @@ -155,20 +161,20 @@ panel_grid_major_y=element_line(color=GRID_COLOR, size=0.3), panel_grid_major_x=element_blank(), panel_grid_minor=element_blank(), - plot_title=element_text(size=28, color=INK), - axis_title_y=element_text(size=22, color=INK), + plot_title=element_text(size=16, color=INK), + axis_title_y=element_text(size=12, color=INK), axis_title_x=element_blank(), - axis_text_x=element_text(size=20, color=INK_SOFT), - axis_text_y=element_text(size=18, color=INK_SOFT), + axis_text_x=element_text(size=12, color=INK_SOFT), + axis_text_y=element_text(size=10, color=INK_SOFT), legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT), - legend_title=element_text(size=20, color=INK), - legend_text=element_text(size=18, color=INK_SOFT), + legend_title=element_text(size=12, color=INK), + legend_text=element_text(size=10, color=INK_SOFT), ) - + ggsize(1600, 900) + + ggsize(800, 450) ) -# Save PNG (scale 3x → 4800 × 2700 px) -ggsave(plot, f"plot-{THEME}.png", path=".", scale=3) +# Save PNG: scale=4 on ggsize(800, 450) -> 3200 x 1800 px (canonical landscape canvas) +ggsave(plot, f"plot-{THEME}.png", path=".", scale=4) # Save HTML for letsplot interactive tooltips ggsave(plot, f"plot-{THEME}.html", path=".") From 0f9c422f154379dc28b0ef5e6ededd1335542115 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 25 Jul 2026 23:42:02 +0000 Subject: [PATCH 2/5] chore(letsplot): add metadata for slope-basic --- .../slope-basic/metadata/python/letsplot.yaml | 238 +----------------- 1 file changed, 10 insertions(+), 228 deletions(-) diff --git a/plots/slope-basic/metadata/python/letsplot.yaml b/plots/slope-basic/metadata/python/letsplot.yaml index dfb848a542..07fff64323 100644 --- a/plots/slope-basic/metadata/python/letsplot.yaml +++ b/plots/slope-basic/metadata/python/letsplot.yaml @@ -1,239 +1,21 @@ +# Per-library metadata for letsplot implementation of slope-basic +# Auto-generated by impl-generate.yml + library: letsplot language: python specification_id: slope-basic created: '2025-12-23T20:47:50Z' -updated: '2026-04-30T17:14:44Z' +updated: '2026-07-25T23:42:02Z' generated_by: claude-sonnet -workflow_run: 25177850228 +workflow_run: 30179644496 issue: 981 -python_version: 3.13.13 -library_version: 4.9.0 +language_version: 3.13.14 +library_version: 4.11.0 preview_url_light: https://storage.googleapis.com/anyplot-images/plots/slope-basic/python/letsplot/plot-light.png preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/slope-basic/python/letsplot/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/slope-basic/python/letsplot/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/slope-basic/python/letsplot/plot-dark.html -quality_score: 85 +quality_score: null review: - strengths: - - Excellent spec compliance — all slopegraph requirements satisfied with correct - title format - - Strong storytelling via top-3 mover emphasis (differential line weight + alpha) - creates a clear focal story - - Proper Okabe-Ito palette with full theme-adaptive chrome; both light and dark - renders pass the readability check - - 'Perfect code quality: deterministic, clean, idiomatic letsplot usage' - - Genuine use of layer_tooltips() showcases letsplot's interactive differentiation - weaknesses: - - Label crowding on both sides (especially left, mid-range values) causes overlap - where 4-5 entities cluster near similar y-values - - geom_text label size=10 renders slightly small at 4800x2700 px; size 12-13 would - improve legibility - image_description: |- - Light render (plot-light.png): - Background: Warm off-white #FAF8F1 — correct light theme surface. - Chrome: Title "slope-basic · letsplot · anyplot.ai" in dark ink (#1A1A17), clearly readable. Y-axis label "Sales ($K)" and x-axis tick labels "Q1 Sales ($K)"/"Q4 Sales ($K)" in dark soft ink — all readable. Legend on right with "Change" header and green/orange entries, styled with elevated background. - Data: Green (#009E73) segments for increases, orange (#D55E00) for decreases. Top-3 movers (Cameras, Smartphones, Laptops) emphasized with bold lines (size=3.5, alpha=1.0); background lines dimmed (alpha=0.40). Endpoint labels on both sides with entity name + value. - Legibility verdict: PASS — all chrome text readable. Minor label overlap in mid-range ($80K-$120K) band. - - Dark render (plot-dark.png): - Background: Near-black #1A1A17 — correct dark theme surface. - Chrome: Title, axis labels, tick labels, and legend text all shift to light ink (#F0EFE8/#B8B7B0). All text readable against dark background. No dark-on-dark failures observed. Legend background uses elevated dark surface #242420. - Data: Data colors identical to light render — green #009E73 for increases, orange #D55E00 for decreases. Same visual hierarchy (bold top movers vs. dimmed background lines). - Legibility verdict: PASS — theme-adaptive chrome successfully applied to all elements. - criteria_checklist: - visual_quality: - score: 24 - max: 30 - items: - - id: VQ-01 - name: Text Legibility - score: 7 - max: 8 - passed: true - comment: All sizes explicitly set (title 28pt, y-label 22pt, ticks 18-20pt); - geom_text labels size=10 slightly small - - id: VQ-02 - name: No Overlap - score: 3 - max: 6 - passed: false - comment: Moderate label crowding in mid-range $80K-$120K band on left side; - main content readable - - id: VQ-03 - name: Element Visibility - score: 5 - max: 6 - passed: true - comment: Segments and points clearly visible; top-mover emphasis works well - - id: VQ-04 - name: Color Accessibility - score: 2 - max: 2 - passed: true - comment: Green/orange Okabe-Ito pair is CVD-safe with clear luminance contrast - - id: VQ-05 - name: Layout & Canvas - score: 3 - max: 4 - passed: true - comment: Extended x-limits give good label clearance; slight vertical crowding - - id: VQ-06 - name: Axis Labels & Title - score: 2 - max: 2 - passed: true - comment: Y-axis Sales ($K), x-axis tick labels Q1/Q4 Sales ($K) — descriptive - with units - - id: VQ-07 - name: Palette Compliance - score: 2 - max: 2 - passed: true - comment: 'Correct backgrounds #FAF8F1/#1A1A17; first series #009E73; full - theme-adaptive chrome in both renders' - design_excellence: - score: 13 - max: 20 - items: - - id: DE-01 - name: Aesthetic Sophistication - score: 5 - max: 8 - passed: true - comment: Visual hierarchy via differential line weight elevates design above - defaults; not publication-level - - id: DE-02 - name: Visual Refinement - score: 4 - max: 6 - passed: true - comment: X-grid removed, y-grid subtle, legend styled with elevated background - - id: DE-03 - name: Data Storytelling - score: 4 - max: 6 - passed: true - comment: Top-3 movers emphasized; increase/decrease color coding guides interpretation - spec_compliance: - score: 15 - max: 15 - items: - - id: SC-01 - name: Plot Type - score: 5 - max: 5 - passed: true - comment: Correct slopegraph using geom_segment + geom_point + geom_text - - id: SC-02 - name: Required Features - score: 4 - max: 4 - passed: true - comment: Labels at both endpoints, color-coded by direction, time-point axis - labels, 10 entities within 5-15 spec - - id: SC-03 - name: Data Mapping - score: 3 - max: 3 - passed: true - comment: X encodes time points, Y encodes values; segments correctly span - Q1 to Q4 - - id: SC-04 - name: Title & Legend - score: 3 - max: 3 - passed: true - comment: Title slope-basic · letsplot · anyplot.ai exactly correct; legend - Change with Increase/Decrease correct - data_quality: - score: 15 - max: 15 - items: - - id: DQ-01 - name: Feature Coverage - score: 6 - max: 6 - passed: true - comment: Shows both increases and decreases, crossing patterns, rank reversals, - varying magnitudes - - id: DQ-02 - name: Realistic Context - score: 5 - max: 5 - passed: true - comment: Consumer electronics quarterly sales is a real, neutral, comprehensible - business scenario - - id: DQ-03 - name: Appropriate Scale - score: 4 - max: 4 - passed: true - comment: $55K-$215K range for electronics product line sales is factually - plausible - code_quality: - score: 10 - max: 10 - items: - - id: CQ-01 - name: KISS Structure - score: 3 - max: 3 - passed: true - comment: Linear Imports to Data to Plot to Save; no functions or classes - - id: CQ-02 - name: Reproducibility - score: 2 - max: 2 - passed: true - comment: Data is hardcoded and fully deterministic - - id: CQ-03 - name: Clean Imports - score: 2 - max: 2 - passed: true - comment: All lets_plot imports actively used; only pandas and os as additional - deps - - id: CQ-04 - name: Code Elegance - score: 2 - max: 2 - passed: true - comment: Clean, Pythonic; layer_tooltips() is genuine letsplot interactivity, - not fake - - id: CQ-05 - name: Output & API - score: 1 - max: 1 - passed: true - comment: Saves plot-{THEME}.png (scale=3) and plot-{THEME}.html for both themes - library_mastery: - score: 8 - max: 10 - items: - - id: LM-01 - name: Idiomatic Usage - score: 5 - max: 5 - passed: true - comment: 'Exemplary ggplot grammar: layered geoms, aes(), scale_*_manual(), - theme(), labs(), ggsize()' - - id: LM-02 - name: Distinctive Features - score: 3 - max: 5 - passed: true - comment: Uses layer_tooltips() with title/line format-specifiers (letsplot-specific); - dual PNG+HTML export demonstrates interactive hybrid output - verdict: APPROVED -impl_tags: - dependencies: [] - techniques: - - layer-composition - - hover-tooltips - - html-export - patterns: - - wide-to-long - dataprep: [] - styling: - - alpha-blending - - grid-styling + strengths: [] + weaknesses: [] From f76b0352fe11372bbb5508d61679db02e4fdca85 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 25 Jul 2026 23:46:58 +0000 Subject: [PATCH 3/5] chore(letsplot): update quality score 88 and review feedback for slope-basic --- .../implementations/python/letsplot.py | 6 +- .../slope-basic/metadata/python/letsplot.yaml | 244 +++++++++++++++++- 2 files changed, 240 insertions(+), 10 deletions(-) diff --git a/plots/slope-basic/implementations/python/letsplot.py b/plots/slope-basic/implementations/python/letsplot.py index 7dfdb14cbd..deae6f3ae4 100644 --- a/plots/slope-basic/implementations/python/letsplot.py +++ b/plots/slope-basic/implementations/python/letsplot.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai slope-basic: Basic Slope Chart (Slopegraph) -Library: letsplot 4.9.0 | Python 3.13.13 -Quality: pending | Updated: 2026-07-25 +Library: letsplot 4.11.0 | Python 3.13.14 +Quality: 88/100 | Updated: 2026-07-25 """ import os diff --git a/plots/slope-basic/metadata/python/letsplot.yaml b/plots/slope-basic/metadata/python/letsplot.yaml index 07fff64323..b3476febb1 100644 --- a/plots/slope-basic/metadata/python/letsplot.yaml +++ b/plots/slope-basic/metadata/python/letsplot.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for letsplot implementation of slope-basic -# Auto-generated by impl-generate.yml - library: letsplot language: python specification_id: slope-basic created: '2025-12-23T20:47:50Z' -updated: '2026-07-25T23:42:02Z' +updated: '2026-07-25T23:46:58Z' generated_by: claude-sonnet workflow_run: 30179644496 issue: 981 @@ -15,7 +12,240 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/slope-bas preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/slope-basic/python/letsplot/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/slope-basic/python/letsplot/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/slope-basic/python/letsplot/plot-dark.html -quality_score: null +quality_score: 88 review: - strengths: [] - weaknesses: [] + strengths: + - 'Excellent data storytelling: the top-3 movers by absolute change render bold + and fully opaque while the remaining lines are dimmed to alpha=0.40, creating + a clear visual hierarchy that guides the eye to the biggest Q1-to-Q4 changes' + - Correct, idiomatic slope-chart construction via geom_segment + geom_point + geom_text + layering, with entity+value labels placed at both endpoints for legibility + - 'Distinctive lets-plot-specific feature: separate layer_tooltips() configs for + top movers (with a "Top mover" title marker) vs. normal lines, a genuine interactive + touch that adds value in the HTML export' + - Semantic color mapping (brand green = Increase, matte red = Decrease) matches + the Imprint palette's documented semantic-exception guidance for gain/loss framing + - 'Fully theme-adaptive chrome: data colors are pixel-identical between light/dark + renders, backgrounds are correct at #FAF8F1/#1A1A17, and all text tokens (INK/INK_SOFT) + are threaded through title, axis, and legend elements' + - Clean, deterministic, single-scope script — no functions/classes, all imports + used, no dead code + weaknesses: + - 'Full rectangular panel border (all four spines) is visible in both renders instead + of the default L-shaped (bottom+left only) frame the style guide calls for; a + slope chart isn''t the ''enclosed heatmap grid'' exception. Fix: remove the panel + border in theme() (e.g. panel_border=element_blank()) so only the bottom/left + axis lines remain.' + - The alpha-blended (0.40) background lines lean on the red/green hue difference + as the primary distinguishing signal for red-green color-vision-deficient viewers; + slope direction is a redundant cue but becomes subtle at low alpha across 10 overlapping + lines. Raise the alpha floor for the dimmed group (e.g. to ~0.5-0.55) or add a + secondary encoding (linetype) to keep CVD-safety strong even when dimmed. + image_description: |- + Light render (plot-light.png): + Background: Warm off-white, consistent with #FAF8F1 — not pure white. + Chrome: Title "slope-basic · python · letsplot · anyplot.ai" in dark ink, clearly readable. Y-axis title "Sales ($K)" and tick labels (50-300) in dark/soft-dark ink, all legible. X-axis carries no title but uses tick labels "Q1 Sales ($K)" / "Q4 Sales ($K)" as the two time-point axis labels, dark and legible. A full rectangular panel border (all four sides) is visible, which deviates from the L-shaped spine default. Horizontal grid lines are subtle and only on the y-axis. + Data: 10 entities connected by segments between Q1 and Q4 x-positions. First-series green (#009E73) marks "Increase", matte red (#AE3030) marks "Decrease" — matches Imprint semantic exception for gain/loss. Top-3 movers (Headphones, Smart TVs, Smartphones by abs. change) render as bold, fully opaque lines; the other 7 lines are dimmed to ~40% alpha, creating clear visual hierarchy. Entity + value labels (e.g. "Cameras ($270K)") sit at both endpoints without overlapping each other or the data. + Legibility verdict: PASS + + Dark render (plot-dark.png): + Background: Warm near-black, consistent with #1A1A17 — not pure black. + Chrome: Title, axis title, and tick labels are all rendered in light ink and clearly readable against the dark background — no dark-on-dark failures observed. The same full rectangular panel border issue is present here too (all four sides visible, light-colored on dark bg). + Data: Colors are pixel-identical to the light render (green #009E73 / red #AE3030), confirming only chrome flipped between themes. Same top-mover bold/dim emphasis pattern holds. + Legibility verdict: PASS + criteria_checklist: + visual_quality: + score: 28 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 7 + max: 8 + passed: true + comment: All text explicitly sized and readable in both themes; entity labels + at size=4.2mm are legible but modest at full scale + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: Data spacing (min gap ~20 at both endpoints) keeps entity+value labels + from colliding + - id: VQ-03 + name: Element Visibility + score: 6 + max: 6 + passed: true + comment: Sparse data (10 entities) with prominent markers (size=6) and bold + top-mover emphasis + - id: VQ-04 + name: Color Accessibility + score: 1 + max: 2 + passed: false + comment: Direction relies on red/green as primary signal; dimmed 40% alpha + lines reduce CVD distinguishability even with redundant slope-direction + cue + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: Canvas dimension gate passed; no overflow or clipping observed + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Y-axis labeled with units; x-axis tick labels serve as time-point + labels per spec notes + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series #009E73, semantic red for decrease, correct theme-adaptive + backgrounds, identical data colors across themes' + design_excellence: + score: 13 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: Thoughtful top-mover emphasis and semantic color choice, but the + full panel border undercuts the minimalist polish + - id: DE-02 + name: Visual Refinement + score: 3 + max: 6 + passed: false + comment: Grid subtle and whitespace generous, but full rectangular panel border + (all four spines) instead of the L-shaped default + - id: DE-03 + name: Data Storytelling + score: 5 + max: 6 + passed: true + comment: Bold vs. dimmed lines create a clear focal point on the top-3 movers + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Correct slopegraph connecting two time points + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Endpoint labels, direction color-coding, labeled vertical axes, 10 + entities (within 5-15 range) + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: X = time point, Y = value, correctly mapped + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title matches mandated format exactly; legend labels 'Increase'/'Decrease' + match direction categories + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: Covers entities, dual time-point values, direction encoding, and + top-mover emphasis + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Consumer electronics quarterly sales — plausible and neutral + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Sales figures ($50K-$300K) are sensible for the domain + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: No functions/classes, flat top-level script + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: Fully deterministic hardcoded data, no randomness + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: All imported names are used + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Appropriate complexity, no fake UI/interactivity + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot-{THEME}.png (scale=4) and plot-{THEME}.html correctly + library_mastery: + score: 7 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: Proper grammar-of-graphics layering with geom_segment/geom_point/geom_text + and scale_color_manual + - id: LM-02 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: Custom layer_tooltips() differentiated for top movers is a genuine + lets-plot-specific touch + verdict: REJECTED +impl_tags: + dependencies: [] + techniques: + - annotations + - layer-composition + - hover-tooltips + - html-export + patterns: + - data-generation + dataprep: [] + styling: + - alpha-blending From d1b5ab5858304c9051b79d0ff890f31a2fc4938d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 25 Jul 2026 23:58:40 +0000 Subject: [PATCH 4/5] fix(letsplot): address review feedback for slope-basic Attempt 1/4 - fixes based on AI review --- plots/slope-basic/implementations/python/letsplot.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plots/slope-basic/implementations/python/letsplot.py b/plots/slope-basic/implementations/python/letsplot.py index deae6f3ae4..dbdda1e578 100644 --- a/plots/slope-basic/implementations/python/letsplot.py +++ b/plots/slope-basic/implementations/python/letsplot.py @@ -1,4 +1,4 @@ -""" anyplot.ai +"""anyplot.ai slope-basic: Basic Slope Chart (Slopegraph) Library: letsplot 4.11.0 | Python 3.13.14 Quality: 88/100 | Updated: 2026-07-25 @@ -23,6 +23,7 @@ labs, layer_tooltips, scale_color_manual, + scale_linetype_manual, scale_x_continuous, scale_y_continuous, theme, @@ -130,9 +131,9 @@ # Background lines: dimmed to let top movers stand out + geom_segment( data=seg_normal, - mapping=aes(x="x_start", y="y_start", xend="x_end", yend="y_end", color="direction"), + mapping=aes(x="x_start", y="y_start", xend="x_end", yend="y_end", color="direction", linetype="direction"), size=1.8, - alpha=0.40, + alpha=0.55, tooltips=_tooltip_normal, ) # Top-mover lines: bold, fully opaque — emphasises the biggest Q1→Q4 changes @@ -151,13 +152,16 @@ data=df_right, mapping=aes(x="x", y="value", label="label"), hjust=0, nudge_x=0.07, size=4.2, color=INK_SOFT ) + scale_color_manual(values={"Increase": COLOR_INCREASE, "Decrease": COLOR_DECREASE}) + + scale_linetype_manual(values={"Increase": "solid", "Decrease": "dashed"}, guide="none") + scale_x_continuous(breaks=[0, 1], labels=["Q1 Sales ($K)", "Q4 Sales ($K)"], limits=[-1.05, 2.05]) + scale_y_continuous(limits=[20, 300]) + labs(title="slope-basic · python · letsplot · anyplot.ai", x="", y="Sales ($K)", color="Change") + theme_minimal() + theme( plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG), - panel_background=element_rect(fill=PAGE_BG), + # color matches fill so the rect draws no border (theme_minimal has no + # spines by default — the "remove all spines" clean-look alternative) + panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG), panel_grid_major_y=element_line(color=GRID_COLOR, size=0.3), panel_grid_major_x=element_blank(), panel_grid_minor=element_blank(), From 8e1452a34285db993dd9edcd295a7d926de72d99 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Jul 2026 00:03:37 +0000 Subject: [PATCH 5/5] chore(letsplot): update quality score 94 and review feedback for slope-basic --- .../implementations/python/letsplot.py | 4 +- .../slope-basic/metadata/python/letsplot.yaml | 159 +++++++++--------- 2 files changed, 78 insertions(+), 85 deletions(-) diff --git a/plots/slope-basic/implementations/python/letsplot.py b/plots/slope-basic/implementations/python/letsplot.py index dbdda1e578..6d35bcc7a4 100644 --- a/plots/slope-basic/implementations/python/letsplot.py +++ b/plots/slope-basic/implementations/python/letsplot.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai slope-basic: Basic Slope Chart (Slopegraph) Library: letsplot 4.11.0 | Python 3.13.14 -Quality: 88/100 | Updated: 2026-07-25 +Quality: 94/100 | Updated: 2026-07-26 """ import os diff --git a/plots/slope-basic/metadata/python/letsplot.yaml b/plots/slope-basic/metadata/python/letsplot.yaml index b3476febb1..09b9a9a437 100644 --- a/plots/slope-basic/metadata/python/letsplot.yaml +++ b/plots/slope-basic/metadata/python/letsplot.yaml @@ -2,7 +2,7 @@ library: letsplot language: python specification_id: slope-basic created: '2025-12-23T20:47:50Z' -updated: '2026-07-25T23:46:58Z' +updated: '2026-07-26T00:03:36Z' generated_by: claude-sonnet workflow_run: 30179644496 issue: 981 @@ -12,50 +12,50 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/slope-bas preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/slope-basic/python/letsplot/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/slope-basic/python/letsplot/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/slope-basic/python/letsplot/plot-dark.html -quality_score: 88 +quality_score: 94 review: strengths: - - 'Excellent data storytelling: the top-3 movers by absolute change render bold - and fully opaque while the remaining lines are dimmed to alpha=0.40, creating - a clear visual hierarchy that guides the eye to the biggest Q1-to-Q4 changes' - - Correct, idiomatic slope-chart construction via geom_segment + geom_point + geom_text - layering, with entity+value labels placed at both endpoints for legibility - - 'Distinctive lets-plot-specific feature: separate layer_tooltips() configs for - top movers (with a "Top mover" title marker) vs. normal lines, a genuine interactive - touch that adds value in the HTML export' - - Semantic color mapping (brand green = Increase, matte red = Decrease) matches - the Imprint palette's documented semantic-exception guidance for gain/loss framing - - 'Fully theme-adaptive chrome: data colors are pixel-identical between light/dark - renders, backgrounds are correct at #FAF8F1/#1A1A17, and all text tokens (INK/INK_SOFT) - are threaded through title, axis, and legend elements' + - Panel-border issue from attempt 1 is fully resolved — both renders now use a clean, + spine-free frame (only the y grid lines remain) instead of a full box border + - 'Color-blindness fix applied: seg_normal now carries scale_linetype_manual (solid + = Increase, dashed = Decrease) as a redundant cue on top of color, directly addressing + the attempt-1 VQ-04 finding' + - 'Excellent data storytelling: top-3 movers by absolute change (Headphones, Smart + TVs, Smartphones) render bold and fully opaque while the other 7 lines are dimmed, + creating a clear visual hierarchy' + - 'Distinctive lets-plot feature: separate layer_tooltips() configs for top movers + (with a "★ Top mover" title) vs. normal lines — genuine library-specific interactivity, + not just a generic geom_segment chart' + - Entity + value labels at both endpoints, evenly spaced (~20-25 units apart) with + zero overlap across 10 entities on both sides + - 'Fully theme-adaptive chrome: data colors are pixel-identical across light/dark + renders, correct #FAF8F1/#1A1A17 backgrounds, all text tokens legible in both + themes' - Clean, deterministic, single-scope script — no functions/classes, all imports used, no dead code weaknesses: - - 'Full rectangular panel border (all four spines) is visible in both renders instead - of the default L-shaped (bottom+left only) frame the style guide calls for; a - slope chart isn''t the ''enclosed heatmap grid'' exception. Fix: remove the panel - border in theme() (e.g. panel_border=element_blank()) so only the bottom/left - axis lines remain.' - - The alpha-blended (0.40) background lines lean on the red/green hue difference - as the primary distinguishing signal for red-green color-vision-deficient viewers; - slope direction is a redundant cue but becomes subtle at low alpha across 10 overlapping - lines. Raise the alpha floor for the dimmed group (e.g. to ~0.5-0.55) or add a - secondary encoding (linetype) to keep CVD-safety strong even when dimmed. + - Title 'slope-basic · python · letsplot · anyplot.ai' occupies only ~45% of plot + width at fontsize=16 — slightly under the 50-70% comfortable-fill guideline (not + a deduction, since it neither overflows nor looks squeezed, but a touch more fontsize + would improve visual balance) + - At small (400px) preview scale the 10 entity+value labels become quite small — + an inherent readability tension of a 10-entity slope chart rather than a fixable + implementation flaw, but worth noting if entity count grows in future regenerations image_description: |- Light render (plot-light.png): - Background: Warm off-white, consistent with #FAF8F1 — not pure white. - Chrome: Title "slope-basic · python · letsplot · anyplot.ai" in dark ink, clearly readable. Y-axis title "Sales ($K)" and tick labels (50-300) in dark/soft-dark ink, all legible. X-axis carries no title but uses tick labels "Q1 Sales ($K)" / "Q4 Sales ($K)" as the two time-point axis labels, dark and legible. A full rectangular panel border (all four sides) is visible, which deviates from the L-shaped spine default. Horizontal grid lines are subtle and only on the y-axis. - Data: 10 entities connected by segments between Q1 and Q4 x-positions. First-series green (#009E73) marks "Increase", matte red (#AE3030) marks "Decrease" — matches Imprint semantic exception for gain/loss. Top-3 movers (Headphones, Smart TVs, Smartphones by abs. change) render as bold, fully opaque lines; the other 7 lines are dimmed to ~40% alpha, creating clear visual hierarchy. Entity + value labels (e.g. "Cameras ($270K)") sit at both endpoints without overlapping each other or the data. + Background: Warm off-white, consistent with #FAF8F1 — not pure white, not dark. + Chrome: Title "slope-basic · python · letsplot · anyplot.ai" in dark ink, fully visible and not clipped at the top or left edge. Y-axis "Sales ($K)" title and 50-300 tick labels in dark/soft-dark ink, all readable. X-axis has no title text but uses "Q1 Sales ($K)" / "Q4 Sales ($K)" tick labels as the two time-point axis labels. Subtle horizontal-only grid (vertical grid removed). No panel border/box — clean spine-free frame (attempt-1 issue resolved). + Data: First-series green is #009E73 (Increase), matte red #AE3030 (Decrease) — matches Imprint semantic-exception guidance. Top-3 movers by absolute change (Headphones, Smart TVs, Smartphones) render bold/fully opaque; the other 7 lines are dimmed (alpha=0.55) AND use a linetype difference (solid=Increase, dashed=Decrease) as a redundant CVD-safe cue. Entity+value labels sit at both endpoints (e.g. "Cameras ($270K)"), evenly spaced with no overlap. Legend "Change" (Increase/Decrease) sits clear of the data area with no clipping. Legibility verdict: PASS Dark render (plot-dark.png): - Background: Warm near-black, consistent with #1A1A17 — not pure black. - Chrome: Title, axis title, and tick labels are all rendered in light ink and clearly readable against the dark background — no dark-on-dark failures observed. The same full rectangular panel border issue is present here too (all four sides visible, light-colored on dark bg). - Data: Colors are pixel-identical to the light render (green #009E73 / red #AE3030), confirming only chrome flipped between themes. Same top-mover bold/dim emphasis pattern holds. + Background: Warm near-black, consistent with #1A1A17 — not pure black, not light. + Chrome: Same layout on the dark surface. Title, y-axis title, and tick labels are all rendered in light ink (INK/INK_SOFT tokens) and clearly readable — no dark-on-dark failures anywhere. Grid lines subtle but visible. No panel border, matching the light render. + Data: Colors are pixel-identical to the light render (#009E73 green / #AE3030 red), confirming only chrome flipped between themes. Same bold-top-mover / dimmed-plus-dashed-others hierarchy holds up equally well on dark. Legibility verdict: PASS criteria_checklist: visual_quality: - score: 28 + score: 29 max: 30 items: - id: VQ-01 @@ -63,74 +63,68 @@ review: score: 7 max: 8 passed: true - comment: All text explicitly sized and readable in both themes; entity labels - at size=4.2mm are legible but modest at full scale + comment: All text readable in both themes; sizes explicit and hierarchical - id: VQ-02 name: No Overlap score: 6 max: 6 passed: true - comment: Data spacing (min gap ~20 at both endpoints) keeps entity+value labels - from colliding + comment: 10 evenly-spaced endpoint labels on each side, zero collisions - id: VQ-03 name: Element Visibility score: 6 max: 6 passed: true - comment: Sparse data (10 entities) with prominent markers (size=6) and bold - top-mover emphasis + comment: Marker size 6 with bold/dimmed contrast appropriate for 10-entity + density - id: VQ-04 name: Color Accessibility - score: 1 + score: 2 max: 2 - passed: false - comment: Direction relies on red/green as primary signal; dimmed 40% alpha - lines reduce CVD distinguishability even with redundant slope-direction - cue + passed: true + comment: Linetype (solid/dashed) now backs the color coding, fixing the attempt-1 + CVD finding - id: VQ-05 name: Layout & Canvas score: 4 max: 4 passed: true - comment: Canvas dimension gate passed; no overflow or clipping observed + comment: 3200x1800 canvas confirmed, no overflow/clipping, good proportions - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: Y-axis labeled with units; x-axis tick labels serve as time-point - labels per spec notes + comment: Sales ($K) with units; Q1/Q4 axis labels descriptive - id: VQ-07 name: Palette Compliance score: 2 max: 2 passed: true - comment: 'First series #009E73, semantic red for decrease, correct theme-adaptive - backgrounds, identical data colors across themes' + comment: '#009E73 first series, correct theme backgrounds both renders' design_excellence: - score: 13 + score: 16 max: 20 items: - id: DE-01 name: Aesthetic Sophistication - score: 5 + score: 6 max: 8 passed: true - comment: Thoughtful top-mover emphasis and semantic color choice, but the - full panel border undercuts the minimalist polish + comment: Semantic color, top-mover emphasis, custom tooltips — panel border + issue from attempt 1 resolved - id: DE-02 name: Visual Refinement - score: 3 + score: 5 max: 6 - passed: false - comment: Grid subtle and whitespace generous, but full rectangular panel border - (all four spines) instead of the L-shaped default + passed: true + comment: Spine-free frame, subtle y-only grid, generous whitespace - id: DE-03 name: Data Storytelling score: 5 max: 6 passed: true - comment: Bold vs. dimmed lines create a clear focal point on the top-3 movers + comment: Bold vs. dimmed lines create a clear focal point on top-3 movers spec_compliance: score: 15 max: 15 @@ -140,27 +134,26 @@ review: score: 5 max: 5 passed: true - comment: Correct slopegraph connecting two time points + comment: Correct slopegraph construction - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Endpoint labels, direction color-coding, labeled vertical axes, 10 - entities (within 5-15 range) + comment: Endpoint labels, direction color-coding, time-point axis labels, + 10 entities - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: X = time point, Y = value, correctly mapped + comment: X=time point, Y=Sales, full data range shown - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: Title matches mandated format exactly; legend labels 'Increase'/'Decrease' - match direction categories + comment: Title matches mandated format; legend labels match direction values data_quality: score: 15 max: 15 @@ -170,20 +163,19 @@ review: score: 6 max: 6 passed: true - comment: Covers entities, dual time-point values, direction encoding, and - top-mover emphasis + comment: 'Shows all slopegraph aspects: rank change, magnitude, direction' - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Consumer electronics quarterly sales — plausible and neutral + comment: Plausible, neutral consumer-electronics quarterly sales data - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: Sales figures ($50K-$300K) are sensible for the domain + comment: Sensible $K sales values with meaningful spread code_quality: score: 10 max: 10 @@ -193,59 +185,60 @@ review: score: 3 max: 3 passed: true - comment: No functions/classes, flat top-level script + comment: No functions/classes, flat script - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: Fully deterministic hardcoded data, no randomness + comment: Fully deterministic, no randomness - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: All imported names are used + comment: All imports used - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: Appropriate complexity, no fake UI/interactivity + comment: No fake UI; real letsplot tooltips - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves plot-{THEME}.png (scale=4) and plot-{THEME}.html correctly + comment: Saves plot-{THEME}.png (scale=4) and plot-{THEME}.html library_mastery: - score: 7 + score: 9 max: 10 items: - id: LM-01 name: Idiomatic Usage - score: 4 + score: 5 max: 5 passed: true - comment: Proper grammar-of-graphics layering with geom_segment/geom_point/geom_text - and scale_color_manual + comment: Proper ggplot-grammar layering, theme() customization - id: LM-02 name: Distinctive Features - score: 3 + score: 4 max: 5 passed: true - comment: Custom layer_tooltips() differentiated for top movers is a genuine - lets-plot-specific touch - verdict: REJECTED + comment: Custom layer_tooltips() per-layer, differentiated for top movers + verdict: APPROVED impl_tags: dependencies: [] techniques: + - slopegraph - annotations - - layer-composition - - hover-tooltips - - html-export + - tooltips + - highlight-emphasis patterns: - data-generation + - iteration-over-groups dataprep: [] styling: + - publication-ready - alpha-blending + - semantic-color-coding