Skip to content

feat(letsplot): implement funnel-basic#5431

Merged
github-actions[bot] merged 4 commits intomainfrom
implementation/funnel-basic/letsplot
Apr 26, 2026
Merged

feat(letsplot): implement funnel-basic#5431
github-actions[bot] merged 4 commits intomainfrom
implementation/funnel-basic/letsplot

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

Implementation: funnel-basic - python/letsplot

Implements the python/letsplot version of funnel-basic.

File: plots/funnel-basic/implementations/python/letsplot.py

Parent Issue: #789


🤖 impl-generate workflow

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 26, 2026

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): Warm off-white background (#FAF8F1). Title "funnel-basic · letsplot · anyplot.ai" is bold, dark (#1A1A17), centered at top — clearly readable. Five trapezoidal funnel segments narrowing top-to-bottom: Awareness (#009E73 brand green, full canvas width), Interest (#D55E00 vermillion), Consideration (#0072B2 blue), Intent (#CC79A7 reddish purple), Purchase (#E69F00 orange-yellow, smallest rectangle). Each segment shows bold white text with stage name + comma-formatted count + percentage (e.g. "Awareness / 1,000 · 100%"). The Purchase stage correctly uses dark text (#1A1A17) on yellow for contrast. Subtle PAGE_BG-colored borders between segments create visual separation. Canvas utilization is good — funnel spans the full width at top and fills ~70% of vertical space. All text is readable against the light background. Legibility verdict: PASS.

Dark render (plot-dark.png): Near-black background (#1A1A17). Title is light (#F0EFE8) on dark background — clearly readable. All five funnel segments retain their identical Okabe-Ito colors (data colors unchanged from light render ✓). Awareness through Intent stage labels show white text on colored fills — all readable. The Purchase segment (yellow #E69F00) shows near-white text (INK = #F0EFE8 in dark mode) on the yellow background — contrast ratio approximately 2:1, below WCAG AA. The text "Purchase / 100 · 10%" is still marginally readable at this canvas size, but the contrast is suboptimal. No dark-on-dark failures for the other four stages. Overall legibility verdict: PASS with minor concern (Purchase stage dark-mode text contrast).

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

Score: 86/100

Category Score Max
Visual Quality 28 30
Design Excellence 12 20
Spec Compliance 15 15
Data Quality 15 15
Code Quality 10 10
Library Mastery 6 10
Total 86 100

Visual Quality (28/30)

  • VQ-01: Text Legibility (6/8) — Title and most labels are explicitly sized and readable; label size=12 declared (36pt effective with 3x scale, just below the 20pt-declared recommendation); dark-mode Purchase segment has near-white (#F0EFE8) on yellow (#E69F00) with ~2:1 contrast ratio
  • VQ-02: No Overlap (6/6) — No overlapping text; each label fits cleanly within its segment
  • VQ-03: Element Visibility (6/6) — All five segments clearly visible, distinct colors, appropriate sizing
  • VQ-04: Color Accessibility (2/2) — Okabe-Ito palette is CVD-safe; stages distinguishable by color + text labels, no red-green sole signal
  • VQ-05: Layout & Canvas (4/4) — Funnel fills ~70% of vertical canvas, centered with balanced whitespace; top segment spans full width
  • VQ-06: Axis Labels & Title (2/2) — Title in correct format; no axis labels appropriate for funnel chart with embedded labels
  • VQ-07: Palette Compliance (2/2) — First stage = #009E73 ✓; Okabe-Ito order maintained ✓; light bg = #FAF8F1 ✓; dark bg = #1A1A17 ✓; data colors identical across themes ✓

Design Excellence (12/20)

  • DE-01: Aesthetic Sophistication (5/8) — Above default: adaptive text-on-fill color logic (white on colored stages, dark on yellow) shows design thought; segment gap borders add polish; theme_void creates a clean canvas. Not yet publication-ready — no typography hierarchy within labels, no emphasis on key conversion drops.
  • DE-02: Visual Refinement (4/6) — theme_void() removes all unnecessary chrome; PAGE_BG segment borders add breathing room between stages; generous whitespace around funnel. Could go further with refined title font weight or subtle shadow/depth on segments.
  • DE-03: Data Storytelling (3/6) — Self-contained labels (name + count + %) communicate data clearly. The funnel shape provides natural size-based hierarchy. However no visual emphasis on where the steepest conversion drop occurs — all stages receive equal visual weight despite widely different drop-off rates.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct trapezoidal funnel chart with proportional widths
  • SC-02: Required Features (4/4) — Stages ordered large→small ✓; distinct Okabe-Ito colors per stage ✓; value + percentage labels on each segment ✓; widths proportional to value/max_value ✓
  • SC-03: Data Mapping (3/3) — Stages 5-deep from Awareness to Purchase; values 1000→100; widths correctly normalized by first stage value
  • SC-04: Title & Legend (3/3) — Title "funnel-basic · letsplot · anyplot.ai" exact format ✓; legend suppressed with guide="none" (appropriate — segments are self-labeled)

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Shows all funnel aspects: progressive narrowing, proportional widths, 5-stage depth, percentage drop visualization
  • DQ-02: Realistic Context (5/5) — Sales/marketing funnel is a standard neutral real-world use case; stage names (Awareness→Purchase) are industry-standard marketing funnel terminology
  • DQ-03: Appropriate Scale (4/4) — 1000→100 represents a realistic ~10% overall conversion rate; progressive drops are plausible (40%, 33%, 50%, 50%)

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Flat script: imports → tokens → data → polygon construction → plot → save; no unnecessary functions or classes
  • CQ-02: Reproducibility (2/2) — Deterministic hardcoded data; no random state needed
  • CQ-03: Clean Imports (2/2) — All imported symbols are used; os for theme env var; all lets_plot imports active
  • CQ-04: Code Elegance (2/2) — Clean Pythonic loop with strict=True zip; TEXT_ON_FILL list cleanly maps fill→text colors; no over-engineering
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png (scale=3) and plot-{THEME}.html ✓; no bare plot.png

Library Mastery (6/10)

  • LM-01: Idiomatic Usage (4/5) — Good ggplot grammar usage: geom_polygon for custom shape, scale_color_identity to pass literal hex colors through aes mapping, scale_y_reverse for orientation, theme_void for clean canvas; correct ggsave with scale parameter
  • LM-02: Distinctive Features (2/5) — geom_polygon for funnel construction is creative; HTML export (plot-{THEME}.html) is lets_plot-distinctive. Could further leverage lets_plot-specific interactivity in the HTML (tooltips showing conversion rates on hover) or geom_label for padded text boxes.

Score Caps Applied

  • None — all caps conditions evaluated; none triggered (DE-01=5 > 2, DE-02=4 > 2, CQ-04=2 > 0)

Strengths

  • Custom trapezoid geometry via geom_polygon is correct and creative — produces proper funnel shape with proportional widths and visual gaps between stages
  • Adaptive text-color logic (TEXT_ON_FILL list, dark ink on yellow #E69F00, white on other stages) shows deliberate design thought for the light theme
  • Perfect spec compliance — all required features present, correct example data, correct title format
  • theme_void() + segment gap borders = genuinely clean minimal output with no unnecessary chrome
  • Code is flat, deterministic, and Pythonic (strict=True zip, categorical ordering)

Weaknesses

  • Dark-mode Purchase text: TEXT_ON_FILL[4] resolves to INK = "#F0EFE8" (near-white) in dark theme — white on yellow #E69F00 has ~2:1 contrast ratio. Fix: hardcode "#1A1A17" for Purchase text in both themes (yellow always needs dark text)
  • Design excellence limited — no visual emphasis on the steepest conversion drop-off; all stages receive equal weight despite very different drop rates (e.g. Intent→Purchase is only 50%)
  • Label size=12 declared (36pt effective); could increase to 14-16pt declared for better compliance with the ≥20pt label recommendation
  • Library mastery could leverage lets_plot interactive HTML features (tooltips with conversion rates) since HTML is already being exported

Issues Found

  1. VQ-01 / Dark-mode contrast: TEXT_ON_FILL = ["white", "white", "white", "white", INK] — in dark theme INK = "#F0EFE8", which is near-white on yellow (#E69F00), giving ~2:1 contrast ratio.

    • Fix: Replace INK in TEXT_ON_FILL with the literal "#1A1A17" so Purchase text is always dark regardless of theme.
  2. DE-03 LOW: No visual hierarchy distinguishes high vs. low drop-off stages. Viewer must mentally compute which transitions are most significant.

    • Fix: Add inter-stage drop-off annotations (e.g. small "▼ −40%" labels between Awareness and Interest in the gaps), or vary label font size by stage weight to create focal emphasis.
  3. DE-01 MODERATE: Design is above default but not publication-ready. Typography within labels is uniform (all bold, same size), and no visual treatment adds depth beyond the flat color fills.

    • Fix: Vary title size upward (e.g. size=28), add a subtle subtitle or data source note, or use slightly reduced alpha on non-focal segments to draw attention.

AI Feedback for Next Attempt

Fix dark-mode Purchase text: replace INK in TEXT_ON_FILL with literal "#1A1A17" so yellow stage always uses dark text. Add visual storytelling: insert inter-stage conversion rate drop annotations (e.g. "▼ −40%" in the gaps between segments) to highlight where drop-offs are steepest. Increase label text size from 12 to 14-16pt declared. These changes will lift VQ-01, DE-01, and DE-03 significantly.

Verdict: REJECTED

@github-actions github-actions Bot added quality:86 Quality score 86/100 ai-approved Quality OK, ready for merge labels Apr 26, 2026
@github-actions github-actions Bot merged commit 416faf4 into main Apr 26, 2026
3 checks passed
@github-actions github-actions Bot deleted the implementation/funnel-basic/letsplot branch April 26, 2026 06:05
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 quality:86 Quality score 86/100

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants