Skip to content

feat(letsplot): implement line-yield-curve#8557

Merged
MarkusNeusinger merged 6 commits into
mainfrom
implementation/line-yield-curve/letsplot
Jun 10, 2026
Merged

feat(letsplot): implement line-yield-curve#8557
MarkusNeusinger merged 6 commits into
mainfrom
implementation/line-yield-curve/letsplot

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Implementation: line-yield-curve - python/letsplot

Implements the python/letsplot version of line-yield-curve.

File: plots/line-yield-curve/implementations/python/letsplot.py

Parent Issue: #4664


🤖 impl-generate workflow

github-actions Bot added 2 commits June 10, 2026 00:51
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
@claude

claude Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): Warm off-white #FAF8F1 background — correct, not pure white. Title "line-yield-curve · letsplot · anyplot.ai" in dark ink (~50% plot width), fully readable. Three yield curves plotted: "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 with italic "Inversion Region" annotation in red. Data points visible at each of the 11 maturities on all three curves. Axis labels "Yield (%)" and "Maturity" clearly readable in dark ink. Legend at top with elevated off-white box. All text clearly readable against the light background — no light-on-light issues. Legibility verdict: PASS.

Dark render (plot-dark.png): Warm near-black #1A1A17 background — correct, not pure black. Title, axis labels, and tick labels all rendered in light #F0EFE8/#B8B7B0 text — clearly readable against the dark background. Legend box uses elevated dark #242420 background with light-colored legend text. All three curve colors are identical to the light render (green, lavender, blue — data colors correctly theme-invariant). Inversion ribbon visible as dark maroon fill. "Inversion Region" annotation in red still legible. No dark-on-dark failures observed anywhere. Legibility verdict: PASS.

Both paragraphs confirm both renders were reviewed. Both pass the theme-readability check.

Score: 89/100

Category Score Max
Visual Quality 29 30
Design Excellence 13 20
Spec Compliance 14 15
Data Quality 15 15
Code Quality 10 10
Library Mastery 8 10
Total 89 100

Visual Quality (29/30)

  • VQ-01: Text Legibility (8/8) — All font sizes explicitly set (plot_title=16, axis_title=12, axis_text=10, legend_text=10, annotation geom_text size=4mm); all text readable in both themes; proportions balanced
  • VQ-02: No Overlap (6/6) — No overlapping text; x-axis tick labels adequately spaced; legend clear of data; annotation well-placed
  • VQ-03: Element Visibility (5/6) — Lines and points visible; geom_point size=2.5 is slightly small for 33 sparse data points (sparse-data heuristic: < 50 points → larger, prominent markers)
  • VQ-04: Color Accessibility (2/2) — Imprint palette is CVD-safe; green/lavender/blue are three distinct hue families; adequate contrast in both themes
  • VQ-05: Layout & Canvas (4/4) — Canvas gate passed (800×450 × scale=4 = 3200×1800); legend placement tidy; plot area well-utilized; balanced margins
  • VQ-06: Axis Labels & Title (2/2) — "Yield (%)" includes units; "Maturity" is descriptive
  • VQ-07: Palette Compliance (2/2) — First series #009E73 correct; canonical Imprint order for series 2–3; #AE3030 used semantically for inversion (bad/warning role); backgrounds #FAF8F1/#1A1A17 correct; data colors identical across themes

Design Excellence (13/20)

  • DE-01: Aesthetic Sophistication (5/8) — Above a well-configured default: Imprint palette applied correctly, inversion ribbon adds visual interest, custom chrome tokens throughout, clean financial publication style — but lacks bold title weight or stronger typographic hierarchy to reach 6/8
  • DE-02: Visual Refinement (4/6) — Y-axis grid only (panel_grid_major_x blank, minor blank), refined legend background, axis lines set — clearly above defaults; explicit top/right spine removal would add polish
  • DE-03: Data Storytelling (4/6) — Inversion region shading with annotation creates a clear focal point; three distinct curve shapes tell the economic cycle story; viewer immediately identifies the recession signal

Spec Compliance (14/15)

  • SC-01: Plot Type (5/5) — Yield curve with multiple lines on shared axes and points at each maturity node
  • SC-02: Required Features (4/4) — Multi-curve display (3 curves), inversion region highlighted via ribbon, annotation, maturity_years x-axis with string labels, legend with date labels
  • SC-03: Data Mapping (3/3) — X=maturity_years (numeric), Y=yield_pct, color=date; all 11 maturities visible; full data range shown
  • SC-04: Title & Legend (2/3) — Legend labels correct; 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"

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — All three canonical yield curve shapes: normal upward-sloping, inverted (recession signal), steep post-pandemic; full 1M–30Y maturity range; inversion highlighted
  • DQ-02: Realistic Context (5/5) — Real U.S. Treasury yield data with specific historical dates; neutral financial domain; Jan 2018/Aug 2019/Mar 2021 are genuine macroeconomic landmarks
  • DQ-03: Appropriate Scale (4/4) — Yield values historically accurate for the named dates (normal 1.28–2.96%, inverted 1.44–2.09%, steep 0.03–2.35%)

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Flat imports → data → plot → save; no functions or classes
  • CQ-02: Reproducibility (2/2) — All data hardcoded/deterministic; no random seed needed
  • CQ-03: Clean Imports (2/2) — os, pandas, lets_plot — all used; noqa comments appropriate for wildcard import
  • CQ-04: Code Elegance (2/2) — Clean Pythonic code; pd.Categorical for ordered color assignment is an elegant pattern
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png (scale=4) and plot-{THEME}.html; current API

Library Mastery (8/10)

  • LM-01: Idiomatic Usage (5/5) — Grammar of graphics used expertly: ggplot() + geom_ribbon + geom_line + geom_point + geom_text; scale_color_manual + scale_x_continuous with breaks/labels; theme_minimal + theme() override — fully idiomatic letsplot
  • LM-02: Distinctive Features (3/5) — layer_tooltips().line() chaining is a native letsplot interactive tooltip API for HTML output; pd.Categorical ordered category for color-order control is letsplot-aware; no more exotic letsplot-specific geometry or computed statistics

Score Caps Applied

  • None

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 #AE3030 fill and "Inversion Region" italic annotation — focal point is immediately clear in both themes
  • Theme-adaptive chrome tokens fully applied throughout: backgrounds, INK/INK_SOFT text, legend elevated background, grid color — both renders pass theme-readability check
  • Correct x-axis scaling: maturity_years for proper spacing with human-readable labels via scale_x_continuous breaks/labels
  • Perfect code quality and data quality — real historical data, clean KISS structure, native letsplot layer_tooltips() for HTML interactivity

Weaknesses

  • Title missing "python": code has "line-yield-curve · letsplot · anyplot.ai" but required format is "line-yield-curve · python · letsplot · anyplot.ai" (−1 SC-04)
  • geom_point size=2.5 slightly small for sparse data (33 points): sparse-data heuristic (< 50 points) calls for larger, prominent markers — increase to size=3.5 (−1 VQ-03)
  • DE-01 headroom: add fontface="bold" to plot_title element_text and stronger typographic hierarchy to lift from 5→6
  • DE-02 headroom: explicitly suppress top/right panel border (add panel_border=element_blank() or equivalent) for cleaner spine removal beyond theme_minimal defaults

Issues Found

  1. SC-04 TITLE FORMAT: Title missing required "python" language component
    • Fix: Change title="line-yield-curve · letsplot · anyplot.ai"title="line-yield-curve · python · letsplot · anyplot.ai" in the labs() call
  2. VQ-03 MARKER SIZE: geom_point size=2.5 is undersized for 33 sparse data points
    • Fix: Increase geom_point(size=3.5, alpha=0.85) for better point visibility on the curves
  3. DE-01/DE-02 POLISH: Minor design refinements to push above threshold
    • Fix: Add plot_title=element_text(color=INK, size=16, fontface="bold") and panel_border=element_blank() to the theme() call

AI Feedback for Next Attempt

Fix the title format first — this single change (+1 SC-04) brings the score to 90 and would pass at Attempt 2. Additionally: increase geom_point size from 2.5 to 3.5 for sparse-data prominence, add fontface="bold" to plot_title, and add panel_border=element_blank() to the theme for cleaner spine removal. The economic narrative and Imprint palette are well-executed — focus only on the title fix and minor polish to clear 90.

Verdict: REJECTED

