Skip to content

feat(ggplot2): implement waveform-audio#8294

Merged
MarkusNeusinger merged 6 commits into
mainfrom
implementation/waveform-audio/ggplot2
Jun 3, 2026
Merged

feat(ggplot2): implement waveform-audio#8294
MarkusNeusinger merged 6 commits into
mainfrom
implementation/waveform-audio/ggplot2

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot commented Jun 3, 2026

Implementation: waveform-audio - r/ggplot2

Implements the r/ggplot2 version of waveform-audio.

File: plots/waveform-audio/implementations/r/ggplot2.R

Parent Issue: #4563


🤖 impl-generate workflow

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 3, 2026

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): Warm off-white background (#FAF8F1). A brand-green (#009E73) filled ribbon waveform spans 0–2 seconds, symmetric around the zero axis, showing a seismic trace: quiet noise (0–0.4s), a high-frequency P-wave transient (peak ~0.35 normalized, arriving at 0.4s), a higher-amplitude lower-frequency S-wave (peak ~0.9 normalized, arriving at 0.8s), and a decaying coda (from 1.3s). A muted horizontal zero-line is clearly visible. Subtle grey grid lines at 0.25s intervals. Title "Seismic P-wave & S-wave Arrivals · waveform-audio · r · ggplot2 · anyplot.ai" in dark ink (~11pt), axis labels in dark ink (10pt), tick labels in #4A4A44 (8pt). All text is clearly readable against the light background.

Dark render (plot-dark.png): Warm near-black background (#1A1A17). Waveform fill color is identical #009E73 — matching the light render exactly (only chrome flips). Title, axis labels, and tick labels render in light cream/muted tones (#F0EFE8 / #B8B7B0), clearly readable against the dark background. Grid lines adapt to a faint dark-theme INK_MUTED. No dark-on-dark failures observed — all text is light-colored and legible.

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

Score: 87/100

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

Visual Quality (29/30)

  • VQ-01: Text Legibility (7/8) — All font sizes explicitly set (dynamic title ~11pt, axis labels 10pt, ticks 8pt). Both renders readable. Tick labels are on the small side for mobile but pass.
  • VQ-02: No Overlap (6/6) — No overlapping elements in either render.
  • VQ-03: Element Visibility (6/6) — Ribbon with alpha=0.78 is appropriate for 8000-point dense waveform. Shape clearly visible in both themes.
  • VQ-04: Color Accessibility (2/2) — Single-series brand green on warm backgrounds. High contrast, CVD-safe.
  • VQ-05: Layout & Canvas (4/4) — 3200×1800 landscape confirmed. Balanced margins.
  • VQ-06: Axis Labels & Title (2/2) — "Time (s)" with units; "Normalized Amplitude" descriptive for normalized data.
  • VQ-07: Palette Compliance (2/2) — First (only) series is #009E73. Backgrounds are #FAF8F1 light / #1A1A17 dark. All chrome tokens theme-adaptive.

Design Excellence (12/20)

  • DE-01: Aesthetic Sophistication (5/8) — Above a plain library default: Imprint palette, theme tokens, thoughtful geom_ribbon approach. Not yet "strong design" — lacks intentional visual hierarchy or emphasis points.
  • DE-02: Visual Refinement (4/6) — Good: panel border removed, axis ticks removed, minor grid blank, major grid subtle (linewidth=0.2), generous margins. Not perfect: axis.line retained on all sides rather than a clean L-shape or no spines.
  • DE-03: Data Storytelling (3/6) — The waveform data has a clear phase structure (noise → P-wave → S-wave → coda) but the plot provides no visual guidance. The title promises "P-wave & S-wave Arrivals" but neither phase boundary is marked. The viewer must already know seismology to find the story.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct waveform using geom_ribbon for filled area symmetric around zero.
  • SC-02: Required Features (4/4) — Filled area, semi-transparent fill (alpha=0.78), horizontal zero-line, time X-axis, normalized amplitude Y-axis (-1 to +1), synthetic data. All present.
  • SC-03: Data Mapping (3/3) — Time on X, amplitude on Y with correct limits and breaks.
  • SC-04: Title & Legend (3/3) — Format "{Descriptive} · waveform-audio · r · ggplot2 · anyplot.ai" correct. No legend (single series — correct).

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Shows all waveform aspects: noise baseline, P-wave transient (high frequency, moderate amplitude), S-wave (lower frequency, higher amplitude), coda decay. Full dynamic range.
  • DQ-02: Realistic Context (5/5) — Seismology (earthquake P/S-wave detection) is a real, neutral, scientifically grounded application of waveform visualization.
  • DQ-03: Appropriate Scale (4/4) — P-wave at 0.4s, S-wave at 0.8s — physically plausible inter-phase timing. Normalized to 0.92 peak. 0–2s time domain realistic for a short seismic trace.

Code Quality (9/10)

  • CQ-01: KISS Structure (3/3) — Clean linear flow: imports → tokens → data → plot → save. No functions or classes.
  • CQ-02: Reproducibility (2/2) — set.seed(42) present.
  • CQ-03: Clean Imports (1/2) — library(dplyr) is loaded but never used. No dplyr verbs, no pipe; data.frame() is base R throughout. Remove it.
  • CQ-04: Code Elegance (2/2) — pmin/pmax inside aes() is concise and correct. No over-engineering.
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png via ragg::agg_png. Current API.

Library Mastery (7/10)

  • LM-01: Idiomatic Usage (4/5) — geom_ribbon with pmin/pmax in aes() is the idiomatic ggplot2 approach for a sign-split filled waveform. scale_x_continuous, expansion(), theme_minimal() chain all idiomatic.
  • LM-02: Distinctive Features (3/5) — The aes(ymin = pmin(amplitude, 0), ymax = pmax(amplitude, 0)) pattern for splitting the ribbon at zero is a ggplot2-specific declarative idiom. More distinctive than a generic line plot.

Score Caps Applied

  • None

Strengths

  • geom_ribbon with pmin/pmax in aes() elegantly creates the symmetric waveform fill in one declarative layer — idiomatic ggplot2
  • Seismic context (P-wave, S-wave, coda) is scientifically accurate and domain-appropriate
  • Full theme-adaptive chrome correctly flips background, text, and grid tokens; data color #009E73 is identical in both renders
  • All spec requirements met: filled area mirrored at zero, semi-transparent fill, zero-line, correct axis ranges
  • Dynamic title font-size scaling prevents overflow
  • Subtle grid and removed ticks produce a clean, polished look

Weaknesses

  • Unused import: library(dplyr) is loaded but not called anywhere — remove it
  • No phase annotations: the title promises "P-wave & S-wave Arrivals" but neither phase is marked in the plot. Add geom_vline() at t=0.4s (P) and t=0.8s (S) plus annotate('text', ...) labels to anchor the viewer.
  • DE-01 headroom: adding phase-line annotations and subtle visual hierarchy would push aesthetic sophistication from 5/8 toward 6/8.

Issues Found

  1. CQ-03 — Unused import: library(dplyr) is imported but no dplyr functions are used
    • Fix: Remove the library(dplyr) line
  2. DE-03 LOW — No storytelling: Title says "P-wave & S-wave Arrivals" but plot doesn't mark them
    • Fix: Add geom_vline(xintercept = c(0.4, 0.8), linetype = 'dashed', color = INK_MUTED, linewidth = 0.5) and annotate('text', x = c(0.4, 0.8), y = 1.0, label = c('P', 'S'), ...) to label the phase arrivals
  3. DE-01 — Aesthetic headroom: Refine visual hierarchy to push above 5/8
    • Fix: Differentiate the phase annotation lines from the zero-line (different linetype/color), and tighten whitespace around the zero-line label

AI Feedback for Next Attempt

Three targeted fixes will clear the 90-point threshold: (1) Remove library(dplyr) — it's never used. (2) Mark the P-wave (t=0.4s) and S-wave (t=0.8s) arrivals with subtle dashed vertical lines and small text labels ("P", "S") in INK_MUTED — the title promises them, the body should deliver. (3) Use INK_SOFT or INK_MUTED for the phase lines (not the brand green) so they read as reference chrome rather than data. Keep everything else — the geom_ribbon pmin/pmax approach, the dynamic title size, the theme tokens — all are correct.

Verdict: REJECTED

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

github-actions Bot commented Jun 3, 2026

🔧 Repair Attempt 1/4

Applied fixes based on AI review feedback.

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


🤖 impl-repair

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 3, 2026

AI Review - Attempt 2/3

Image Description

Light render (plot-light.png): The plot shows a seismic waveform on a warm off-white (#FAF8F1) background. The filled ribbon (brand green #009E73, alpha≈0.78) is symmetric around zero, with a clear quiet section before the P-wave arrival at 0.4 s, a moderate P-wave packet, then a large-amplitude S-wave burst centred around 0.85–1.0 s, followed by decaying coda. Vertical dashed lines mark the P and S arrivals with bold 'P' and 'S' text annotations at y=0.90. The zero-line is a thin horizontal rule. Axis labels 'Time (s)' and 'Normalized Amplitude' are clearly readable in dark ink; tick labels (0.00–2.00, −1 to 1) are smaller but legible. Title 'Seismic P-wave & S-wave Arrivals · waveform-audio · r · ggplot2 · anyplot.ai' spans ~85–90% of the canvas width at the calculated 11pt. All text is readable against the light background.
Legibility verdict: PASS

Dark render (plot-dark.png): The same waveform on the warm near-black (#1A1A17) background. The green ribbon (#009E73) is identically coloured to the light render — highly visible and vibrant against the dark surface. Chrome elements flip correctly: title and axis labels render in cream (#F0EFE8), tick labels in #B8B7B0, grid lines in #A8A79F. The 'P' and 'S' annotations appear in cream ink, clearly readable. No dark-on-dark failures observed; all text is legible. Grid lines are slightly more prominent on the dark background than the light one (ggplot2 cannot use alpha for grid lines), but not overwhelming.
Legibility verdict: PASS

Score: 89/100

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

Visual Quality (29/30)

  • VQ-01: Text Legibility (7/8) — All text readable in both themes; title at computed 11pt (only 1pt above 10pt axis labels) creates a narrow hierarchy. All readable at full resolution.
  • VQ-02: No Overlap (6/6) — P/S annotations at y=0.90 are above waveform peaks; no collision with data or other text
  • VQ-03: Element Visibility (6/6) — 8000-sample ribbon with alpha=0.78 is density-appropriate; waveform prominent in both themes
  • VQ-04: Color Accessibility (2/2) — Single brand-green series; P/S distinguished by line style + label, not color alone
  • VQ-05: Layout & Canvas (4/4) — Canvas gate passed (3200×1800); generous margins; nothing clipped; good proportions
  • VQ-06: Axis Labels & Title (2/2) — 'Time (s)' and 'Normalized Amplitude' are descriptive with units
  • VQ-07: Palette Compliance (2/2) — First (only) series #009E73; backgrounds #FAF8F1/#1A1A17; both renders theme-correct

Design Excellence (12/20)

  • DE-01: Aesthetic Sophistication (5/8) — Above default: purposeful seismic application with annotated P/S arrivals shows intentional design; clean typography; but single-color ribbon is visually simple
  • DE-02: Visual Refinement (3/6) — Good: axis ticks removed, minor grid disabled, panel border removed with L-frame axis lines, subtle major grid; solid refinement above baseline
  • DE-03: Data Storytelling (4/6) — Clear narrative: quiet pre-P noise → P-wave arrival → dominant S-wave → coda decay; vertical reference lines guide the viewer effectively

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct filled-area waveform symmetric around zero using geom_ribbon
  • SC-02: Required Features (4/4) — Semi-transparent fill ✓, zero-line reference ✓, time on x-axis ✓, normalized amplitude −1 to +1 ✓, synthetic data ✓
  • SC-03: Data Mapping (3/3) — Time in seconds on X, normalized amplitude on Y, y-limits ±1.05 show all data
  • SC-04: Title & Legend (3/3) — Title uses optional descriptive prefix + correct format; no legend needed for single series

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Waveform shows filled area, zero-line, amplitude envelope dynamics, P/S annotations, and coda
  • DQ-02: Realistic Context (5/5) — Seismic P-wave/S-wave arrivals is a canonical waveform application (listed in spec); realistic decay envelopes
  • DQ-03: Appropriate Scale (4/4) — 8000 samples over 2 s at realistic amplitudes normalized to [−0.92, 0.92]

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Flat linear script, no functions or classes
  • CQ-02: Reproducibility (2/2) — set.seed(42) at top
  • CQ-03: Clean Imports (2/2) — Only ggplot2 and ragg imported, both used
  • CQ-04: Code Elegance (2/2) — Clean structure; dynamic title size formula is elegant; no fake UI
  • CQ-05: Output & API (1/1) — Saves as plot-{THEME}.png via ggsave with ragg::agg_png

Library Mastery (8/10)

  • LM-01: Idiomatic Usage (5/5) — Excellent: geom_ribbon(aes(ymin=pmin(amplitude,0), ymax=pmax(amplitude,0))) is the idiomatic ggplot2 pattern for split-fill waveforms; expansion(), annotate(), and theme layer composition all correct
  • LM-02: Distinctive Features (3/5) — Good use of layer composition and expansion() but no particularly advanced ggplot2 capability demonstrated beyond standard geoms

Score Caps Applied

  • None

Strengths

  • is the correct and idiomatic ggplot2 pattern for waveform visualization — splits the ribbon at the zero line elegantly
  • Seismic P-wave/S-wave application with annotated arrival markers adds meaningful context and data storytelling well above a generic demo
  • Perfect spec compliance: all required features present (zero-line, semi-transparent fill, correct normalized axes, synthetic data)
  • Flawless theme adaptation — every chrome element uses the correct INK/INK_SOFT/INK_MUTED token; dark render has no dark-on-dark failures
  • Dynamic title size formula (max(8, round(12 * 67 / nchar(title)))) handles the long descriptive prefix correctly

Weaknesses

  • Title size floor is 8pt — for this title the computed size is 11pt which is only 1pt above the 10pt axis labels; minimal visual hierarchy between title and labels. Raise the floor to 12pt (max(12, round(14 * 67 / nchar(title)))) so the title is always clearly dominant
  • Grid is rendered with INK_MUTED at full opacity on the dark background (#A8A79F on #1A1A17) giving slightly more contrast than ideal. Since ggplot2 cannot use alpha for grid lines, consider using a darker shade e.g. '#5A5A52' for the dark-theme grid color to reduce prominence

Issues Found

  1. VQ-01 MINOR: Title hierarchy: computed 11pt title vs 10pt axis labels leaves only 1pt difference — visual hierarchy between title and axis labels is tight. Fix: raise floor in max() from 8 to 12 and base from 12 to 14: .
  2. DE-01 AVERAGE: Design is clean and functional but the visual treatment is straightforward — a single-color ribbon without additional design interest. Consider adding a subtle amplitude-envelope overlay line or using slightly different styling for the pre-arrival noise section.

AI Feedback for Next Attempt

Raise the title font size floor: replace with so the title is always visually dominant over the 10pt axis labels. For a subtle design improvement, consider a slightly darker grid color in dark theme to reduce grid prominence. The seismic context, P/S annotations, and geom_ribbon technique are all excellent — keep them.

Verdict: APPROVED

@github-actions github-actions Bot added quality:89 Quality score 89/100 ai-approved Quality OK, ready for merge and removed quality:87 Quality score 87/100 labels Jun 3, 2026
@MarkusNeusinger MarkusNeusinger merged commit 19684c1 into main Jun 3, 2026
3 checks passed
@MarkusNeusinger MarkusNeusinger deleted the implementation/waveform-audio/ggplot2 branch June 3, 2026 01:37
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant