Skip to content

feat(ggplot2): implement line-yield-curve#8556

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

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

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Implementation: line-yield-curve - r/ggplot2

Implements the r/ggplot2 version of line-yield-curve.

File: plots/line-yield-curve/implementations/r/ggplot2.R

Parent Issue: #4664


🤖 impl-generate workflow

@claude

claude Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): The plot renders on a warm off-white background (#FAF8F1). Three yield curves are shown: Jan 2021 (brand green #009E73, near-zero rates with steep upward slope), Jul 2023 (lavender #C475FD, deeply inverted curve peaking ~5.5% at the short end), and Jan 2024 (blue #4467A3, still inverted but slightly normalizing). A subtle gray shading (alpha=0.07) marks the 3M–2Y inversion zone with a muted-gray "Inversion zone" annotation. X-axis uses log scale with maturity labels (1M–30Y); Y-axis shows yield percentage with one-decimal formatting. Legend sits in the right margin with a light elevated background and subtle border. All text — title, axis labels, tick labels, legend, annotation — is clearly readable in dark ink against the warm cream background. The title "line-yield-curve · r · ggplot2 · anyplot.ai" spans roughly 60% of the plot width at size=12. Legibility verdict: PASS.

Dark render (plot-dark.png): Same layout on a near-black background (#1A1A17). Data colors are identical to the light render — green, lavender, and blue curves remain unchanged. Chrome flips correctly: title, axis labels, and tick labels render in light cream tones (#F0EFE8 / #B8B7B0) against the dark surface. The "Inversion zone" annotation uses INK_MUTED (#A8A79F in dark) — readable against the slightly darker shaded region. Legend background uses the elevated dark token (#242420) with a subtle border. Grid lines are faint and non-intrusive. No dark-on-dark failures detected — all text elements are clearly readable. The brand green #009E73 remains visible and distinct. Legibility verdict: PASS.

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

Score: 89/100

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

Visual Quality (28/30)

  • VQ-01: Text Legibility (7/8) — All font sizes explicitly set (title=12, axis.title=10, axis.text=8, legend.text=9). Readable in both themes. Minor: "Inversion zone" annotation at size=2.8mm is on the small side but readable.
  • VQ-02: No Overlap (6/6) — No text overlaps with data or other text. Tick labels, legend, and annotation are well-spaced.
  • VQ-03: Element Visibility (5/6) — Lines and points visible at linewidth=1.2, size=2.5. Jan 2021 near-zero points are hard to distinguish from the axis line, though the curve itself is clear.
  • VQ-04: Color Accessibility (2/2) — Three Imprint hues (green/lavender/blue) are perceptually well-separated; CVD-safe under the Imprint palette.
  • VQ-05: Layout & Canvas (4/4) — Canvas 3200×1800 (width=8, height=4.5, dpi=400). Good proportions, balanced margins at 20pt, legend is proximate to data.
  • VQ-06: Axis Labels & Title (2/2) — X-axis "Maturity", Y-axis "Yield (%)" — descriptive with units.
  • VQ-07: Palette Compliance (2/2) — First series Jan 2021 uses #009E73. Positions 2–3 use lavender and blue in canonical Imprint order. Backgrounds: #FAF8F1 light / #1A1A17 dark. Data colors identical across both renders; only chrome flips.

Design Excellence (13/20)

  • DE-01: Aesthetic Sophistication (5/8) — Above a basic configured default: Imprint palette, log-scaled x-axis appropriate for the domain, shaded inversion zone with annotation, custom legend styling. Not yet at the "strong design" (6) tier — the annotation is minimal and the chart could benefit from additional polish (e.g., removing tick marks, tighter legend integration, subtitle or caption).
  • DE-02: Visual Refinement (4/6) — Good: panel.border removed, L-shaped axis frame, very subtle major grid (alpha=0.15 on INK), no minor grid, generous margins. Loses 2 points vs. "perfect" because tick marks remain and the chart could have more whitespace between the legend and plot area.
  • DE-03: Data Storytelling (4/6) — Good: the dramatic visual contrast between the Jan 2021 near-zero green curve at the bottom and the 2023–2024 inverted curves at ~5% immediately tells the monetary-cycle story. The shaded inversion zone with annotation directs the reader to the key insight. Not quite "excellent" (6) — could further emphasize the crossing/divergence of the curves.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct yield curve line chart with data points, multiple curves per spec requirement.
  • SC-02: Required Features (4/4) — 3 curves (≥2 required), log scale on x-axis, maturity tick labels, inversion region shaded, legend with dates.
  • SC-03: Data Mapping (3/3) — maturity_years on x-axis (log scale) with maturity string labels, yield_pct on y-axis. All data visible.
  • SC-04: Title & Legend (3/3) — Title "line-yield-curve · r · ggplot2 · anyplot.ai" matches required format. Legend labels (Jan 2021, Jul 2023, Jan 2024) match data.

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Shows all three canonical yield curve shapes: steeply normal (Jan 2021 QE era), deeply inverted (Jul 2023 peak hiking), and normalizing inverted (Jan 2024). Full spectrum of yield curve behavior demonstrated.
  • DQ-02: Realistic Context (5/5) — U.S. Treasury yield curve data on historically significant dates. Neutral financial context, no controversial topics.
  • DQ-03: Appropriate Scale (4/4) — Values are factually accurate: Jan 2021 near-zero (QE era), Jul 2023 at 5.25–5.50% fed funds range, Jan 2024 beginning normalization. Maturities 1M–30Y match U.S. Treasury issuance schedule.

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Clean Imports → Tokens → Data → Plot → Save. No functions or classes.
  • CQ-02: Reproducibility (2/2) — Fully deterministic hardcoded data; no randomness needed.
  • CQ-03: Clean Imports (2/2) — ggplot2 (plot), scales (alpha + label formatting), ragg (save device). All used.
  • CQ-04: Code Elegance (2/2) — Idiomatic R/ggplot2, no over-engineering, no fake interactive elements.
  • CQ-05: Output & API (1/1) — Saves as plot-${THEME}.png using ragg::agg_png. Correct.

Library Mastery (8/10)

  • LM-01: Idiomatic Usage (5/5) — Expert use of ggplot2 grammar: aes() mapping, layered geoms (annotate rect → geom_line → geom_point → annotate text), scale_x_log10 with custom breaks/labels, scale_y_continuous with expansion, full theme() override with adaptive tokens.
  • LM-02: Distinctive Features (3/5) — Uses some ggplot2-specific features: scale_x_log10(breaks=..., labels=...) for custom log-scale labeling, annotate("rect", ...) for the shaded zone, expansion(mult=...) for y-axis headroom. Could go further with ggplot2-exclusive capabilities (e.g., facet_\* for a small-multiples panel showing each curve, or geom_ribbon for shading between curves rather than a fixed rect).

Score Caps Applied

  • None — all caps avoided (DE-01=5 > 2 and DE-02=4 > 2, so no 75-cap; no other caps triggered).

Strengths

  • Perfect spec compliance and data quality: historically accurate U.S. Treasury data covering all canonical yield curve shapes (normal, inverted, normalizing)
  • Strong Imprint palette application: brand green for Jan 2021, canonical order for subsequent curves, correct theme-adaptive chrome in both renders
  • Log scale x-axis is the financially appropriate choice and uses ggplot2's scale_x_log10 with custom break labels elegantly
  • Shaded inversion zone + annotation adds genuine interpretive value; the visual contrast between the near-zero 2021 curve and 2023–2024 curves tells the monetary cycle story immediately
  • Clean code: KISS structure, fully deterministic, all imports used

Weaknesses

  • DE-01/DE-02: Tick marks remain visible on both axes — removing them (axis.ticks = element_blank()) would give the chart the cleaner financial-publication look it's aiming for
  • DE-01: Legend is functional but could be more integrated — e.g., direct line labels instead of a boxed legend, or at minimum reducing legend.key.width to avoid wasted horizontal space
  • LM-02: The inversion shading uses a fixed annotate("rect") spanning a manually chosen x range — a more distinctive approach would use geom_ribbon() between two curves to shade where the 2023/2024 curves exceed the 2021 curve, making the inversion region data-driven
  • VQ-03: Jan 2021 near-zero points (0.05%–0.09% for first 4 maturities) are nearly invisible against the x-axis baseline — increasing geom_point size to 3.5 or adding a subtle white stroke would improve distinguishability

Issues Found

  1. DE-01/DE-02 MODERATE: Tick marks still visible; removing them would lift visual refinement to the polished financial chart tier.
    • Fix: Add axis.ticks = element_blank() to the theme call
  2. DE-01 MODERATE: Boxed legend with key.width=1.5cm takes significant horizontal space; consider reducing to unit(1.2, "cm") or switching to direct line labels using geom_text/annotate at the right edge of each curve
  3. LM-02 LOW: Inversion shading is a fixed rect; data-driven ribbon shading using geom_ribbon would be more distinctive and accurate
  4. VQ-03 LOW: Near-zero Jan 2021 points are very small relative to axis line — increase point size or add white stroke

AI Feedback for Next Attempt

The core implementation is excellent — accurate data, correct chart type, proper Imprint palette, good theme adaptation. To reach 90+: (1) remove axis tick marks (axis.ticks = element_blank()) for a cleaner financial chart look, (2) replace the fixed annotate rect with a data-driven geom_ribbon between curve pairs to shade where short-term rates exceed long-term rates (makes the shading accurate and uses a distinctive ggplot2 approach), (3) consider direct-label annotations at the right edge of each curve instead of the boxed legend — this removes the heavy right legend and adds visual sophistication. These three changes address DE-01, DE-02, and LM-02 simultaneously.

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): Warm off-white background (#FAF8F1). Title "line-yield-curve · r · ggplot2 · anyplot.ai" in dark ink at the top left. Three yield curves plotted: Jan 2021 in brand green (#009E73) showing a steep upward-sloping curve from ~0.05% to ~1.83%; Jul 2023 in lavender (#C475FD) showing a deeply inverted curve starting at ~5.30% (short end) declining to ~3.96% (long end); Jan 2024 in blue (#4467A3) very close to Jul 2023 also inverted. A subtle light-gray ribbon fills the short-end region (1M–2Y) between the 2021 baseline and 2023 peak. "Inversion zone" annotation text appears above the ribbon in muted ink. X-axis uses log scale with maturity labels (1M to 30Y); Y-axis shows yield % from 0.0% to ~6.5%. Legend at right with colored line swatches. All text is clearly readable against the light background with no legibility failures. Legibility verdict: PASS.

Dark render (plot-dark.png): Warm near-black background (#1A1A17). Same three curves with identical data colors — green, lavender, blue — confirming palette invariance. Title and all axis labels/tick labels render in light ink (#F0EFE8 / #B8B7B0), fully readable. Grid lines are subtle against the dark surface. The ribbon is very subtle in dark mode (nearly invisible at alpha=0.10 on the dark surface) but the "Inversion zone" annotation is still visible. Legend box uses elevated dark background (#242420) with a soft border. No dark-on-dark text failures detected; all chrome tokens correctly adapt. Data colors are identical to the light render. Legibility verdict: PASS.

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

Score: 87/100

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

Visual Quality (28/30)

  • VQ-01: Text Legibility (7/8) — Font sizes explicitly set (title=12, axis=10, tick=8); all labels readable in both renders at full size. Minor: title is at the lower bound (~50%) of recommended 50–70% plot-width proportion.
  • VQ-02: No Overlap (6/6) — No text/data collisions; Jan 2021 curve is visually well-separated from the 2023/2024 inverted curves.
  • VQ-03: Element Visibility (5/6) — Lines (linewidth=1.2) and points (size=3.5) are clearly visible. Ribbon fill at alpha=0.10 is very subtle and nearly invisible in the dark render, reducing its effectiveness as a highlight.
  • VQ-04: Color Accessibility (2/2) — Imprint palette positions 1–3 (green/lavender/blue) are CVD-safe; no red-green sole-signal issue.
  • VQ-05: Layout & Canvas (4/4) — Canvas passes dimension gate (3200×1800). Good margins (20pt all sides), proportions well-balanced, no overflow.
  • VQ-06: Axis Labels & Title (2/2) — X-axis "Maturity", Y-axis "Yield (%)" with unit; both descriptive.
  • VQ-07: Palette Compliance (2/2) — First series (#009E73 brand green) ✓; positions 1→3 in canonical order; backgrounds #FAF8F1 / #1A1A17 ✓; chrome correctly flips between themes.

Design Excellence (13/20)

  • DE-01: Aesthetic Sophistication (5/8) — Above-default polish: Imprint palette applied correctly, ribbon + annotation add narrative intent, intentional hierarchy between the flat 2021 baseline and the inverted 2023/2024 cluster. Not exceptional (no emphasis technique distinguishes the most important curve, legend border adds minor visual noise).
  • DE-02: Visual Refinement (4/6) — Above-default refinement: panel border removed, minor grid removed, axis ticks removed, subtle major grid at 15% opacity. L-shaped axis lines add clean structure. Legend border slightly noisy per style-guide guidance to remove box frames.
  • DE-03: Data Storytelling (4/6) — Above-default storytelling: historically significant dates chosen (QE-era vs. peak-hiking-cycle vs. beginning-normalization) tell a coherent macro narrative. Ribbon + annotation guide the viewer toward the inversion concept. Could be stronger with explicit labeling of the most important curve or a subtitle/callout explaining the inversion signal.

Spec Compliance (14/15)

  • SC-01: Plot Type (5/5) — Correct multi-line yield curve on log-scale x-axis; all 11 maturity tenors plotted.
  • SC-02: Required Features (3/4) — Three curves ✓; legend with dates ✓; log-scale x-axis with maturity labels ✓. Minor: the ribbon is positioned between the Jan 2021 baseline and Jul 2023 short-end, labeled "Inversion zone" — this communicates the concept but doesn't strictly show "where short-term yields exceed long-term yields" within a single curve. A more precise approach would shade the area where each inverted curve's short-end exceeds its own long-end.
  • SC-03: Data Mapping (3/3) — maturity_years drives x-axis positioning; maturity strings used as tick labels; yield_pct on y-axis; all data points shown.
  • SC-04: Title & Legend (3/3) — Title "line-yield-curve · r · ggplot2 · anyplot.ai" matches required format; legend labels "Jan 2021", "Jul 2023", "Jan 2024" correct.

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Normal upward-sloping curve (Jan 2021), deeply inverted curve (Jul 2023), partially normalizing inverted curve (Jan 2024) — all key yield-curve shape variants represented.
  • DQ-02: Realistic Context (5/5) — Real US Treasury yield data; historically significant dates with accurate yield levels for each Fed policy regime; neutral framing.
  • DQ-03: Appropriate Scale (4/4) — Jan 2021 yields (0.05–1.83%) consistent with near-zero QE era; Jul 2023 (3.96–5.52%) consistent with 5.25–5.50% fed funds; Jan 2024 (3.97–5.52%) consistent with beginning normalization.

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Flat procedural script; no unnecessary functions or classes.
  • CQ-02: Reproducibility (2/2) — All data is hardcoded; deterministic output without requiring a seed.
  • CQ-03: Clean Imports (2/2) — library(ggplot2), library(scales), library(ragg) — all three imported and used.
  • CQ-04: Code Elegance (2/2) — Clean, readable code; appropriate complexity for this plot type; no fake UI.
  • CQ-05: Output & API (1/1) — Saves as plot-{THEME}.png via sprintf; uses current ggplot2 3.5.1 API (linewidth= not size= for lines).

Library Mastery (7/10)

  • LM-01: Idiomatic Usage (4/5) — Good ggplot2 grammar: geom_ribbon + geom_line + geom_point composition, scale_color_manual, scale_x_log10 with custom breaks/labels, expansion() for y-axis, theme_minimal() + theme() layering. Slightly above default.
  • LM-02: Distinctive Features (3/5) — Uses ggplot2-specific: scale_x_log10 with explicit breaks/labels, geom_ribbon for region highlighting, factor() with explicit levels for ordered legend, expansion(mult=) for y-axis breathing room, INK token alpha via scales::alpha(). Above default.

Score Caps Applied

  • None

Strengths

  • Correct Imprint palette applied in canonical order with first series as brand green
  • Full theme-adaptive chrome: all text, grid, legend, and background tokens correctly flip between light and dark renders
  • Historically accurate and narratively meaningful data (QE era → hiking cycle peak → normalization)
  • Idiomatic ggplot2 grammar with appropriate geom layering (ribbon + line + point)
  • Clean code: flat procedural script, all imports used, deterministic data, correct output filenames
  • Correct log-scale x-axis with maturity string labels properly positioned at numeric maturity_years
  • Good visual refinement: panel border removed, minor grid removed, ticks removed, subtle major grid

Weaknesses

  • Ribbon alpha=0.10 is too subtle — nearly invisible in the dark render; raise to alpha=0.18–0.22 so the inversion-zone highlight reads in both themes
  • Ribbon semantics imprecise: currently spans from Jan 2021 baseline to Jul 2023 at 1M–2Y, labeled "Inversion zone" — but the inversion is within the Jul 2023/Jan 2024 curves (short-end > long-end of the same curve); consider shading the area below the inverted curve's long-end yield level in the front-end region instead
  • Legend border box adds minor visual noise; style guide recommends removing legend box frames — consider legend.background = element_rect(fill = ELEVATED_BG, color = NA) or remove the border entirely
  • Title at size=12pt spans ~50% of plot width, at the lower bound of recommended 50–70%; slightly larger (13pt) would give it more visual authority

Issues Found

  1. VQ-03 LOW: Ribbon fill at alpha=0.10 nearly disappears in dark render, reducing effectiveness of the inversion-zone highlight.
    • Fix: Increase ribbon alpha to 0.18–0.22 so it reads on both the cream and near-black surfaces.
  2. SC-02 MINOR: Ribbon positions are between the 2021 baseline and 2023 short-end, but the spec asks to highlight "where short-term yields exceed long-term yields" — the ribbon doesn't directly encode this relationship within a single curve.
    • Fix: Either annotate more precisely (e.g. add a reference horizontal line at the long-end yield level) or adjust the ribbon to span from the 2Y yield down to the 30Y yield of the Jul 2023 curve, showing the excess.

AI Feedback for Next Attempt

Increase ribbon alpha from 0.10 to ~0.20 so the inversion-zone shading is visible in both light and dark renders. Reconsider ribbon semantics: the highlight should show where short-end yields exceed long-end yields within a single curve — e.g. shade the area between the short-end level and the 10Y/30Y level of the inverted curves. Remove the legend border (set color = NA) to reduce visual noise. Optionally increase title fontsize from 12 to 13 for slightly more visual authority. All other aspects (palette, canvas, theme tokens, code structure, data) are strong — keep them unchanged.

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 3640579 into main Jun 10, 2026
3 checks passed
@MarkusNeusinger MarkusNeusinger deleted the implementation/line-yield-curve/ggplot2 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