From af09161ebf711953916ea5d94affc767647ee3a9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 10 Jun 2026 00:51:08 +0000 Subject: [PATCH 1/5] feat(letsplot): implement line-yield-curve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regen from quality 91. Addressed: - Canvas: fixed to canonical ggsize(800, 450) + scale=4 → 3200×1800 px (was 1600×900 + scale=3) - Theme-adaptive chrome: added ANYPLOT_THEME env var, PAGE_BG/INK/INK_SOFT/ELEVATED_BG tokens - Colors: corrected to Imprint palette canonical order (#009E73 first), using pd.Categorical for deterministic assignment - Output: save as plot-{THEME}.png and plot-{THEME}.html (was plot.png without theme suffix) - Title: updated pyplots.ai → anyplot.ai - Font sizes: aligned to library prompt (title=16, axis_title=12, axis_text=10, legend=10) - Tick crowding: replaced 3M/1Y with 6M/1Y to eliminate short-maturity crowding - Inversion ribbon: uses #AE3030 (Imprint semantic red) for consistency --- .../implementations/python/letsplot.py | 88 +++++++++++-------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/plots/line-yield-curve/implementations/python/letsplot.py b/plots/line-yield-curve/implementations/python/letsplot.py index d7544cca78..5091fccfa7 100644 --- a/plots/line-yield-curve/implementations/python/letsplot.py +++ b/plots/line-yield-curve/implementations/python/letsplot.py @@ -1,29 +1,43 @@ -""" pyplots.ai +"""anyplot.ai line-yield-curve: Yield Curve (Interest Rate Term Structure) -Library: letsplot 4.9.0 | Python 3.14.3 -Quality: 91/100 | Created: 2026-03-14 +Library: letsplot | Python """ +import os + import pandas as pd from lets_plot import * # noqa: F403 -from lets_plot.export import ggsave as export_ggsave LetsPlot.setup_html() # noqa: F405 -# Data - U.S. Treasury yield curves on three dates +THEME = os.getenv("ANYPLOT_THEME", "light") + +# Theme-adaptive chrome tokens — Imprint palette +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" + +# Imprint categorical palette — canonical order, first series always #009E73 +IMPRINT_PALETTE = ["#009E73", "#C475FD", "#4467A3", "#BD8233", "#AE3030", "#2ABCCD", "#954477", "#99B314"] + +# Data — U.S. Treasury yield curves on three dates maturities = ["1M", "3M", "6M", "1Y", "2Y", "3Y", "5Y", "7Y", "10Y", "20Y", "30Y"] maturity_years = [1 / 12, 0.25, 0.5, 1, 2, 3, 5, 7, 10, 20, 30] # Normal upward-sloping curve (Jan 2018) yields_normal = [1.28, 1.53, 1.72, 1.89, 2.05, 2.19, 2.41, 2.55, 2.66, 2.83, 2.96] -# Inverted curve (Aug 2019 - recession signal) +# Inverted curve (Aug 2019 — recession signal) yields_inverted = [2.09, 2.00, 1.92, 1.75, 1.52, 1.46, 1.44, 1.48, 1.52, 1.77, 1.97] # Steep post-pandemic curve (Mar 2021) yields_steep = [0.03, 0.03, 0.04, 0.07, 0.14, 0.32, 0.83, 1.18, 1.62, 2.19, 2.35] +# Use ordered Categorical so color assignments follow the named order +DATE_ORDER = ["Jan 2018 (Normal)", "Aug 2019 (Inverted)", "Mar 2021 (Steep)"] + rows = [] for i in range(len(maturities)): rows.append( @@ -52,21 +66,18 @@ ) df = pd.DataFrame(rows) +df["date"] = pd.Categorical(df["date"], categories=DATE_ORDER, ordered=True) -# Inversion region: shade between inverted curve and the 10Y yield baseline -# Shows where short-term rates exceed the long-term benchmark +# Inversion region: shade where short-term yields exceed the 10Y baseline ten_year_yield = yields_inverted[8] # 10Y = 1.52% inv_mat = [maturity_years[i] for i in range(9)] # 1M through 10Y inv_upper = [yields_inverted[i] for i in range(9)] inv_lower = [ten_year_yield] * 9 inversion_df = pd.DataFrame({"maturity_years": inv_mat, "y_upper": inv_upper, "y_lower": inv_lower}) -# Reduce x-axis labels to avoid overlap at short maturities -tick_positions = [0.25, 1, 2, 5, 10, 20, 30] -tick_labels = ["3M", "1Y", "2Y", "5Y", "10Y", "20Y", "30Y"] - -# Colorblind-safe palette: blue, amber, teal-green -colors = ["#306998", "#E69F00", "#009E73"] +# Sparse ticks — removes 3M/1Y crowding at short maturities +tick_positions = [0.5, 1, 2, 5, 10, 20, 30] +tick_labels_x = ["6M", "1Y", "2Y", "5Y", "10Y", "20Y", "30Y"] plot = ( ggplot() # noqa: F405 @@ -74,14 +85,14 @@ + geom_ribbon( # noqa: F405 data=inversion_df, mapping=aes(x="maturity_years", ymin="y_lower", ymax="y_upper"), # noqa: F405 - fill="#C44E52", - alpha=0.2, + fill="#AE3030", + alpha=0.18, ) - # Yield curve lines with tooltips + # Yield curve lines with interactive tooltips + geom_line( # noqa: F405 data=df, mapping=aes(x="maturity_years", y="yield_pct", color="date"), # noqa: F405 - size=2.5, + size=1.0, tooltips=layer_tooltips() # noqa: F405 .line("@date") .line("Maturity: @maturity") @@ -90,36 +101,41 @@ + geom_point( # noqa: F405 data=df, mapping=aes(x="maturity_years", y="yield_pct", color="date"), # noqa: F405 - size=5, + size=2.5, alpha=0.85, ) - # Annotation for inversion region + # Inversion region label — geom_text size is in mm, not pt + geom_text( # noqa: F405 aes(x="x", y="y", label="label"), # noqa: F405 - data=pd.DataFrame({"x": [1.5], "y": [2.18], "label": ["Inversion Region"]}), - color="#C44E52", - size=12, + data=pd.DataFrame({"x": [1.5], "y": [2.15], "label": ["Inversion Region"]}), + color="#AE3030", + size=4, fontface="italic", ) - + scale_color_manual(values=colors) # noqa: F405 - + scale_x_continuous(breaks=tick_positions, labels=tick_labels) # noqa: F405 + + scale_color_manual(values=IMPRINT_PALETTE[:3]) # noqa: F405 + + scale_x_continuous(breaks=tick_positions, labels=tick_labels_x) # noqa: F405 + labs( # noqa: F405 - x="Maturity", y="Yield (%)", title="line-yield-curve · letsplot · pyplots.ai", color="" + x="Maturity", y="Yield (%)", title="line-yield-curve · letsplot · anyplot.ai", color="" ) - + ggsize(1600, 900) # noqa: F405 + + ggsize(800, 450) # 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_position="top", + plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG), # noqa: F405 + panel_background=element_rect(fill=PAGE_BG), # noqa: F405 + panel_grid_major_y=element_line(color=INK_SOFT, size=0.2), # noqa: F405 panel_grid_major_x=element_blank(), # noqa: F405 panel_grid_minor=element_blank(), # noqa: F405 - panel_grid_major_y=element_line(color="#E0E0E0", size=0.5), # noqa: F405 + axis_title=element_text(color=INK, size=12), # noqa: F405 + axis_text=element_text(color=INK_SOFT, size=10), # noqa: F405 + axis_line=element_line(color=INK_SOFT), # noqa: F405 + plot_title=element_text(color=INK, size=16), # noqa: F405 + legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT), # noqa: F405 + legend_text=element_text(color=INK_SOFT, size=10), # noqa: F405 + legend_title=element_text(color=INK), # noqa: F405 + legend_position="top", ) ) -# Save -export_ggsave(plot, "plot.png", path=".", scale=3) -export_ggsave(plot, "plot.html", path=".") +# Save PNG (scale=4 → 800×450 × 4 = 3200×1800 px) and HTML for the current theme +ggsave(plot, f"plot-{THEME}.png", path=".", scale=4) # noqa: F405 +ggsave(plot, f"plot-{THEME}.html", path=".") # noqa: F405 From de25b56cc0b69309224879d0d7c6237031175927 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 10 Jun 2026 00:51:21 +0000 Subject: [PATCH 2/5] chore(letsplot): add metadata for line-yield-curve --- .../metadata/python/letsplot.yaml | 230 ++---------------- 1 file changed, 16 insertions(+), 214 deletions(-) diff --git a/plots/line-yield-curve/metadata/python/letsplot.yaml b/plots/line-yield-curve/metadata/python/letsplot.yaml index 381f125903..626c2aabdb 100644 --- a/plots/line-yield-curve/metadata/python/letsplot.yaml +++ b/plots/line-yield-curve/metadata/python/letsplot.yaml @@ -1,219 +1,21 @@ +# Per-library metadata for letsplot implementation of line-yield-curve +# Auto-generated by impl-generate.yml + library: letsplot +language: python specification_id: line-yield-curve created: '2026-03-14T22:15:13Z' -updated: '2026-03-14T22:29:13Z' -generated_by: claude-opus-4-5-20251101 -workflow_run: 23097460574 +updated: '2026-06-10T00:51:21Z' +generated_by: claude-sonnet +workflow_run: 27245197539 issue: 4664 -python_version: 3.14.3 -library_version: 4.9.0 -preview_url: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/letsplot/plot.png -preview_html: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/letsplot/plot.html -quality_score: 91 +language_version: 3.13.13 +library_version: 4.10.1 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/python/letsplot/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/python/letsplot/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/python/letsplot/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/python/letsplot/plot-dark.html +quality_score: null review: - strengths: - - Excellent data storytelling with inversion region shading and annotation highlighting - the recession signal - - Colorblind-safe palette with strong differentiation between three economic regimes - - Perfect spec compliance with all required features including maturity_years spacing - and multi-curve comparison - - Realistic Treasury yield data across three distinct economic periods - - Clean well-structured code with proper lets-plot idioms - weaknesses: - - Minor tick label crowding at short maturities (3M and 1Y are close together) - image_description: 'The plot displays three U.S. Treasury yield curves on a clean - white background. The title "line-yield-curve · letsplot · pyplots.ai" appears - at the top left. A top-center legend identifies three series: "Jan 2018 (Normal)" - in dark blue, "Aug 2019 (Inverted)" in amber/gold, and "Mar 2021 (Steep)" in teal - green. The x-axis is labeled "Maturity" with ticks at 3M, 1Y, 2Y, 5Y, 10Y, 20Y, - 30Y using proper numeric spacing. The y-axis is labeled "Yield (%)". A light pink/red - shaded ribbon in the upper-left highlights the inversion region where short-term - rates exceed the 10Y yield, with italic red "Inversion Region" text. The blue - normal curve rises smoothly from ~1.28% to ~2.96%. The amber inverted curve starts - high at ~2.09% and dips to ~1.44% before recovering. The teal steep curve starts - near 0% and rises sharply to ~2.35%. Each curve has circular markers at data points. - Only subtle horizontal y-axis gridlines are shown.' - criteria_checklist: - visual_quality: - score: 29 - 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' - - id: VQ-02 - name: No Overlap - score: 5 - max: 6 - passed: true - comment: 3M and 1Y tick labels slightly close due to numeric x-axis spacing - but readable - - id: VQ-03 - name: Element Visibility - score: 6 - max: 6 - passed: true - comment: Lines size=2.5 and points size=5 well-visible for 33 data points - - id: VQ-04 - name: Color Accessibility - score: 4 - max: 4 - passed: true - comment: Okabe-Ito-inspired colorblind-safe palette - - id: VQ-05 - name: Layout & Canvas - score: 4 - max: 4 - passed: true - comment: 1600x900 at scale=3, plot fills canvas well - - id: VQ-06 - name: Axis Labels & Title - score: 2 - max: 2 - passed: true - comment: 'Descriptive labels with units: Maturity, Yield (%)' - design_excellence: - score: 15 - max: 20 - items: - - id: DE-01 - name: Aesthetic Sophistication - score: 6 - max: 8 - passed: true - comment: Custom colorblind-safe palette, professional financial chart aesthetic - - id: DE-02 - name: Visual Refinement - score: 4 - max: 6 - passed: true - comment: theme_minimal, x-grid removed, subtle y-grid, legend at top - - id: DE-03 - name: Data Storytelling - score: 5 - max: 6 - passed: true - comment: Inversion region shading and annotation create clear recession signal - narrative - spec_compliance: - score: 15 - max: 15 - items: - - id: SC-01 - name: Plot Type - score: 5 - max: 5 - passed: true - comment: Correct line chart for yield curves - - id: SC-02 - name: Required Features - score: 4 - max: 4 - passed: true - comment: 'All spec features present: multi-curve, maturity_years spacing, - inversion highlight, legend' - - id: SC-03 - name: Data Mapping - score: 3 - max: 3 - passed: true - comment: maturity_years on x, yield_pct on y, correctly mapped - - id: SC-04 - name: Title & Legend - score: 3 - max: 3 - passed: true - comment: Correct title format, descriptive legend labels - data_quality: - score: 15 - max: 15 - items: - - id: DQ-01 - name: Feature Coverage - score: 6 - max: 6 - passed: true - comment: Shows normal, inverted, and steep yield curve shapes - - id: DQ-02 - name: Realistic Context - score: 5 - max: 5 - passed: true - comment: Real U.S. Treasury yield curve scenarios with plausible dates and - rates - - id: DQ-03 - name: Appropriate Scale - score: 4 - max: 4 - passed: true - comment: Yields in 0-3% range, realistic for depicted periods - code_quality: - score: 10 - max: 10 - items: - - id: CQ-01 - name: KISS Structure - score: 3 - max: 3 - passed: true - comment: Clean imports-data-plot-save structure - - id: CQ-02 - name: Reproducibility - score: 2 - max: 2 - passed: true - comment: Deterministic hardcoded data - - id: CQ-03 - name: Clean Imports - score: 2 - max: 2 - passed: true - comment: All imports used - - id: CQ-04 - name: Code Elegance - score: 2 - max: 2 - passed: true - comment: Appropriate complexity, clean DataFrame and plot construction - - id: CQ-05 - name: Output & API - score: 1 - max: 1 - passed: true - comment: Saves as plot.png via export_ggsave with scale=3 - library_mastery: - score: 7 - max: 10 - items: - - id: LM-01 - name: Idiomatic Usage - score: 4 - max: 5 - passed: true - comment: Proper ggplot grammar with multiple geoms, scales, theme customization - - id: LM-02 - name: Distinctive Features - score: 3 - max: 5 - passed: true - comment: Uses layer_tooltips for interactive hover, HTML export, ggsize - verdict: APPROVED -impl_tags: - dependencies: [] - techniques: - - annotations - - layer-composition - - hover-tooltips - - manual-ticks - - html-export - patterns: - - data-generation - - iteration-over-groups - dataprep: [] - styling: - - grid-styling - - alpha-blending + strengths: [] + weaknesses: [] From b9f5df76c3d402298f5581584965a1288bd45567 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 10 Jun 2026 00:58:14 +0000 Subject: [PATCH 3/5] chore(letsplot): update quality score 89 and review feedback for line-yield-curve --- .../implementations/python/letsplot.py | 5 +- .../metadata/python/letsplot.yaml | 267 +++++++++++++++++- 2 files changed, 263 insertions(+), 9 deletions(-) diff --git a/plots/line-yield-curve/implementations/python/letsplot.py b/plots/line-yield-curve/implementations/python/letsplot.py index 5091fccfa7..29f6163315 100644 --- a/plots/line-yield-curve/implementations/python/letsplot.py +++ b/plots/line-yield-curve/implementations/python/letsplot.py @@ -1,6 +1,7 @@ -"""anyplot.ai +""" anyplot.ai line-yield-curve: Yield Curve (Interest Rate Term Structure) -Library: letsplot | Python +Library: letsplot 4.10.1 | Python 3.13.13 +Quality: 89/100 | Updated: 2026-06-10 """ import os diff --git a/plots/line-yield-curve/metadata/python/letsplot.yaml b/plots/line-yield-curve/metadata/python/letsplot.yaml index 626c2aabdb..b2c07a8ae5 100644 --- a/plots/line-yield-curve/metadata/python/letsplot.yaml +++ b/plots/line-yield-curve/metadata/python/letsplot.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for letsplot implementation of line-yield-curve -# Auto-generated by impl-generate.yml - library: letsplot language: python specification_id: line-yield-curve created: '2026-03-14T22:15:13Z' -updated: '2026-06-10T00:51:21Z' +updated: '2026-06-10T00:58:14Z' generated_by: claude-sonnet workflow_run: 27245197539 issue: 4664 @@ -15,7 +12,263 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/line-yiel preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/python/letsplot/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/python/letsplot/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/python/letsplot/plot-dark.html -quality_score: null +quality_score: 89 review: - strengths: [] - weaknesses: [] + strengths: + - Three distinct yield curve shapes (normal, inverted, steep) tell a compelling + economic narrative with correct Imprint palette ordering + - Inversion region highlighted via geom_ribbon with semantic red (#AE3030) fill + and 'Inversion Region' italic annotation — focal point is immediately clear + - 'Theme-adaptive chrome tokens fully applied: backgrounds, INK/INK_SOFT text tokens, + legend elevated background, grid color — both renders correct' + - Scale uses maturity_years for correct log-like x-axis spacing with human-readable + maturity labels via scale_x_continuous breaks/labels + - 'Idiomatic letsplot multi-layer composition: geom_ribbon + geom_line + geom_point + + geom_text with native layer_tooltips() for HTML interactivity' + - 'Perfect data quality: historically plausible U.S. Treasury yield values for the + three named dates; factually correct curve shapes' + weaknesses: + - 'Title is missing the required language component: code has ''line-yield-curve + · letsplot · anyplot.ai'' but the mandated format is ''{spec-id} · {language} + · {library} · anyplot.ai'' — fix to ''line-yield-curve · python · letsplot · anyplot.ai''' + - geom_point size=2.5 is on the small side for sparse data (33 points across 3 series); + increase to size=3.5 to make individual data points more prominent per the sparse-data + heuristic (< 50 points → larger, prominent markers) + - DE-01 could reach 6/8 with a bolder title weight (fontface='bold' on plot_title) + and a subtle subtitle or y-axis baseline annotation to sharpen typographic hierarchy + - DE-02 could reach 5/6 by explicitly removing top and right spines (theme_minimal + leaves them in by default in letsplot; add panel_border=element_blank() or equivalent) + and using a slightly more generous legend padding + image_description: |- + Light render (plot-light.png): + Background: warm off-white #FAF8F1 — correct, not pure white + Chrome: title "line-yield-curve · letsplot · anyplot.ai" in dark ink (~50% plot width), fully readable; axis labels "Maturity" and "Yield (%)" in dark INK at size 12; tick labels at size 10 in INK_SOFT; legend at top with elevated off-white box containing three labeled series + Data: three yield curves — "Jan 2018 (Normal)" in #009E73 (brand green), "Aug 2019 (Inverted)" in #C475FD (lavender), "Mar 2021 (Steep)" in #4467A3 (blue). Inversion region shaded with semi-transparent matte red (#AE3030 alpha=0.18) ribbon from 1M to ~2Y maturity; "Inversion Region" annotation in red italic text near x=1.5. Points at each maturity visible on all three curves. + Legibility verdict: PASS — all text clearly readable against the warm off-white background; no light-on-light issues + + Dark render (plot-dark.png): + Background: warm near-black #1A1A17 — correct, not pure black + Chrome: title, axis labels, tick labels all rendered in light #F0EFE8/B8B7B0 text — clearly readable against dark background; legend box uses elevated dark background #242420 with light-colored legend text; no dark-on-dark failures observed + Data: all three curve colors identical to light render — green #009E73, lavender #C475FD, blue #4467A3 — only chrome flipped as expected; inversion ribbon visible as dark maroon fill; "Inversion Region" annotation in red still visible + Legibility verdict: PASS — all text clearly readable against the warm near-black background; no dark-on-dark text failures; data colors correctly theme-invariant + criteria_checklist: + visual_quality: + score: 29 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 8 + max: 8 + passed: true + comment: All font sizes explicitly set (plot_title=16, axis_title=12, axis_text=10, + legend_text=10, geom_text size=4mm); all text readable in both themes; proportions + balanced + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: No overlapping text; x-axis tick labels (6M, 1Y, 2Y, 5Y, 10Y, 20Y, + 30Y) are spaced adequately; legend does not overlap data; annotation placed + clearly + - id: VQ-03 + name: Element Visibility + score: 5 + max: 6 + passed: true + comment: Lines and points visible; geom_point size=2.5 is slightly small for + 33 sparse data points — sparse data heuristic recommends larger markers + (< 50 points) + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Imprint palette is CVD-safe; green/lavender/blue are three distinct + hue families; adequate luminance contrast in both themes + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: Canvas gate passed (ggsize 800×450 × scale=4 = 3200×1800); legend + at top is tidy; plot area well-utilized; balanced margins + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Y-axis 'Yield (%)' includes units; X-axis 'Maturity' is descriptive + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series #009E73 (green) correct; second #C475FD (lavender), + third #4467A3 (blue) — canonical Imprint order; #AE3030 used semantically + for inversion (bad/warning signal); backgrounds #FAF8F1 / #1A1A17 correct; + data colors identical across themes' + design_excellence: + score: 13 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: 'Above well-configured default: Imprint palette applied correctly, + inversion ribbon adds visual interest, custom chrome tokens, clean financial + style — but lacks bold title weight or typographic hierarchy to reach 6+' + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: Y-axis grid only (panel_grid_major_x blank, minor blank), refined + legend background, axis lines set — clearly above defaults but top/right + spine removal not explicitly forced + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Inversion region shading with annotation creates clear focal point; + three curve shapes tell economic cycle story; viewer immediately identifies + the recession signal + spec_compliance: + score: 14 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Yield curve with multiple lines on shared axes, points at each maturity + node — correct chart type + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Multi-curve display (3 curves), inversion region highlighted via + ribbon, annotation, maturity_years x-axis with proper string labels, legend + with dates + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: X=maturity_years (numeric), Y=yield_pct, color=date — correct mapping; + all 11 maturities visible; axes show full data range + - id: SC-04 + name: Title & Legend + score: 2 + max: 3 + passed: false + comment: Title is 'line-yield-curve · letsplot · anyplot.ai' but required + format is '{spec-id} · {language} · {library} · anyplot.ai' — missing 'python' + component; legend labels correct (Jan 2018 (Normal), Aug 2019 (Inverted), + Mar 2021 (Steep)) + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: 'All three canonical yield curve shapes shown: normal upward-sloping, + inverted (recession signal), steep post-pandemic; full maturity range 1M–30Y; + inversion region highlighted' + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Real U.S. Treasury yield data with specific historical dates; neutral + financial domain; Jan 2018, Aug 2019, Mar 2021 are genuine macroeconomic + landmarks + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Yield values historically accurate for the named dates; normal curve + 1.28–2.96%, inversion 1.44–2.09%, steep 0.03–2.35% — all plausible for those + periods + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: Flat imports → data → plot → save; no functions or classes + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: All data is hardcoded/deterministic; no random generation needed + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: os, pandas, lets_plot — all used; noqa comments appropriate for wildcard + import + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Clean Pythonic code; pd.Categorical for ordered color assignment + is an elegant pattern; appropriate complexity for the visualization + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot-{THEME}.png (scale=4) and plot-{THEME}.html; current API + usage + library_mastery: + score: 8 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 5 + max: 5 + passed: true + comment: 'Grammar of graphics used expertly: ggplot() + geom_ribbon + geom_line + + geom_point + geom_text; scale_color_manual + scale_x_continuous; theme_minimal + + theme() override — fully idiomatic letsplot' + - id: LM-02 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: layer_tooltips().line() chaining is a native letsplot interactive + feature (HTML output); pd.Categorical ordered category for color-order control + is letsplot-aware; but no exotic letsplot-specific geometry or computed + statistics used + verdict: REJECTED +impl_tags: + dependencies: [] + techniques: + - hover-tooltips + - html-export + - annotations + - layer-composition + - manual-ticks + patterns: + - iteration-over-groups + dataprep: [] + styling: + - alpha-blending From a7d09567fcd40261343f9d0e9fde945375b5bc3f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 10 Jun 2026 01:00:17 +0000 Subject: [PATCH 4/5] fix(letsplot): address review feedback for line-yield-curve Attempt 1/3 - fixes based on AI review --- .../line-yield-curve/implementations/python/letsplot.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plots/line-yield-curve/implementations/python/letsplot.py b/plots/line-yield-curve/implementations/python/letsplot.py index 29f6163315..483706ff14 100644 --- a/plots/line-yield-curve/implementations/python/letsplot.py +++ b/plots/line-yield-curve/implementations/python/letsplot.py @@ -1,4 +1,4 @@ -""" anyplot.ai +"""anyplot.ai line-yield-curve: Yield Curve (Interest Rate Term Structure) Library: letsplot 4.10.1 | Python 3.13.13 Quality: 89/100 | Updated: 2026-06-10 @@ -102,7 +102,7 @@ + geom_point( # noqa: F405 data=df, mapping=aes(x="maturity_years", y="yield_pct", color="date"), # noqa: F405 - size=2.5, + size=3.5, alpha=0.85, ) # Inversion region label — geom_text size is in mm, not pt @@ -116,7 +116,7 @@ + scale_color_manual(values=IMPRINT_PALETTE[:3]) # noqa: F405 + scale_x_continuous(breaks=tick_positions, labels=tick_labels_x) # noqa: F405 + labs( # noqa: F405 - x="Maturity", y="Yield (%)", title="line-yield-curve · letsplot · anyplot.ai", color="" + x="Maturity", y="Yield (%)", title="line-yield-curve · python · letsplot · anyplot.ai", color="" ) + ggsize(800, 450) # noqa: F405 + theme_minimal() # noqa: F405 @@ -129,10 +129,11 @@ axis_title=element_text(color=INK, size=12), # noqa: F405 axis_text=element_text(color=INK_SOFT, size=10), # noqa: F405 axis_line=element_line(color=INK_SOFT), # noqa: F405 - plot_title=element_text(color=INK, size=16), # noqa: F405 + plot_title=element_text(color=INK, size=16, face="bold"), # noqa: F405 legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT), # noqa: F405 legend_text=element_text(color=INK_SOFT, size=10), # noqa: F405 legend_title=element_text(color=INK), # noqa: F405 + panel_border=element_blank(), # noqa: F405 legend_position="top", ) ) From 3c3717397b8d0a84221a989070a059b2dec7522b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 10 Jun 2026 01:07:31 +0000 Subject: [PATCH 5/5] chore(letsplot): update quality score 87 and review feedback for line-yield-curve --- .../implementations/python/letsplot.py | 4 +- .../metadata/python/letsplot.yaml | 184 ++++++++---------- 2 files changed, 80 insertions(+), 108 deletions(-) diff --git a/plots/line-yield-curve/implementations/python/letsplot.py b/plots/line-yield-curve/implementations/python/letsplot.py index 483706ff14..e114a1018f 100644 --- a/plots/line-yield-curve/implementations/python/letsplot.py +++ b/plots/line-yield-curve/implementations/python/letsplot.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai line-yield-curve: Yield Curve (Interest Rate Term Structure) Library: letsplot 4.10.1 | Python 3.13.13 -Quality: 89/100 | Updated: 2026-06-10 +Quality: 87/100 | Updated: 2026-06-10 """ import os diff --git a/plots/line-yield-curve/metadata/python/letsplot.yaml b/plots/line-yield-curve/metadata/python/letsplot.yaml index b2c07a8ae5..073ffaa12f 100644 --- a/plots/line-yield-curve/metadata/python/letsplot.yaml +++ b/plots/line-yield-curve/metadata/python/letsplot.yaml @@ -2,7 +2,7 @@ library: letsplot language: python specification_id: line-yield-curve created: '2026-03-14T22:15:13Z' -updated: '2026-06-10T00:58:14Z' +updated: '2026-06-10T01:07:31Z' generated_by: claude-sonnet workflow_run: 27245197539 issue: 4664 @@ -12,103 +12,90 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/line-yiel preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/python/letsplot/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/python/letsplot/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/line-yield-curve/python/letsplot/plot-dark.html -quality_score: 89 +quality_score: 87 review: strengths: - - Three distinct yield curve shapes (normal, inverted, steep) tell a compelling - economic narrative with correct Imprint palette ordering - - Inversion region highlighted via geom_ribbon with semantic red (#AE3030) fill - and 'Inversion Region' italic annotation — focal point is immediately clear - - 'Theme-adaptive chrome tokens fully applied: backgrounds, INK/INK_SOFT text tokens, - legend elevated background, grid color — both renders correct' - - Scale uses maturity_years for correct log-like x-axis spacing with human-readable - maturity labels via scale_x_continuous breaks/labels - - 'Idiomatic letsplot multi-layer composition: geom_ribbon + geom_line + geom_point - + geom_text with native layer_tooltips() for HTML interactivity' - - 'Perfect data quality: historically plausible U.S. Treasury yield values for the - three named dates; factually correct curve shapes' + - Excellent spec compliance — all required features present including inversion + region highlight and annotation + - Historically accurate U.S. Treasury yield curve data for three meaningful dates + that tell a clear story + - Correct Imprint palette usage with full theme-adaptive chrome in both light and + dark renders + - layer_tooltips() leverages letsplot's native interactive tooltip API distinctively + - Inversion ribbon + annotation creates a genuine visual focal point and data story weaknesses: - - 'Title is missing the required language component: code has ''line-yield-curve - · letsplot · anyplot.ai'' but the mandated format is ''{spec-id} · {language} - · {library} · anyplot.ai'' — fix to ''line-yield-curve · python · letsplot · anyplot.ai''' - - geom_point size=2.5 is on the small side for sparse data (33 points across 3 series); - increase to size=3.5 to make individual data points more prominent per the sparse-data - heuristic (< 50 points → larger, prominent markers) - - DE-01 could reach 6/8 with a bolder title weight (fontface='bold' on plot_title) - and a subtle subtitle or y-axis baseline annotation to sharpen typographic hierarchy - - DE-02 could reach 5/6 by explicitly removing top and right spines (theme_minimal - leaves them in by default in letsplot; add panel_border=element_blank() or equivalent) - and using a slightly more generous legend padding + - 6M and 1Y x-axis tick labels are close (potentially touching) due to linear-scale + compression — consider log-scale x-axis (scale_x_log10) which naturally spreads + short maturities, or rotate short-end labels + - Inversion ribbon at alpha=0.18 is subtle; on dark background it is quite faint + — consider raising to alpha=0.22–0.25 for better dark-theme visibility + - Line width size=1.0 is conservative for a sparse 11-point dataset; increase to + 1.4–1.6 for more visual weight image_description: |- Light render (plot-light.png): - Background: warm off-white #FAF8F1 — correct, not pure white - Chrome: title "line-yield-curve · letsplot · anyplot.ai" in dark ink (~50% plot width), fully readable; axis labels "Maturity" and "Yield (%)" in dark INK at size 12; tick labels at size 10 in INK_SOFT; legend at top with elevated off-white box containing three labeled series - Data: three yield curves — "Jan 2018 (Normal)" in #009E73 (brand green), "Aug 2019 (Inverted)" in #C475FD (lavender), "Mar 2021 (Steep)" in #4467A3 (blue). Inversion region shaded with semi-transparent matte red (#AE3030 alpha=0.18) ribbon from 1M to ~2Y maturity; "Inversion Region" annotation in red italic text near x=1.5. Points at each maturity visible on all three curves. - Legibility verdict: PASS — all text clearly readable against the warm off-white background; no light-on-light issues + Background: warm off-white #FAF8F1 — correct + Chrome: title "line-yield-curve · python · letsplot · anyplot.ai" bold and visible; axis labels "Maturity" and "Yield (%)" clearly readable; tick labels visible though 6M/1Y/2Y are tight at short-maturity end + Data: three yield curves — brand green #009E73 (Jan 2018 Normal), lavender #C475FD (Aug 2019 Inverted), blue #4467A3 (Mar 2021 Steep); inversion ribbon in salmon/pink (alpha=0.18); "Inversion Region" italic red annotation + Legibility verdict: PASS — all text readable; minor 6M/1Y tick crowding noted but not a failure Dark render (plot-dark.png): - Background: warm near-black #1A1A17 — correct, not pure black - Chrome: title, axis labels, tick labels all rendered in light #F0EFE8/B8B7B0 text — clearly readable against dark background; legend box uses elevated dark background #242420 with light-colored legend text; no dark-on-dark failures observed - Data: all three curve colors identical to light render — green #009E73, lavender #C475FD, blue #4467A3 — only chrome flipped as expected; inversion ribbon visible as dark maroon fill; "Inversion Region" annotation in red still visible - Legibility verdict: PASS — all text clearly readable against the warm near-black background; no dark-on-dark text failures; data colors correctly theme-invariant + Background: warm near-black #1A1A17 — correct + Chrome: title and axis labels rendered in light ink (#F0EFE8/#B8B7B0), clearly readable against dark surface; no dark-on-dark failures detected; legend background uses #242420 (elevated dark) + Data: colors identical to light render — green, lavender, blue curves unchanged as required; inversion ribbon slightly more subtle on dark but still visible + Legibility verdict: PASS — all text readable on dark background; no dark-on-dark issues criteria_checklist: visual_quality: - score: 29 + score: 27 max: 30 items: - id: VQ-01 name: Text Legibility - score: 8 + score: 7 max: 8 passed: true - comment: All font sizes explicitly set (plot_title=16, axis_title=12, axis_text=10, - legend_text=10, geom_text size=4mm); all text readable in both themes; proportions - balanced + comment: All font sizes explicitly set; readable in both themes; 6M/1Y tick + spacing slightly tight at short-maturity end - id: VQ-02 name: No Overlap - score: 6 + score: 5 max: 6 passed: true - comment: No overlapping text; x-axis tick labels (6M, 1Y, 2Y, 5Y, 10Y, 20Y, - 30Y) are spaced adequately; legend does not overlap data; annotation placed - clearly + comment: 6M and 1Y tick labels near-touching due to linear-scale compression + of 0.5-2 year range on 0-30 axis - id: VQ-03 name: Element Visibility score: 5 max: 6 passed: true - comment: Lines and points visible; geom_point size=2.5 is slightly small for - 33 sparse data points — sparse data heuristic recommends larger markers - (< 50 points) + comment: Lines/points well-sized for 33 data points; inversion ribbon at alpha=0.18 + slightly faint in dark render - id: VQ-04 name: Color Accessibility score: 2 max: 2 passed: true - comment: Imprint palette is CVD-safe; green/lavender/blue are three distinct - hue families; adequate luminance contrast in both themes + comment: Imprint palette, CVD-safe, three distinct series - id: VQ-05 name: Layout & Canvas score: 4 max: 4 passed: true - comment: Canvas gate passed (ggsize 800×450 × scale=4 = 3200×1800); legend - at top is tidy; plot area well-utilized; balanced margins + comment: 3200x1800 correct, good canvas utilization, balanced margins, legend + at top - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: Y-axis 'Yield (%)' includes units; X-axis 'Maturity' is descriptive + comment: Maturity and Yield (%) with units - id: VQ-07 name: Palette Compliance score: 2 max: 2 passed: true - comment: 'First series #009E73 (green) correct; second #C475FD (lavender), - third #4467A3 (blue) — canonical Imprint order; #AE3030 used semantically - for inversion (bad/warning signal); backgrounds #FAF8F1 / #1A1A17 correct; - data colors identical across themes' + comment: 'First series #009E73, Imprint canonical order (positions 1-3), inversion + ribbon uses #AE3030 semantic anchor, backgrounds #FAF8F1/#1A1A17, full theme-adaptive + chrome' design_excellence: score: 13 max: 20 @@ -118,27 +105,24 @@ review: score: 5 max: 8 passed: true - comment: 'Above well-configured default: Imprint palette applied correctly, - inversion ribbon adds visual interest, custom chrome tokens, clean financial - style — but lacks bold title weight or typographic hierarchy to reach 6+' + comment: Professional financial style with inversion region highlight; above + default but not publication-ready - id: DE-02 name: Visual Refinement score: 4 max: 6 passed: true - comment: Y-axis grid only (panel_grid_major_x blank, minor blank), refined - legend background, axis lines set — clearly above defaults but top/right - spine removal not explicitly forced + comment: Y-only grid, x-grid blanked, panel_border removed, explicit legend + background token, L-shaped axis frame - id: DE-03 name: Data Storytelling score: 4 max: 6 passed: true - comment: Inversion region shading with annotation creates clear focal point; - three curve shapes tell economic cycle story; viewer immediately identifies - the recession signal + comment: Three dates tell normal-inverted-steep narrative arc; inversion ribbon + and annotation create focal point spec_compliance: - score: 14 + score: 15 max: 15 items: - id: SC-01 @@ -146,32 +130,28 @@ review: score: 5 max: 5 passed: true - comment: Yield curve with multiple lines on shared axes, points at each maturity - node — correct chart type + comment: Multi-line yield curve with numeric x-axis spacing - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Multi-curve display (3 curves), inversion region highlighted via - ribbon, annotation, maturity_years x-axis with proper string labels, legend - with dates + comment: Three curves, inversion region shaded and annotated, maturity_years + for spacing, maturity labels for ticks - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: X=maturity_years (numeric), Y=yield_pct, color=date — correct mapping; - all 11 maturities visible; axes show full data range + comment: x=maturity_years, y=yield_pct, color=date; all 11 maturities per + curve - id: SC-04 name: Title & Legend - score: 2 + score: 3 max: 3 - passed: false - comment: Title is 'line-yield-curve · letsplot · anyplot.ai' but required - format is '{spec-id} · {language} · {library} · anyplot.ai' — missing 'python' - component; legend labels correct (Jan 2018 (Normal), Aug 2019 (Inverted), - Mar 2021 (Steep)) + passed: true + comment: 'Correct title format; legend: Jan 2018 (Normal), Aug 2019 (Inverted), + Mar 2021 (Steep)' data_quality: score: 15 max: 15 @@ -181,25 +161,22 @@ review: score: 6 max: 6 passed: true - comment: 'All three canonical yield curve shapes shown: normal upward-sloping, - inverted (recession signal), steep post-pandemic; full maturity range 1M–30Y; - inversion region highlighted' + comment: Normal, inverted, and steep curves showcase all three yield curve + shapes - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Real U.S. Treasury yield data with specific historical dates; neutral - financial domain; Jan 2018, Aug 2019, Mar 2021 are genuine macroeconomic - landmarks + comment: Real U.S. Treasury dates with historically accurate context; neutral + financial data - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: Yield values historically accurate for the named dates; normal curve - 1.28–2.96%, inversion 1.44–2.09%, steep 0.03–2.35% — all plausible for those - periods + comment: Jan 2018 (1.3-3%), Aug 2019 inversion (1.4-2.1%), Mar 2021 post-pandemic + (0.03-2.35%) are historically accurate code_quality: score: 10 max: 10 @@ -209,64 +186,59 @@ review: score: 3 max: 3 passed: true - comment: Flat imports → data → plot → save; no functions or classes + comment: Imports -> tokens -> data -> plot -> save; no functions/classes - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: All data is hardcoded/deterministic; no random generation needed + comment: Fully deterministic hardcoded data - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: os, pandas, lets_plot — all used; noqa comments appropriate for wildcard - import + comment: os, pandas, lets_plot only - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: Clean Pythonic code; pd.Categorical for ordered color assignment - is an elegant pattern; appropriate complexity for the visualization + comment: Well-organized, ordered categorical for color stability - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves plot-{THEME}.png (scale=4) and plot-{THEME}.html; current API - usage + comment: Saves plot-{THEME}.png and plot-{THEME}.html correctly library_mastery: - score: 8 + score: 7 max: 10 items: - id: LM-01 name: Idiomatic Usage - score: 5 + score: 4 max: 5 passed: true - comment: 'Grammar of graphics used expertly: ggplot() + geom_ribbon + geom_line - + geom_point + geom_text; scale_color_manual + scale_x_continuous; theme_minimal - + theme() override — fully idiomatic letsplot' + comment: Correct grammar-of-graphics pattern, layer_tooltips(), scale functions, + theme_minimal+theme() idiomatically used - id: LM-02 name: Distinctive Features score: 3 max: 5 passed: true - comment: layer_tooltips().line() chaining is a native letsplot interactive - feature (HTML output); pd.Categorical ordered category for color-order control - is letsplot-aware; but no exotic letsplot-specific geometry or computed - statistics used - verdict: REJECTED + comment: layer_tooltips() with .line() chains is letsplot-specific; HTML output + captures native letsplot interactivity; ordered pd.Categorical ensures color + assignment stability + verdict: APPROVED impl_tags: dependencies: [] techniques: + - annotations + - manual-ticks - hover-tooltips - html-export - - annotations - layer-composition - - manual-ticks patterns: - iteration-over-groups dataprep: []