@github-actions github-actions Bot added quality:89 Quality score 89/100 ai-rejected Quality not OK, triggers update labels Jun 10, 2026
@github-actions github-actions Bot added ai-attempt-1 First repair attempt and removed ai-rejected Quality not OK, triggers update labels Jun 10, 2026
Attempt 1/3 - fixes based on AI review
@github-actions

Copy link
Copy Markdown
Contributor Author

🔧 Repair Attempt 1/4

Applied fixes based on AI review feedback.

Status: Repair completed, re-triggering review...


🤖 impl-repair

@claude

claude Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

AI Review - Attempt 2/3

Image Description

Light render (plot-light.png): Three yield curves rendered on a warm off-white #FAF8F1 background. The Jan 2018 (Normal) curve is brand green #009E73, rising from ~1.3% at 6M to ~3% at 30Y. The Aug 2019 (Inverted) curve is lavender #C475FD, starting high at ~2.1% for 1M then declining to ~1.4% around 5Y before recovering to ~2% at 30Y. The Mar 2021 (Steep) curve is blue #4467A3, rising sharply from near 0% to ~2.4% at 30Y. A soft salmon/pink ribbon (alpha=0.18) shades the inversion region in the short-to-medium maturity range, with an italic red "Inversion Region" annotation in the upper-left portion of the plot. Legend is positioned at top with all three series labeled. X-axis shows sparse ticks at 6M, 1Y, 2Y, 5Y, 10Y, 20Y, 30Y; Y-axis shows Yield (%) from 0 to 3. Title "line-yield-curve · python · letsplot · anyplot.ai" is bold and clearly visible. All text is readable against the light background. Minor concern: the 6M and 1Y tick labels are close together at the short-maturity end due to linear scale compression.

Dark render (plot-dark.png): Same plot on the warm near-black #1A1A17 background. Data colors are identical to the light render — green, lavender, and blue series are unchanged as required. The inversion ribbon remains visible (slightly more subtle at alpha=0.18 on the dark surface, but still discernible). Title and axis labels render in light ink (#F0EFE8/#B8B7B0), clearly visible against the dark background. Grid lines are subtle and appropriate. No dark-on-dark text failures detected — all labels, tick marks, and legend text are legible. Brand green #009E73 is clearly visible on the dark surface. The legend background correctly uses #242420 (elevated dark surface).

Both paragraphs are required. A review that only describes one render is invalid.

Score: 87/100

Category Score Max
Visual Quality 27 30
Design Excellence 13 20
Spec Compliance 15 15
Data Quality 15 15
Code Quality 10 10
Library Mastery 7 10
Total 87 100

Visual Quality (27/30)

  • VQ-01: Text Legibility (7/8) — all font sizes explicitly set; title/axis/legend text readable in both themes; tight 6M/1Y tick spacing at short-maturity end is a minor readability concern at mobile scale
  • VQ-02: No Overlap (5/6) — 6M and 1Y tick labels are close (potentially touching) due to linear-scale compression of 0.5–2 year range on a 0–30 axis; main content is readable
  • VQ-03: Element Visibility (5/6) — line/point sizes appropriate for 33 data points; inversion ribbon at alpha=0.18 is intentionally subtle but is slightly faint in the dark render
  • VQ-04: Color Accessibility (2/2) — Imprint palette, CVD-safe, three distinct series easily distinguishable
  • VQ-05: Layout & Canvas (4/4) — 3200×1800 canvas correct, plot fills canvas well, legend at top integrates cleanly, balanced margins
  • VQ-06: Axis Labels & Title (2/2) — "Maturity" and "Yield (%)" with units
  • VQ-07: Palette Compliance (2/2) — first series is #009E73, palette follows Imprint canonical order (positions 1–3), inversion ribbon uses #AE3030 (semantic anchor for recession/loss), backgrounds #FAF8F1/#1A1A17, chrome tokens fully theme-adaptive in both renders

Design Excellence (13/20)

  • DE-01: Aesthetic Sophistication (5/8) — professional financial chart style with Imprint palette; inversion region shading and annotation elevate above a plain default; clean minimal theme; not quite publication-ready (line widths conservative, legend box could be more refined)
  • DE-02: Visual Refinement (4/6) — y-axis-only grid, x-grid and minor grid blanked, panel_border=element_blank(), L-shaped axis frame, explicit legend background with ELEVATED_BG token — clear refinement effort above defaults
  • DE-03: Data Storytelling (4/6) — the three dates tell a narrative arc (normal → inverted recession signal → post-pandemic steep); inversion ribbon and annotation create a focal point; viewer immediately understands the insight

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — multi-line yield curve with proper numeric x-axis
  • SC-02: Required Features (4/4) — three curves (≥2 required), inversion region shaded and annotated, legend showing dates, maturity_years for x-axis spacing, maturity labels for ticks
  • SC-03: Data Mapping (3/3) — x=maturity_years (numeric), y=yield_pct, color=date; all 11 maturities per curve visible
  • SC-04: Title & Legend (3/3) — title is line-yield-curve · python · letsplot · anyplot.ai; legend labels: "Jan 2018 (Normal)", "Aug 2019 (Inverted)", "Mar 2021 (Steep)"

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — showcases normal upward-sloping, inverted, and steep post-pandemic curves; all three yield-curve shapes present
  • DQ-02: Realistic Context (5/5) — real U.S. Treasury yield curve dates with historically accurate context; neutral financial data
  • DQ-03: Appropriate Scale (4/4) — Jan 2018 yields (1.3–3%), Aug 2019 inversion (1.4–2.1%), Mar 2021 post-pandemic low rates (0.03–2.35%) are historically accurate

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — imports → tokens → data → plot → save; no functions/classes
  • CQ-02: Reproducibility (2/2) — fully deterministic hardcoded data; no random seed needed
  • CQ-03: Clean Imports (2/2) — os, pandas, lets_plot only; no unused imports
  • CQ-04: Code Elegance (2/2) — well-organized, ordered categorical for color stability, inversion DataFrame cleanly constructed
  • CQ-05: Output & API (1/1) — saves plot-{THEME}.png and plot-{THEME}.html correctly

Library Mastery (7/10)

  • LM-01: Idiomatic Usage (4/5) — correct letsplot grammar-of-graphics pattern; layer_tooltips() interactive API; scale_color_manual, scale_x_continuous, theme_minimal + theme() all used idiomatically
  • LM-02: Distinctive Features (3/5) — layer_tooltips() with .line() chains is letsplot-specific interactive tooltip API; HTML output captures native letsplot interactivity; ordered pd.Categorical ensures color assignment stability across letsplot's rendering pipeline

Score Caps Applied

  • None

Strengths

  • 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

  • 6M and 1Y x-axis tick labels are close (potentially touching) due to linear-scale compression — consider switching to log-scale x-axis (scale_x_log10) which would naturally spread short maturities, or rotate short-end labels slightly
  • 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 visibility in dark theme without being distracting
  • Line width size=1.0 is conservative for a sparse 11-point dataset; the style guide recommends thicker lines for few series/few points — consider increasing to 1.4–1.6

Issues Found

  1. VQ-01/VQ-02 MINOR: 6M and 1Y tick labels at the compressed short-maturity end nearly touch on a 0–30 linear x-axis
    • Fix: Use scale_x_log10() instead of scale_x_continuous() — log scale is standard for yield curves and naturally spaces short maturities; or reduce to fewer ticks (drop 1Y, keep 6M/2Y/5Y/10Y/20Y/30Y)
  2. DE-01 MODERATE: Line width is conservative for a sparse 11-point/3-curve dataset
    • Fix: Increase geom_line(size=1.4) and geom_point(size=4.0) to give more visual weight to the curves

AI Feedback for Next Attempt

Strong implementation with excellent spec compliance and data quality. To push above 90: (1) switch to log-scale x-axis which is the industry standard for yield curves and eliminates the short-maturity tick crowding, (2) increase line weight to 1.4–1.6 and point size to 4.0 for more visual impact on a sparse dataset, (3) slightly raise inversion ribbon alpha to 0.22 for better dark-theme visibility.

Verdict: APPROVED

@github-actions github-actions Bot added quality:87 Quality score 87/100 ai-approved Quality OK, ready for merge and removed quality:89 Quality score 89/100 labels Jun 10, 2026
@MarkusNeusinger MarkusNeusinger merged commit 473ebad into main Jun 10, 2026
3 checks passed
@MarkusNeusinger MarkusNeusinger deleted the implementation/line-yield-curve/letsplot branch June 10, 2026 01:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-approved Quality OK, ready for merge ai-attempt-1 First repair attempt quality:87 Quality score 87/100

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant