Skip to content

feat(letsplot): implement line-win-probability#5091

Merged
github-actions[bot] merged 5 commits intomainfrom
implementation/line-win-probability/letsplot
Mar 20, 2026
Merged

feat(letsplot): implement line-win-probability#5091
github-actions[bot] merged 5 commits intomainfrom
implementation/line-win-probability/letsplot

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

Implementation: line-win-probability - letsplot

Implements the letsplot version of line-win-probability.

File: plots/line-win-probability/implementations/letsplot.py

Parent Issue: #4418


🤖 impl-generate workflow

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 20, 2026

AI Review - Attempt 1/3

Image Description

The plot displays a win probability chart for an Eagles vs Cowboys NFL game. The title reads "line-win-probability · letsplot · pyplots.ai" with a subtitle "Eagles 27 – Cowboys 17 · Eagles recover from Q3 deficit for convincing finish". The y-axis shows "Eagles Win Probability" from 0% to 100% with a dashed gray 50% reference line. The x-axis shows "Game Progress" with quarter labels (Q1, Q2, Q3, Q4, End) separated by dotted vertical lines. A thick dark line traces the win probability over ~120 plays. Area above 50% is filled with a muted teal/dark green (Eagles color, #004C54) at alpha 0.35, and area below 50% is filled with a gray (#869397) at alpha 0.35. Five key scoring events are annotated with white-filled circle markers and text labels: "Cowboys TD 3-7", "Eagles TD 10-7", "Cowboys TD 13-14", "Eagles TD 20-14", and "Eagles TD 27-17". The probability starts at 50%, rises early in Q1, drops after the Cowboys TD, fluctuates around 50% through Q2-Q3, then surges sharply to near 100% at the end. The background is clean white with subtle horizontal gridlines on major y-axis ticks only.

Score: 89/100

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

Visual Quality (27/30)

  • VQ-01: Text Legibility (8/8) — All font sizes explicitly set: title 24pt, axis titles 20pt, tick labels 16pt, subtitle 16pt. All text is clearly readable.
  • VQ-02: No Overlap (4/6) — The "Eagles TD 27-17" annotation is crowded at the right edge with the "17" partially overlapping the area fill boundary. Two annotation points near end-of-game are close together with labels competing for space.
  • VQ-03: Element Visibility (6/6) — Line thickness (1.8) is well-chosen for 120 data points. Markers are clearly visible with white fill and dark stroke. Area fills at alpha 0.35 provide good contrast without obscuring the line.
  • VQ-04: Color Accessibility (4/4) — Teal green vs gray is colorblind-safe. No red-green reliance. Good contrast between filled areas.
  • VQ-05: Layout & Canvas (3/4) — Plot fills canvas well horizontally. However, the lower portion (0-25%) is largely empty since probability never drops that low, creating some wasted vertical space. Margins are explicitly set and balanced.
  • VQ-06: Axis Labels & Title (2/2) — "Eagles Win Probability" and "Game Progress" are descriptive. Percentage formatting on y-axis provides implicit units.

Design Excellence (16/20)

  • DE-01: Aesthetic Sophistication (6/8) — Thoughtful use of actual team colors (Eagles dark teal, Cowboys gray) rather than defaults. Dark line with white-filled circle markers creates a clean, sports-broadcast aesthetic. Narrative subtitle adds context. Clearly above library defaults.
  • DE-02: Visual Refinement (5/6) — theme_minimal removes spines. Major x-grid removed, minor grid removed, only subtle y-gridlines remain. Generous margins (40/60/20/20). Quarter dividers use dotted lines at low opacity. Well-polished.
  • DE-03: Data Storytelling (5/6) — Subtitle narrates the game outcome. Annotations highlight the key momentum shifts. Area fill color-codes which team is favored. The dramatic Q4 surge is visually impactful. Clear focal point and story arc.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Win probability line chart with area fill — correct chart type.
  • SC-02: Required Features (4/4) — Y-axis 0-100% ✓, prominent 50% reference line ✓, area fill above/below 50% with team colors ✓, annotated scoring events ✓, final score in subtitle ✓, quarter markers on x-axis ✓.
  • SC-03: Data Mapping (3/3) — X = play number (game progression), Y = win probability. Axes show full range.
  • SC-04: Title & Legend (3/3) — Title follows exact format "line-win-probability · letsplot · pyplots.ai". No legend needed for this single-series chart; team colors are implied by area fill context.

Data Quality (14/15)

  • DQ-01: Feature Coverage (5/6) — Shows lead changes, momentum swings in both directions, close game through the middle, and a decisive finish. Multiple scoring event types (TD, FG). Could show more dramatic back-and-forth to fully exercise the visualization.
  • DQ-02: Realistic Context (5/5) — NFL game between real teams (Eagles vs Cowboys). Realistic scoring progression with field goals and touchdowns. Neutral sports context.
  • DQ-03: Appropriate Scale (4/4) — Win probabilities correctly bounded 0-1, starting at 0.50. Score progression is realistic (3-0, 3-7, 10-7, 13-7, 13-14, 20-14, 20-17, 27-17). 120 plays is realistic for an NFL game.

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Clean linear flow: imports → data generation → event definitions → dataframe → plot → save. No functions or classes.
  • CQ-02: Reproducibility (2/2) — np.random.seed(42) set at the top.
  • CQ-03: Clean Imports (2/2) — All imports used: numpy, pandas, lets_plot, export_ggsave.
  • CQ-04: Code Elegance (2/2) — Appropriate complexity. Tooltip configuration is a legitimate letsplot feature, not fake interactivity. Helper columns (above_50, below_50) for ribbon fill are clean.
  • CQ-05: Output & API (1/1) — Saves as plot.png with export_ggsave(plot, filename="plot.png", path=".", scale=3). Also exports HTML.

Library Mastery (7/10)

  • LM-01: Idiomatic Usage (4/5) — Uses ggplot grammar idiomatically: aes(), geom_ribbon, geom_line, geom_hline, geom_vline, geom_point, geom_text, scale_*_continuous, labs, theme_minimal + theme(). Proper layered composition.
  • LM-02: Distinctive Features (3/5) — Uses layer_tooltips() with .line() and .format() — a letsplot-specific interactive tooltip API. HTML export via export_ggsave is also distinctive. Could leverage more unique letsplot features (e.g., geom_label with custom styling, coord_cartesian for zooming).

Score Caps Applied

  • None

Strengths

  • Excellent spec compliance — all required features present including area fill, 50% reference, quarter markers, annotations, and final score
  • Strong data storytelling with narrative subtitle and well-chosen annotation points
  • Clean visual design with team colors, refined grid, and professional typography
  • Idiomatic letsplot usage with proper ggplot grammar and layer composition
  • Perfect code quality with clean structure and reproducibility

Weaknesses

  • Annotation crowding at the right edge — "Eagles TD 27-17" label overlaps with the area boundary and is close to other annotations
  • Lower portion of the chart (0-25%) is underutilized empty space
  • Could leverage more distinctive letsplot features beyond tooltips

Issues Found

  1. VQ-02 MODERATE: Annotation labels crowded near the right edge of the plot, with "Eagles TD 27-17" overlapping the area fill boundary
    • Fix: Adjust nudge_y direction for some labels or use alternating label positions (above/below) to prevent crowding. Consider reducing the number of late-game annotations or repositioning them.
  2. LM-02 MODERATE: Generic ggplot usage that could be replicated in plotnine with minor syntax changes
    • Fix: Consider using letsplot-specific features like geom_label with background fill, or flavor_* theme functions for distinctive styling

AI Feedback for Next Attempt

Score is 89 — very close to approval. Primary fix needed: resolve annotation overlap at the right edge of the chart where "Eagles TD 27-17" crowds against the plot boundary. Consider alternating label positions (nudge above vs below the line) or reducing annotation density in the final quarter. Also consider using more distinctive letsplot features like flavor_darcula() or geom_label() to push library mastery higher.

Verdict: REJECTED

@github-actions github-actions Bot added quality:89 Quality score 89/100 ai-rejected Quality not OK, triggers update labels Mar 20, 2026
@github-actions github-actions Bot added ai-attempt-1 First repair attempt and removed ai-rejected Quality not OK, triggers update labels Mar 20, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

🔧 Repair Attempt 1/3

Applied fixes based on AI review feedback.

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


🤖 impl-repair

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 20, 2026

AI Review - Attempt 2/3

Image Description

The plot displays a win probability chart for an Eagles vs Cowboys NFL game. A bold dark line traces the Eagles' win probability from Q1 through the end of the game across 120 plays. The x-axis shows game progress with quarter labels (Q1, Q2, Q3, Q4, End) separated by dotted vertical dividers. The y-axis ranges from 0% to 100% with a dashed horizontal reference line at 50%. The area above 50% is filled with a muted dark teal (#004C54, Eagles green) and the area below 50% is filled with a subtle gray (#869397). Five key scoring events are annotated with white circle markers and labeled boxes: Cowboys TD 3-7, Eagles TD 10-7, Cowboys TD 13-14, Eagles TD 20-14, and Eagles TD 27-17. Labels alternate above and below the line to avoid overlap. The title reads "line-win-probability · letsplot · pyplots.ai" with a narrative subtitle "Eagles 27 – Cowboys 17 · Eagles recover from Q3 deficit for convincing finish". The plot uses a high-contrast light theme with only subtle horizontal grid lines, no x-axis grid, and generous whitespace.

Score: 92/100

Category Score Max
Visual Quality 29 30
Design Excellence 16 20
Spec Compliance 15 15
Data Quality 15 15
Code Quality 10 10
Library Mastery 7 10
Total 92 100

Visual Quality (29/30)

  • VQ-01: Text Legibility (8/8) — All font sizes explicitly set: title=24, subtitle=16, axis_title=20, axis_text=16. All text perfectly readable at output resolution.
  • VQ-02: No Overlap (6/6) — Annotation labels use alternating vertical nudge positions to avoid collisions. All text fully readable with no overlaps.
  • VQ-03: Element Visibility (6/6) — Line width 1.8 is well-adapted, event markers (size=6, white fill, dark stroke) are clearly visible, area fills at alpha=0.35 provide context without obscuring the line.
  • VQ-04: Color Accessibility (4/4) — Dark teal vs gray is colorblind-safe with strong luminance contrast. No red-green differentiation issues.
  • VQ-05: Layout & Canvas (3/4) — Good proportions and margins (40,60,20,20). Plot fills canvas well. Minor deduction: the 0-25% y-range is largely unused since probability rarely drops below ~35%, creating some empty space at the bottom — though this is spec-compliant (spec requires 0-100% range).
  • VQ-06: Axis Labels & Title (2/2) — "Eagles Win Probability" and "Game Progress" are descriptive. Y-axis shows percentage format.

Design Excellence (16/20)

  • DE-01: Aesthetic Sophistication (6/8) — Thoughtful team-colored palette with muted tones appropriate for area fills. Narrative subtitle adds editorial quality. High-contrast light flavor provides clean typography. Above defaults but not quite FiveThirtyEight-level — the gray away-team fill is functional but doesn't create as strong a two-team visual identity as bolder color choices would.
  • DE-02: Visual Refinement (5/6) — Excellent: minimal grid (y-major only, subtle #E0E0E0), x-grid removed, minor grid removed, generous margins, theme_minimal + flavor_high_contrast_light effectively removes spines. Quarter dividers use dotted lines. One point shy of perfect — the dashed 50% line could use slightly more prominence to anchor the visual.
  • DE-03: Data Storytelling (5/6) — Strong narrative: subtitle tells the game story, annotations highlight key momentum shifts, the line's trajectory clearly shows the Q3 deficit and Q4 recovery. The alternating label positions guide the eye through the game timeline. Viewer immediately grasps the game arc.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct: line chart with area fill showing win probability evolution over game progression.
  • SC-02: Required Features (4/4) — All spec requirements met: Y-axis 0-100% ✓, prominent 50% reference line ✓, area fill above/below 50% with team colors ✓, annotated scoring events ✓, final score in subtitle ✓, quarter markers on x-axis ✓.
  • SC-03: Data Mapping (3/3) — X=play number (game progression), Y=win probability (0-1 scale displayed as percentage). Correct mapping.
  • SC-04: Title & Legend (3/3) — Title follows exact format "line-win-probability · letsplot · pyplots.ai". No legend needed as team identity is conveyed through area fill colors and annotations.

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Shows multiple lead changes, momentum swings crossing the 50% line, scoring events from both teams (FGs and TDs), and final convergence to winner. Both teams contribute to the narrative.
  • DQ-02: Realistic Context (5/5) — NFL game between Eagles and Cowboys with realistic scoring events (field goals, touchdowns), plausible final score (27-17), and neutral sports context.
  • DQ-03: Appropriate Scale (4/4) — 120 plays is realistic for an NFL game. Win probability starts at 50%, fluctuates within realistic bounds, and converges to ~97% at game end. Score progression is plausible.

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Clean linear flow: imports → seed → data generation → event definitions → dataframe → plot construction → save. No functions or classes.
  • CQ-02: Reproducibility (2/2) — np.random.seed(42) set at the start.
  • CQ-03: Clean Imports (2/2) — All imports used: numpy, pandas, lets_plot (wildcard with noqa is idiomatic for letsplot), export_ggsave.
  • CQ-04: Code Elegance (2/2) — Clean and well-organized. The alternating nudge positions for labels is elegant. Event data structure is clear and maintainable. No fake UI or over-engineering.
  • CQ-05: Output & API (1/1) — Saves as plot.png via export_ggsave with scale=3. Also exports HTML. Current API usage.

Library Mastery (7/10)

  • LM-01: Idiomatic Usage (4/5) — Uses ggplot grammar fluently: aes mappings, geom_ribbon for area fills, geom_line, geom_label with padding/radius parameters, geom_hline/geom_vline, scale_y_continuous with custom labels, coord_cartesian, theme composition. Idiomatic letsplot throughout.
  • LM-02: Distinctive Features (3/5) — Uses letsplot-specific features: layer_tooltips() for interactive hover information, flavor_high_contrast_light() theming, geom_label with label_padding/label_r/label_size parameters, and HTML export alongside PNG. The tooltips are a genuine interactive feature unique to letsplot.

Score Caps Applied

  • None — No cap conditions triggered.

Strengths

  • Excellent data storytelling with narrative subtitle and well-placed event annotations that guide the viewer through the game arc
  • Clean visual design with muted team-colored area fills, minimal grid, and high-contrast light theme
  • Full spec compliance — all required features implemented including area fills, 50% reference line, quarter markers, event annotations, and final score
  • Realistic NFL game data with plausible scoring progression and multiple momentum shifts
  • Good use of letsplot-specific features (interactive tooltips, flavor theming, geom_label customization)

Weaknesses

  • Away team gray fill (#869397) could use a slightly more distinctive team color to strengthen the two-team visual identity
  • The 50% baseline dashed line could be slightly more prominent to better anchor the visual comparison
  • Could explore additional letsplot-distinctive features for higher library mastery

Issues Found

None requiring rejection. Minor improvements possible but overall quality exceeds the 90-point threshold.

AI Feedback for Next Attempt

N/A — Implementation approved. Strong improvement from attempt 1 with good design polish, clear data storytelling, and full spec compliance.

Verdict: APPROVED

@github-actions github-actions Bot added quality:92 Quality score 92/100 ai-approved Quality OK, ready for merge labels Mar 20, 2026
@github-actions github-actions Bot merged commit 3210f1b into main Mar 20, 2026
3 checks passed
@github-actions github-actions Bot deleted the implementation/line-win-probability/letsplot branch March 20, 2026 12:44
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:89 Quality score 89/100 quality:92 Quality score 92/100

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants