From fc16d45d41338102289eb65fd0d8e545c6de47dc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 03:34:18 +0000 Subject: [PATCH 1/5] feat(bokeh): implement piano-roll-midi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regen from quality 90. Addressed: - Fixed canvas to 3200×1800 (was 4800×2700) - Added ANYPLOT_THEME support (light/dark) with full theme-adaptive chrome - Replaced forbidden export_png + Turbo256 with Selenium screenshot + Imprint sequential palette - Fixed title format: piano-roll-midi · python · bokeh · anyplot.ai - Fixed output filenames: plot-{THEME}.png and plot-{THEME}.html - Added sys.path fix to prevent bokeh.py from shadowing the package - Added toolbar_location=None, correct min_border_* values, PIL crop for exact 3200×1800 - Velocity palette: blue (#4467A3) → red (#AE3030) sequential for note visibility in both themes --- .../implementations/python/bokeh.py | 246 ++++++++++++------ 1 file changed, 161 insertions(+), 85 deletions(-) diff --git a/plots/piano-roll-midi/implementations/python/bokeh.py b/plots/piano-roll-midi/implementations/python/bokeh.py index e3c13980ed..8e378306ba 100644 --- a/plots/piano-roll-midi/implementations/python/bokeh.py +++ b/plots/piano-roll-midi/implementations/python/bokeh.py @@ -1,63 +1,90 @@ -""" pyplots.ai +"""anyplot.ai piano-roll-midi: MIDI Piano Roll Visualization -Library: bokeh 3.8.2 | Python 3.14.3 -Quality: 90/100 | Created: 2026-03-07 +Library: bokeh | Python 3.13 +Quality: pending | Created: 2026-06-03 """ +import io +import os +import sys + + +# Prevent bokeh.py from shadowing the installed bokeh package +_this_dir = os.path.dirname(os.path.abspath(__file__)) +sys.path = [p for p in sys.path if os.path.realpath(p) != os.path.realpath(_this_dir)] + +import time +from pathlib import Path + import numpy as np -from bokeh.io import export_png, save +from bokeh.io import output_file, save from bokeh.models import ColorBar, ColumnDataSource, FixedTicker, HoverTool, LinearColorMapper, Range1d -from bokeh.palettes import Turbo256 from bokeh.plotting import figure -from bokeh.resources import Resources +from PIL import Image +from selenium import webdriver +from selenium.webdriver.chrome.options import Options + +# Theme tokens +THEME = os.getenv("ANYPLOT_THEME", "light") +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" +ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420" +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" +INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F" + + +# Imprint palette — sequential velocity colormap interpolator +def _lerp_hex(c0, c1, t): + r0, g0, b0 = (int(c0[i : i + 2], 16) for i in (1, 3, 5)) + r1, g1, b1 = (int(c1[i : i + 2], 16) for i in (1, 3, 5)) + r = int(round(r0 + (r1 - r0) * t)) + g = int(round(g0 + (g1 - g0) * t)) + b = int(round(b0 + (b1 - b0) * t)) + return f"#{r:02X}{g:02X}{b:02X}" + + +# Sequential blue→red: soft (low velocity) to loud (high velocity) +# Direct interpolation avoids near-background midpoint that would hide notes +VELOCITY_PALETTE = [_lerp_hex("#4467A3", "#AE3030", t / 255.0) for t in range(256)] # Data note_names_map = {0: "C", 1: "C#", 2: "D", 3: "D#", 4: "E", 5: "F", 6: "F#", 7: "G", 8: "G#", 9: "A", 10: "A#", 11: "B"} - black_key_indices = {1, 3, 6, 8, 10} - note_names = [f"{note_names_map[p % 12]}{p // 12 - 1}" for p in range(128)] black_keys = {p for p in range(128) if (p % 12) in black_key_indices} -# A short melody/chord progression (C major scale run + chords, ~8 measures) +# Musical phrase: C major scale runs + I-IV-V-I chord progression + melodic resolution notes = [] -# Measure 1-2: ascending C major scale (C4 to C5), gentle crescendo -scale_pitches = [60, 62, 64, 65, 67, 69, 71, 72] -for i, pitch in enumerate(scale_pitches): +# Measures 1-2: ascending C major scale with crescendo +for i, pitch in enumerate([60, 62, 64, 65, 67, 69, 71, 72]): notes.append({"start": i * 0.5, "duration": 0.45, "pitch": pitch, "velocity": 55 + i * 7}) -# Measure 3-4: descending with longer notes, decrescendo -desc_pitches = [72, 71, 69, 67, 65, 64, 62, 60] -for i, pitch in enumerate(desc_pitches): +# Measures 3-4: descending scale with decrescendo +for i, pitch in enumerate([72, 71, 69, 67, 65, 64, 62, 60]): notes.append({"start": 4.0 + i * 0.5, "duration": 0.45, "pitch": pitch, "velocity": 100 - i * 6}) -# Measure 5-6: block chords building to climax (I-IV-V-I progression) -chord_notes = [ - # I chord (C major) - moderate +# Measures 5-6: block chords building to fortissimo climax (I-IV-V-I) +for start, dur, pitch, vel in [ (8.0, 1.0, 60, 85), (8.0, 1.0, 64, 80), (8.0, 1.0, 67, 75), - # IV chord (F major) - building (9.0, 1.0, 65, 95), (9.0, 1.0, 69, 90), (9.0, 1.0, 72, 85), - # V chord (G major) - CLIMAX, fortissimo (10.0, 1.0, 67, 120), (10.0, 1.0, 71, 118), (10.0, 1.0, 74, 115), - # I chord (C major) - resolution, sustained (11.0, 2.0, 60, 100), (11.0, 2.0, 64, 95), (11.0, 2.0, 67, 90), (11.0, 2.0, 72, 85), -] -for start, dur, pitch, vel in chord_notes: +]: notes.append({"start": start, "duration": dur, "pitch": pitch, "velocity": vel}) -# Measure 7-8: melodic phrase with varied dynamics, resolving gently -melody = [ +# Measures 7-8: melodic phrase resolving gently +for start, dur, pitch, vel in [ (13.0, 0.5, 72, 95), (13.5, 0.25, 74, 80), (13.75, 0.25, 72, 75), @@ -65,8 +92,7 @@ (14.5, 0.5, 69, 80), (15.0, 1.0, 67, 65), (15.0, 1.0, 60, 60), -] -for start, dur, pitch, vel in melody: +]: notes.append({"start": start, "duration": dur, "pitch": pitch, "velocity": vel}) starts = np.array([n["start"] for n in notes]) @@ -74,30 +100,34 @@ pitches = np.array([n["pitch"] for n in notes]) velocities = np.array([n["velocity"] for n in notes]) -# Compute rectangle geometry (center-based) rect_x = starts + durations / 2 rect_y = pitches.astype(float) rect_w = durations -rect_h = np.full_like(durations, 0.8) +rect_h = np.full_like(durations, 0.82) -# Pitch range: tight fit to actual data pitch_min = int(pitches.min()) - 1 pitch_max = int(pitches.max()) + 1 -# Background rows for black/white key distinction -bg_pitches = list(range(pitch_min, pitch_max + 1)) -bg_x = [8.0] * len(bg_pitches) -bg_w = [18.0] * len(bg_pitches) -bg_h = [1.0] * len(bg_pitches) -bg_colors = ["#E8E8E8" if p in black_keys else "#F8F8F8" for p in bg_pitches] +# Background key shading — theme-adaptive alternating rows for piano keyboard layout +if THEME == "light": + white_key_color = "#FFFDF6" + black_key_color = "#E5E1D8" +else: + white_key_color = "#262521" + black_key_color = "#131310" +bg_pitches = list(range(pitch_min, pitch_max + 1)) bg_source = ColumnDataSource( - data={"x": bg_x, "y": [float(p) for p in bg_pitches], "w": bg_w, "h": bg_h, "color": bg_colors} + data={ + "x": [8.0] * len(bg_pitches), + "y": [float(p) for p in bg_pitches], + "w": [17.0] * len(bg_pitches), + "h": [1.0] * len(bg_pitches), + "color": [black_key_color if p in black_keys else white_key_color for p in bg_pitches], + } ) -# Perceptually-uniform Turbo palette for velocity mapping -turbo_subset = [Turbo256[i] for i in range(20, 240, 22)] -color_mapper = LinearColorMapper(palette=turbo_subset, low=40, high=127) +color_mapper = LinearColorMapper(palette=VELOCITY_PALETTE, low=40, high=127) note_source = ColumnDataSource( data={ @@ -113,28 +143,40 @@ } ) -# Plot +# Title (45 chars < 67 baseline — use default 50pt) +title = "piano-roll-midi · python · bokeh · anyplot.ai" + +# Plot — canvas 3200×1800, toolbar_location=None prevents extra height in PNG p = figure( - width=4800, - height=2700, - title="piano-roll-midi \u00b7 bokeh \u00b7 pyplots.ai", + width=3200, + height=1800, + title=title, x_axis_label="Time (beats)", - y_axis_label="Pitch (MIDI note)", + y_axis_label="Pitch", x_range=Range1d(-0.5, 16.5), y_range=Range1d(pitch_min - 0.5, pitch_max + 0.5), - tools="pan,wheel_zoom,box_zoom,reset,save", + toolbar_location=None, + min_border_bottom=160, + min_border_left=180, + min_border_top=110, + min_border_right=80, ) -# Background key shading +# Background piano key rows p.rect(x="x", y="y", width="w", height="h", source=bg_source, fill_color="color", line_color=None, level="underlay") -# Beat grid lines (light for beats, strong for measures) +# Custom beat/measure grid lines — measure boundaries stronger than beat lines for beat in range(17): - alpha = 0.4 if beat % 4 == 0 else 0.15 - width = 3 if beat % 4 == 0 else 1 - p.line([beat, beat], [pitch_min - 0.5, pitch_max + 0.5], line_color="#999999", line_alpha=alpha, line_width=width) + is_measure = beat % 4 == 0 + p.line( + [beat, beat], + [pitch_min - 0.5, pitch_max + 0.5], + line_color=INK_SOFT, + line_alpha=0.40 if is_measure else 0.12, + line_width=2.5 if is_measure else 1.0, + ) -# Note rectangles +# Note rectangles colored by velocity p.rect( x="x", y="y", @@ -142,25 +184,12 @@ height="h", source=note_source, fill_color={"field": "velocity", "transform": color_mapper}, - line_color="white", + line_color=PAGE_BG, line_width=2, line_alpha=0.9, ) -# Color bar for velocity legend (visible in static PNG) -color_bar = ColorBar( - color_mapper=color_mapper, - label_standoff=14, - width=28, - location=(0, 0), - title="Velocity", - title_text_font_size="18pt", - major_label_text_font_size="16pt", - ticker=FixedTicker(ticks=[40, 60, 80, 100, 120]), -) -p.add_layout(color_bar, "right") - -# Hover tool +# Hover tooltip for interactive HTML hover = HoverTool( tooltips=[ ("Note", "@note_name"), @@ -171,34 +200,81 @@ ) p.add_tools(hover) -# Style -p.title.text_font_size = "28pt" +# Velocity color bar +color_bar = ColorBar( + color_mapper=color_mapper, + label_standoff=14, + width=40, + location=(0, 0), + title="Velocity", + title_text_font_size="34pt", + title_text_color=INK, + major_label_text_font_size="28pt", + major_label_text_color=INK_SOFT, + ticker=FixedTicker(ticks=[40, 60, 80, 100, 120]), + background_fill_color=PAGE_BG, + border_line_color=None, +) +p.add_layout(color_bar, "right") + +# Style — text sizes per bokeh sizing guide +p.title.text_font_size = "50pt" p.title.text_font_style = "normal" -p.xaxis.axis_label_text_font_size = "22pt" -p.yaxis.axis_label_text_font_size = "22pt" -p.xaxis.major_label_text_font_size = "18pt" -p.yaxis.major_label_text_font_size = "18pt" +p.title.text_color = INK + +p.xaxis.axis_label_text_font_size = "42pt" +p.yaxis.axis_label_text_font_size = "42pt" +p.xaxis.axis_label_text_color = INK +p.yaxis.axis_label_text_color = INK -# Y-axis: show note names +p.xaxis.major_label_text_font_size = "34pt" +p.yaxis.major_label_text_font_size = "34pt" +p.xaxis.major_label_text_color = INK_SOFT +p.yaxis.major_label_text_color = INK_SOFT + +# Y-axis: note names instead of raw MIDI numbers y_ticks = list(range(pitch_min, pitch_max + 1)) p.yaxis.ticker = FixedTicker(ticks=y_ticks) p.yaxis.major_label_overrides = {p_val: note_names[p_val] for p_val in y_ticks} -# X-axis: show beat numbers +# X-axis: integer beat numbers p.xaxis.ticker = FixedTicker(ticks=list(range(17))) -# Remove default grids, clean spines +# Theme-adaptive chrome +p.background_fill_color = PAGE_BG +p.border_fill_color = PAGE_BG p.outline_line_color = None + +p.xaxis.axis_line_color = INK_SOFT +p.yaxis.axis_line_color = INK_SOFT +p.xaxis.major_tick_line_color = INK_SOFT +p.yaxis.major_tick_line_color = INK_SOFT + p.xgrid.grid_line_color = None p.ygrid.grid_line_color = None -p.background_fill_color = "#FFFFFF" -p.border_fill_color = "#FFFFFF" - -p.min_border_left = 120 -p.min_border_bottom = 80 -p.min_border_right = 120 +# Save interactive HTML artifact +output_file(f"plot-{THEME}.html") +save(p) -# Save -export_png(p, filename="plot.png") -save(p, filename="plot.html", title="piano-roll-midi", resources=Resources(mode="cdn")) +# Screenshot with headless Chrome — window is H+200 tall so bokeh canvas fills +# exactly W×H; PIL crops to the target rect before saving. +W, H = 3200, 1800 +opts = Options() +for arg in ( + "--headless=new", + "--no-sandbox", + "--disable-dev-shm-usage", + "--disable-gpu", + f"--window-size={W},{H + 200}", + "--hide-scrollbars", + "--force-device-scale-factor=1", +): + opts.add_argument(arg) +driver = webdriver.Chrome(options=opts) +driver.set_window_size(W, H + 200) +driver.get(f"file://{Path(f'plot-{THEME}.html').resolve()}") +time.sleep(3) +raw = driver.get_screenshot_as_png() +driver.quit() +Image.open(io.BytesIO(raw)).crop((0, 0, W, H)).save(f"plot-{THEME}.png") From a5e2b1e56f2747ce1b5e309e2bbd146671f178d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 03:34:33 +0000 Subject: [PATCH 2/5] chore(bokeh): add metadata for piano-roll-midi --- .../metadata/python/bokeh.yaml | 247 ++---------------- 1 file changed, 16 insertions(+), 231 deletions(-) diff --git a/plots/piano-roll-midi/metadata/python/bokeh.yaml b/plots/piano-roll-midi/metadata/python/bokeh.yaml index e5e4fd3a43..f81b617400 100644 --- a/plots/piano-roll-midi/metadata/python/bokeh.yaml +++ b/plots/piano-roll-midi/metadata/python/bokeh.yaml @@ -1,236 +1,21 @@ +# Per-library metadata for bokeh implementation of piano-roll-midi +# Auto-generated by impl-generate.yml + library: bokeh +language: python specification_id: piano-roll-midi created: '2026-03-07T19:47:49Z' -updated: '2026-03-07T19:59:46Z' -generated_by: claude-opus-4-5-20251101 -workflow_run: 22805912200 +updated: '2026-06-03T03:34:32Z' +generated_by: claude-sonnet +workflow_run: 26861695811 issue: 4565 -python_version: 3.14.3 -library_version: 3.8.2 -preview_url: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/bokeh/plot.png -preview_html: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/bokeh/plot.html -quality_score: 90 +language_version: 3.13.13 +library_version: 3.9.0 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/python/bokeh/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/python/bokeh/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/python/bokeh/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/python/bokeh/plot-dark.html +quality_score: null review: - strengths: - - 'Excellent domain-specific data: musically meaningful phrase with scale runs, - chord progression (I-IV-V-I), and dynamic variation that tells a clear musical - story' - - 'All spec features implemented: black/white key shading, beat/measure grid differentiation, - note names on y-axis, velocity color mapping, auto-fit pitch range' - - 'Good use of Bokeh-specific features: HoverTool, ColumnDataSource, ColorBar, level-based - rendering, HTML export' - - Clean visual design with custom grid lines, removed default chrome, and white - note borders for clarity - - Fully deterministic data with no randomness - weaknesses: - - Turbo colormap is not the most colorblind-accessible choice; viridis or cividis - would score higher on accessibility - - Manual grid line drawing via p.line loop is slightly non-idiomatic compared to - Bokeh grid styling options - image_description: The plot displays a MIDI piano roll visualization with horizontal - colored rectangles representing musical notes. The y-axis shows pitch names from - B3 to D#5, with alternating white and light gray background rows distinguishing - white keys from black keys on a piano. The x-axis shows time in beats from 0 to - 16. Notes are colored using a Turbo colormap ranging from blue (low velocity/soft) - through green and yellow to red (high velocity/loud). Vertical grid lines mark - beats, with thicker/darker lines at measure boundaries (beats 0, 4, 8, 12, 16). - A color bar on the right indicates the velocity scale from 40 to 120. The title - reads "piano-roll-midi · bokeh · pyplots.ai". The musical content shows an ascending - C major scale (measures 1-2), descending scale (measures 3-4), block chords building - to a red-colored climax at beat 10 (measures 5-6), and a resolving melodic phrase - (measures 7-8). White borders separate individual note rectangles clearly. - criteria_checklist: - visual_quality: - score: 29 - max: 30 - items: - - id: VQ-01 - name: Text Legibility - score: 8 - max: 8 - passed: true - comment: 'All font sizes explicitly set: title 28pt, axis labels 22pt, tick - labels 18pt, color bar title 18pt, color bar labels 16pt' - - id: VQ-02 - name: No Overlap - score: 6 - max: 6 - passed: true - comment: No overlapping text; y-axis note names well spaced, x-axis beat numbers - clear - - id: VQ-03 - name: Element Visibility - score: 6 - max: 6 - passed: true - comment: Note rectangles clearly visible with white borders, height 0.8 gives - good spacing - - id: VQ-04 - name: Color Accessibility - score: 3 - max: 4 - passed: true - comment: Turbo palette is perceptually more uniform than rainbow but not as - colorblind-safe as viridis/cividis - - id: VQ-05 - name: Layout & Canvas - score: 4 - max: 4 - passed: true - comment: Good canvas utilization, plot fills space well, color bar positioned - with adequate margins - - id: VQ-06 - name: Axis Labels & Title - score: 2 - max: 2 - passed: true - comment: Time (beats) and Pitch (MIDI note) descriptive with units - design_excellence: - score: 13 - max: 20 - items: - - id: DE-01 - name: Aesthetic Sophistication - score: 5 - max: 8 - passed: true - comment: Turbo palette vibrant and effective; white note borders, alternating - key shading, clean background; above defaults - - id: DE-02 - name: Visual Refinement - score: 4 - max: 6 - passed: true - comment: Default grids removed, custom beat/measure grid lines with differentiated - alpha/width, outline removed, generous margins - - id: DE-03 - name: Data Storytelling - score: 4 - max: 6 - passed: true - comment: Musical data tells a clear story with ascending crescendo, chord - climax, and gentle resolution - spec_compliance: - score: 15 - max: 15 - items: - - id: SC-01 - name: Plot Type - score: 5 - max: 5 - passed: true - comment: Correct piano roll with horizontal rectangles positioned by pitch - and time - - id: SC-02 - name: Required Features - score: 4 - max: 4 - passed: true - comment: 'All spec features: duration as bar length, velocity color, key shading, - grid lines, note names, auto-fit range' - - id: SC-03 - name: Data Mapping - score: 3 - max: 3 - passed: true - comment: X=time in beats, Y=pitch with note names, all data visible - - id: SC-04 - name: Title & Legend - score: 3 - max: 3 - passed: true - comment: Title format correct, ColorBar legend for velocity - data_quality: - score: 15 - max: 15 - items: - - id: DQ-01 - name: Feature Coverage - score: 6 - max: 6 - passed: true - comment: Shows varied durations (0.25-2.0 beats), velocities (55-120), scales, - chords, melodic passages - - id: DQ-02 - name: Realistic Context - score: 5 - max: 5 - passed: true - comment: Realistic C major musical phrase with scale runs, I-IV-V-I chord - progression, melodic resolution - - id: DQ-03 - name: Appropriate Scale - score: 4 - max: 4 - passed: true - comment: MIDI pitches C4-D5, velocities 55-120, 8 measures - all sensible - for musical context - code_quality: - score: 10 - max: 10 - items: - - id: CQ-01 - name: KISS Structure - score: 3 - max: 3 - passed: true - comment: Clean imports-data-plot-save structure, no functions/classes - - id: CQ-02 - name: Reproducibility - score: 2 - max: 2 - passed: true - comment: Fully deterministic hardcoded note data - - id: CQ-03 - name: Clean Imports - score: 2 - max: 2 - passed: true - comment: All imports used including save and Resources for HTML export - - id: CQ-04 - name: Code Elegance - score: 2 - max: 2 - passed: true - comment: Clean, appropriate complexity, no fake UI elements - - id: CQ-05 - name: Output & API - score: 1 - max: 1 - passed: true - comment: Saves as plot.png using current Bokeh API - library_mastery: - score: 8 - max: 10 - items: - - id: LM-01 - name: Idiomatic Usage - score: 4 - max: 5 - passed: true - comment: 'Good use of ColumnDataSource, figure, rect, LinearColorMapper, ColorBar, - FixedTicker; minor: manual grid lines via p.line loop' - - id: LM-02 - name: Distinctive Features - score: 4 - max: 5 - passed: true - comment: HoverTool with custom tooltips, HTML export, ColumnDataSource pattern, - level-based rendering - verdict: APPROVED -impl_tags: - dependencies: [] - techniques: - - colorbar - - hover-tooltips - - manual-ticks - - html-export - patterns: - - data-generation - - columndatasource - - iteration-over-groups - dataprep: [] - styling: - - custom-colormap - - edge-highlighting - - grid-styling + strengths: [] + weaknesses: [] From 1d812d8acb71a4b368c730c8dd7ea48535155357 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 03:41:29 +0000 Subject: [PATCH 3/5] chore(bokeh): update quality score 89 and review feedback for piano-roll-midi --- .../implementations/python/bokeh.py | 6 +- .../metadata/python/bokeh.yaml | 275 +++++++++++++++++- 2 files changed, 271 insertions(+), 10 deletions(-) diff --git a/plots/piano-roll-midi/implementations/python/bokeh.py b/plots/piano-roll-midi/implementations/python/bokeh.py index 8e378306ba..c2b3cd1473 100644 --- a/plots/piano-roll-midi/implementations/python/bokeh.py +++ b/plots/piano-roll-midi/implementations/python/bokeh.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai piano-roll-midi: MIDI Piano Roll Visualization -Library: bokeh | Python 3.13 -Quality: pending | Created: 2026-06-03 +Library: bokeh 3.9.0 | Python 3.13.13 +Quality: 89/100 | Updated: 2026-06-03 """ import io diff --git a/plots/piano-roll-midi/metadata/python/bokeh.yaml b/plots/piano-roll-midi/metadata/python/bokeh.yaml index f81b617400..304b23207f 100644 --- a/plots/piano-roll-midi/metadata/python/bokeh.yaml +++ b/plots/piano-roll-midi/metadata/python/bokeh.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for bokeh implementation of piano-roll-midi -# Auto-generated by impl-generate.yml - library: bokeh language: python specification_id: piano-roll-midi created: '2026-03-07T19:47:49Z' -updated: '2026-06-03T03:34:32Z' +updated: '2026-06-03T03:41:28Z' generated_by: claude-sonnet workflow_run: 26861695811 issue: 4565 @@ -15,7 +12,271 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/piano-rol preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/python/bokeh/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/python/bokeh/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/python/bokeh/plot-dark.html -quality_score: null +quality_score: 89 review: - strengths: [] - weaknesses: [] + strengths: + - Correct piano roll visualization with horizontal note rectangles colored by velocity + - Piano keyboard background rows (alternating white/black key shading) implemented + correctly and theme-adaptive + - Custom beat/measure grid differentiation (stronger lines at measure boundaries) + shows domain understanding + - Note names displayed on y-axis via major_label_overrides instead of raw MIDI numbers + - Interactive HTML artifact with HoverTool showing note name, start, duration, and + velocity + - 'Data covers realistic musical structure: ascending scale, descending scale, chord + progression (I-IV-V-I), and melodic resolution' + - Theme-adaptive chrome fully wired (INK, INK_SOFT tokens applied to all text and + axis elements) + - Canvas correctly sized at 3200x1800 with toolbar_location=None and min_border + reservations + weaknesses: + - 'Velocity colormap (blue #4467A3 → red #AE3030) uses Imprint palette endpoints + but is not the mandated imprint_seq (green→blue) or imprint_div (red↔blue diverging) + — use imprint_div reversed or imprint_seq for compliance; the custom direct interpolation + bypasses the style-guide mandate even though the spec suggests blue=soft/red=loud + semantics' + - 'DE-01 could be improved: typography has no weight variation or font hierarchy + beyond size differences; no distinction between title weight and axis label weight' + - _lerp_hex function defined at module level is a minor KISS violation (CQ-01) — + inline the 3-line interpolation at the one callsite or pre-compute inside the + palette list comprehension + image_description: |- + Light render (plot-light.png): + Background: Warm off-white (#FAF8F1) — correct. Piano keyboard rows alternate between near-white (#FFFDF6, white keys) and soft gray (#E5E1D8, black keys), clearly distinguishable. + Chrome: Title "piano-roll-midi · python · bokeh · anyplot.ai" in dark ink at ~60% plot width — readable. X-axis label "Time (beats)" and Y-axis label "Pitch" in dark ink, both clearly visible. Y-axis tick labels show note names B3 through D#5, X-axis shows beat numbers 0–16. Vertical beat grid lines are subtle; measure boundaries noticeably stronger. Colorbar on right labeled "Velocity" with ticks 40/60/80/100/120. + Data: Note rectangles span a blue (#4467A3) → red (#AE3030) gradient for velocity. Low-velocity notes (C4/D4 at beats 0–2) appear blue; climax chords (measures 10–12) appear vivid red. All data-color elements are clearly visible against both white-key and black-key row backgrounds. + Legibility verdict: PASS — all text is readable against the light background. No dark-on-dark issues. + + Dark render (plot-dark.png): + Background: Warm near-black (#1A1A17) — correct. Piano keyboard rows alternate between dark charcoal (#262521, white keys) and near-black (#131310, black keys); contrast is subtle but present. + Chrome: Title in near-white (#F0EFE8) text — clearly visible. Axis labels "Time (beats)" and "Pitch" in light text, readable. Y-axis tick labels (note names) and X-axis tick labels (beat numbers) in INK_SOFT (#B8B7B0) — adequately visible. Colorbar "Velocity" label and ticks in light colors — readable. + Data: Note rectangle colors are identical to the light render (same blue→red velocity gradient). Notes remain clearly visible against the dark row backgrounds. No dark-on-dark text failures detected. + Legibility verdict: PASS — all text is readable in the dark theme. Chrome correctly flips; data colors unchanged. + criteria_checklist: + visual_quality: + score: 28 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 8 + max: 8 + passed: true + comment: All font sizes explicitly set (50pt title, 42pt axis labels, 34pt + ticks, 34pt colorbar title, 28pt colorbar ticks). Proportions well-balanced + in both renders. No overflow detected. + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: 17 pitch rows with note labels fit without overlap. Beat tick labels + (0-16) have adequate spacing. No collisions. + - id: VQ-03 + name: Element Visibility + score: 6 + max: 6 + passed: true + comment: Note rectangles clearly visible. Height 0.82 per pitch row with slight + gap. Blue-to-red velocity gradient clearly distinguishable. Both renders + pass. + - id: VQ-04 + name: Color Accessibility + score: 1 + max: 2 + passed: false + comment: Blue-to-red gradient is generally legible but mid-range muted-purple + values may be harder to distinguish under some CVD conditions (not a mandated + Imprint cmap optimized for CVD). + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: Canvas 3200x1800, toolbar_location=None, min_border properly set. + Plot fills the canvas well. Colorbar placement is clean. No cutoff detected. + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: 'X-axis: ''Time (beats)'' with units. Y-axis: ''Pitch'' with note + names as tick labels providing unit context. Title format correct.' + - id: VQ-07 + name: Palette Compliance + score: 1 + max: 2 + passed: false + comment: 'Custom velocity colormap lerps between Imprint palette endpoints + (#4467A3 → #AE3030) but is not the mandated imprint_seq (green→blue) or + imprint_div (red↔neutral↔blue). Partial compliance: Imprint colors used + but mandated cmap not applied. Plot backgrounds correct (#FAF8F1 / #1A1A17). + Chrome is theme-correct.' + design_excellence: + score: 13 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: Domain-specific design choices (piano key shading, beat/measure grid + differentiation, velocity color gradient) elevate above defaults. Typography + uses size hierarchy but no weight variation. Sits between configured-default + (4) and strong-design (6). + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: Custom grid lines replace bokeh defaults, outline removed, axis line + colors themed. Color bar styled to match theme. Axis lines still present + but appropriate for a piano roll grid layout. + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: 'Musical arc is visible: blue low-velocity scale runs → crescendo + to red chord climax → resolution. Measure grid reinforces structure. No + section annotations but color hierarchy guides the viewer.' + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: 'Correct piano roll: horizontal rect per note, pitch on y-axis, time + on x-axis, width=duration.' + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Note names on y-axis via major_label_overrides, alternating piano + key row shading, beat and measure grid lines (differentiated), velocity + color scale (blue→red), pitch range auto-fit to data. + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: start→x center, duration→width, pitch→y, velocity→color. All axes + show all data. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title 'piano-roll-midi · python · bokeh · anyplot.ai' correct. Colorbar + labeled 'Velocity' with appropriate tick marks. + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: Shows scalar runs (short eighth-note durations), block chords (quarter-note+), + long sustains (half-note). Velocity range 55-120 spans soft to fortissimo. + Both white-key and black-key pitches present. + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: C major scale runs + I-IV-V-I chord progression + melodic resolution + — genuine musical content. Neutral, non-controversial. Real-world DAW scenario. + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: MIDI note numbers correct (C4=60, D4=62, etc.). Velocity 40-127 within + MIDI standard. Timing in beats (16 beats = 4 measures). Note durations realistic. + code_quality: + score: 9 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 2 + max: 3 + passed: false + comment: _lerp_hex function defined at module level is a minor KISS violation. + Otherwise follows imports→data→plot→save well. + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: All data is hardcoded — fully deterministic, no random seed needed. + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: 'All imports used: io, os, sys, time, Path, numpy, bokeh modules, + PIL, selenium.' + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Clean, Pythonic. No fake UI. HoverTool appropriate for Bokeh. Loop-based + data construction is clear. + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot-{THEME}.html and plot-{THEME}.png. Uses current Bokeh + API. + library_mastery: + score: 9 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 5 + max: 5 + passed: true + comment: ColumnDataSource for both bg and note layers, Range1d for axis ranges, + FixedTicker+major_label_overrides for note names, level='underlay' for background, + ColorBar+LinearColorMapper declarative pattern, HoverTool with template + — all idiomatic Bokeh. + - id: LM-02 + name: Distinctive Features + score: 4 + max: 5 + passed: true + comment: ColumnDataSource multi-layer rendering (underlay background + note + rects), HoverTool with custom tooltip templates, LinearColorMapper+ColorBar + declarative continuous color, FixedTicker+major_label_overrides for domain-specific + axis labels, HTML artifact with toolbar — leverages several Bokeh-specific + capabilities. + verdict: REJECTED +impl_tags: + dependencies: + - selenium + - pillow + techniques: + - colorbar + - manual-ticks + - hover-tooltips + - html-export + patterns: + - data-generation + - columndatasource + - iteration-over-groups + dataprep: [] + styling: + - custom-colormap + - alpha-blending + - edge-highlighting From fd6c3d91a3bcff0758dfdb7b47b093db2b579516 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 03:45:14 +0000 Subject: [PATCH 4/5] fix(bokeh): address review feedback for piano-roll-midi Attempt 1/3 - fixes based on AI review --- .../implementations/python/bokeh.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/plots/piano-roll-midi/implementations/python/bokeh.py b/plots/piano-roll-midi/implementations/python/bokeh.py index c2b3cd1473..eb9b61ed44 100644 --- a/plots/piano-roll-midi/implementations/python/bokeh.py +++ b/plots/piano-roll-midi/implementations/python/bokeh.py @@ -1,4 +1,4 @@ -""" anyplot.ai +"""anyplot.ai piano-roll-midi: MIDI Piano Roll Visualization Library: bokeh 3.9.0 | Python 3.13.13 Quality: 89/100 | Updated: 2026-06-03 @@ -34,19 +34,10 @@ INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F" -# Imprint palette — sequential velocity colormap interpolator -def _lerp_hex(c0, c1, t): - r0, g0, b0 = (int(c0[i : i + 2], 16) for i in (1, 3, 5)) - r1, g1, b1 = (int(c1[i : i + 2], 16) for i in (1, 3, 5)) - r = int(round(r0 + (r1 - r0) * t)) - g = int(round(g0 + (g1 - g0) * t)) - b = int(round(b0 + (b1 - b0) * t)) - return f"#{r:02X}{g:02X}{b:02X}" - - -# Sequential blue→red: soft (low velocity) to loud (high velocity) -# Direct interpolation avoids near-background midpoint that would hide notes -VELOCITY_PALETTE = [_lerp_hex("#4467A3", "#AE3030", t / 255.0) for t in range(256)] +# imprint_seq: brand green (#009E73) → blue (#4467A3) — 256-stop pre-computed inline +VELOCITY_PALETTE = [ + f"#{round(68 * t / 255):02X}{round(158 - 55 * t / 255):02X}{round(115 + 48 * t / 255):02X}" for t in range(256) +] # Data note_names_map = {0: "C", 1: "C#", 2: "D", 3: "D#", 4: "E", 5: "F", 6: "F#", 7: "G", 8: "G#", 9: "A", 10: "A#", 11: "B"} From d34ac7992c506739c1bb2a9fd46dde349b83d74f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 03:51:15 +0000 Subject: [PATCH 5/5] chore(bokeh): update quality score 91 and review feedback for piano-roll-midi --- .../implementations/python/bokeh.py | 4 +- .../metadata/python/bokeh.yaml | 203 ++++++++---------- 2 files changed, 94 insertions(+), 113 deletions(-) diff --git a/plots/piano-roll-midi/implementations/python/bokeh.py b/plots/piano-roll-midi/implementations/python/bokeh.py index eb9b61ed44..257537fa85 100644 --- a/plots/piano-roll-midi/implementations/python/bokeh.py +++ b/plots/piano-roll-midi/implementations/python/bokeh.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai piano-roll-midi: MIDI Piano Roll Visualization Library: bokeh 3.9.0 | Python 3.13.13 -Quality: 89/100 | Updated: 2026-06-03 +Quality: 91/100 | Updated: 2026-06-03 """ import io diff --git a/plots/piano-roll-midi/metadata/python/bokeh.yaml b/plots/piano-roll-midi/metadata/python/bokeh.yaml index 304b23207f..9722ad9626 100644 --- a/plots/piano-roll-midi/metadata/python/bokeh.yaml +++ b/plots/piano-roll-midi/metadata/python/bokeh.yaml @@ -2,7 +2,7 @@ library: bokeh language: python specification_id: piano-roll-midi created: '2026-03-07T19:47:49Z' -updated: '2026-06-03T03:41:28Z' +updated: '2026-06-03T03:51:14Z' generated_by: claude-sonnet workflow_run: 26861695811 issue: 4565 @@ -12,49 +12,40 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/piano-rol preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/python/bokeh/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/python/bokeh/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/piano-roll-midi/python/bokeh/plot-dark.html -quality_score: 89 +quality_score: 91 review: strengths: - - Correct piano roll visualization with horizontal note rectangles colored by velocity - - Piano keyboard background rows (alternating white/black key shading) implemented - correctly and theme-adaptive - - Custom beat/measure grid differentiation (stronger lines at measure boundaries) - shows domain understanding - - Note names displayed on y-axis via major_label_overrides instead of raw MIDI numbers - - Interactive HTML artifact with HoverTool showing note name, start, duration, and - velocity - - 'Data covers realistic musical structure: ascending scale, descending scale, chord - progression (I-IV-V-I), and melodic resolution' - - Theme-adaptive chrome fully wired (INK, INK_SOFT tokens applied to all text and - axis elements) - - Canvas correctly sized at 3200x1800 with toolbar_location=None and min_border - reservations + - Correct imprint_seq colormap (green→blue) for velocity mapping + - 'All spec requirements met: note names on y-axis, alternating piano key shading, + differentiated beat/measure grid lines, color bar' + - 'Excellent bokeh feature utilization: ColorBar, HoverTool, FixedTicker, major_label_overrides, + ColumnDataSource with level=underlay' + - Both themes correctly adapted with appropriate tokens throughout + - Musical phrase is rich and domain-authentic (C major scales + I-IV-V-I chords + + resolution) weaknesses: - - 'Velocity colormap (blue #4467A3 → red #AE3030) uses Imprint palette endpoints - but is not the mandated imprint_seq (green→blue) or imprint_div (red↔blue diverging) - — use imprint_div reversed or imprint_seq for compliance; the custom direct interpolation - bypasses the style-guide mandate even though the spec suggests blue=soft/red=loud - semantics' - - 'DE-01 could be improved: typography has no weight variation or font hierarchy - beyond size differences; no distinction between title weight and axis label weight' - - _lerp_hex function defined at module level is a minor KISS violation (CQ-01) — - inline the 3-line interpolation at the one callsite or pre-compute inside the - palette list comprehension + - 'DE-01 moderate: piano roll design is professional but relies on standard DAW + conventions without standout visual innovation beyond the spec requirements' + - 'DE-02 partially met: custom grid lines are a nice touch, but removing more default + chrome (e.g. axis tick marks) would improve refinement' + - 'DE-03 limited: musical narrative arc is present in the data but the visualization + provides no annotations or focal emphasis to guide the viewer to notice the crescendo→climax→resolution + story' image_description: |- Light render (plot-light.png): - Background: Warm off-white (#FAF8F1) — correct. Piano keyboard rows alternate between near-white (#FFFDF6, white keys) and soft gray (#E5E1D8, black keys), clearly distinguishable. - Chrome: Title "piano-roll-midi · python · bokeh · anyplot.ai" in dark ink at ~60% plot width — readable. X-axis label "Time (beats)" and Y-axis label "Pitch" in dark ink, both clearly visible. Y-axis tick labels show note names B3 through D#5, X-axis shows beat numbers 0–16. Vertical beat grid lines are subtle; measure boundaries noticeably stronger. Colorbar on right labeled "Velocity" with ticks 40/60/80/100/120. - Data: Note rectangles span a blue (#4467A3) → red (#AE3030) gradient for velocity. Low-velocity notes (C4/D4 at beats 0–2) appear blue; climax chords (measures 10–12) appear vivid red. All data-color elements are clearly visible against both white-key and black-key row backgrounds. - Legibility verdict: PASS — all text is readable against the light background. No dark-on-dark issues. + Background: Warm off-white (#FAF8F1) — correct light surface, not pure white. + Chrome: Title "piano-roll-midi · python · bokeh · anyplot.ai" in dark ink, clearly readable. X-axis label "Time (beats)" and Y-axis label "Pitch" in dark ink, proportional 42pt sizing. Tick labels for note names (B3–D#5) and beat numbers (0–16) in INK_SOFT, fully readable at 34pt. Color bar labeled "Velocity" with tick values 40–120 readable. Alternating background row shading distinguishes black/white piano keys (very light cream vs. slightly darker grey-cream). + Data: Note rectangles colored via imprint_seq (#009E73 → #4467A3). Soft notes are teal-green, loud notes are blue. Custom grid lines at every beat (subtle 12% opacity) with stronger lines at measures 0,4,8,12,16 (40% opacity). All note rectangles clearly visible. + Legibility verdict: PASS — all text elements fully readable against the warm off-white surface. Dark render (plot-dark.png): - Background: Warm near-black (#1A1A17) — correct. Piano keyboard rows alternate between dark charcoal (#262521, white keys) and near-black (#131310, black keys); contrast is subtle but present. - Chrome: Title in near-white (#F0EFE8) text — clearly visible. Axis labels "Time (beats)" and "Pitch" in light text, readable. Y-axis tick labels (note names) and X-axis tick labels (beat numbers) in INK_SOFT (#B8B7B0) — adequately visible. Colorbar "Velocity" label and ticks in light colors — readable. - Data: Note rectangle colors are identical to the light render (same blue→red velocity gradient). Notes remain clearly visible against the dark row backgrounds. No dark-on-dark text failures detected. - Legibility verdict: PASS — all text is readable in the dark theme. Chrome correctly flips; data colors unchanged. + Background: Warm near-black (#1A1A17) — correct dark surface, not pure black. + Chrome: Title, axis labels, and tick labels all rendered in light text (#F0EFE8 / #B8B7B0 tokens) — clearly readable against the dark background. No dark-on-dark failures detected. Alternating row shading is subtly visible (near-black vs. slightly lighter dark rows). Color bar with light-text labels readable. + Data: Note rectangle colors are identical to the light render (same teal-green to blue gradient from imprint_seq). Data color invariance confirmed. Custom grid lines visible. + Legibility verdict: PASS — all text elements fully readable against the warm near-black surface; no dark-on-dark issues. criteria_checklist: visual_quality: - score: 28 + score: 30 max: 30 items: - id: VQ-01 @@ -63,57 +54,53 @@ review: max: 8 passed: true comment: All font sizes explicitly set (50pt title, 42pt axis labels, 34pt - ticks, 34pt colorbar title, 28pt colorbar ticks). Proportions well-balanced - in both renders. No overflow detected. + tick labels). All text readable at full size in both light and dark themes. + No legibility failures. - id: VQ-02 name: No Overlap score: 6 max: 6 passed: true - comment: 17 pitch rows with note labels fit without overlap. Beat tick labels - (0-16) have adequate spacing. No collisions. + comment: No text or element overlaps. Note rectangles have 0.18 gap (height=0.82), + chords are on separate pitch rows. Clean layout throughout. - id: VQ-03 name: Element Visibility score: 6 max: 6 passed: true - comment: Note rectangles clearly visible. Height 0.82 per pitch row with slight - gap. Blue-to-red velocity gradient clearly distinguishable. Both renders - pass. + comment: Note rectangles are clearly visible with appropriate size. Velocity + gradient clearly distinguishes dynamic range. Color bar legible. - id: VQ-04 name: Color Accessibility - score: 1 + score: 2 max: 2 - passed: false - comment: Blue-to-red gradient is generally legible but mid-range muted-purple - values may be harder to distinguish under some CVD conditions (not a mandated - Imprint cmap optimized for CVD). + passed: true + comment: imprint_seq (green→blue) is CVD-safe. No red-green sole-signal encoding. - id: VQ-05 name: Layout & Canvas score: 4 max: 4 passed: true - comment: Canvas 3200x1800, toolbar_location=None, min_border properly set. - Plot fills the canvas well. Colorbar placement is clean. No cutoff detected. + comment: Canvas 3200×1800. min_border values (bottom=160, left=180, top=110, + right=80) correctly reserve space for large text. Canvas gate passed. Color + bar well-positioned. - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: 'X-axis: ''Time (beats)'' with units. Y-axis: ''Pitch'' with note - names as tick labels providing unit context. Title format correct.' + comment: 'X: ''Time (beats)'', Y: ''Pitch'', Title correct format. Units present + where needed.' - id: VQ-07 name: Palette Compliance - score: 1 + score: 2 max: 2 - passed: false - comment: 'Custom velocity colormap lerps between Imprint palette endpoints - (#4467A3 → #AE3030) but is not the mandated imprint_seq (green→blue) or - imprint_div (red↔neutral↔blue). Partial compliance: Imprint colors used - but mandated cmap not applied. Plot backgrounds correct (#FAF8F1 / #1A1A17). - Chrome is theme-correct.' + passed: true + comment: 'VELOCITY_PALETTE correctly interpolates #009E73→#4467A3 (imprint_seq). + Backgrounds #FAF8F1 (light) / #1A1A17 (dark). Data colors identical across + both renders.' design_excellence: - score: 13 + score: 12 max: 20 items: - id: DE-01 @@ -121,26 +108,25 @@ review: score: 5 max: 8 passed: true - comment: Domain-specific design choices (piano key shading, beat/measure grid - differentiation, velocity color gradient) elevate above defaults. Typography - uses size hierarchy but no weight variation. Sits between configured-default - (4) and strong-design (6). + comment: Professional piano roll design with domain-appropriate alternating + row shading. Intentional velocity-color hierarchy. Custom grid differentiating + beats from measures. Solid but not visually inventive beyond the spec conventions. - id: DE-02 name: Visual Refinement score: 4 max: 6 passed: true - comment: Custom grid lines replace bokeh defaults, outline removed, axis line - colors themed. Color bar styled to match theme. Axis lines still present - but appropriate for a piano roll grid layout. + comment: Custom manual grid lines replace bokeh default grid. outline_line_color=None + removes frame. Alternating background rows are subtle and don't compete + with data. Could further refine by removing tick marks. - id: DE-03 name: Data Storytelling - score: 4 + score: 3 max: 6 passed: true - comment: 'Musical arc is visible: blue low-velocity scale runs → crescendo - to red chord climax → resolution. Measure grid reinforces structure. No - section annotations but color hierarchy guides the viewer.' + comment: Musical narrative arc (crescendo→climax→resolution) is encoded in + velocity colors, but no annotations or focal emphasis guide the viewer to + the story. Data storytelling is implicit rather than intentional. spec_compliance: score: 15 max: 15 @@ -150,30 +136,30 @@ review: score: 5 max: 5 passed: true - comment: 'Correct piano roll: horizontal rect per note, pitch on y-axis, time - on x-axis, width=duration.' + comment: 'Correct piano roll: horizontal rectangles by pitch (y) and time + (x), width=duration, color=velocity.' - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Note names on y-axis via major_label_overrides, alternating piano - key row shading, beat and measure grid lines (differentiated), velocity - color scale (blue→red), pitch range auto-fit to data. + comment: Note names on y-axis (major_label_overrides), alternating row shading + for black/white keys, beat/measure grid lines with differentiated strength, + sequential velocity colormap. - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: start→x center, duration→width, pitch→y, velocity→color. All axes - show all data. + comment: X=time in beats, Y=pitch as note names, color=velocity, width=duration. + Auto-fit range with 1-note margin. - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: Title 'piano-roll-midi · python · bokeh · anyplot.ai' correct. Colorbar - labeled 'Velocity' with appropriate tick marks. + comment: 'Title: ''piano-roll-midi · python · bokeh · anyplot.ai'' correct. + ColorBar labeled ''Velocity'' with correct tick marks.' data_quality: score: 15 max: 15 @@ -183,61 +169,59 @@ review: score: 6 max: 6 passed: true - comment: Shows scalar runs (short eighth-note durations), block chords (quarter-note+), - long sustains (half-note). Velocity range 55-120 spans soft to fortissimo. - Both white-key and black-key pitches present. + comment: Covers scalar melody (ascending/descending runs), polyphony (block + chords), varying durations (eighth notes to whole notes), full velocity + range (55-127), 8 measures. - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: C major scale runs + I-IV-V-I chord progression + melodic resolution - — genuine musical content. Neutral, non-controversial. Real-world DAW scenario. + comment: C major phrase with I-IV-V-I progression. Velocities in realistic + MIDI range. Note lengths (0.25-2.0 beats) are musically standard. Neutral, + non-controversial content. - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: MIDI note numbers correct (C4=60, D4=62, etc.). Velocity 40-127 within - MIDI standard. Timing in beats (16 beats = 4 measures). Note durations realistic. + comment: Pitch range B3-D5 auto-fits data with 1-note margin. Time range 0-16 + beats. Velocity colormap low=40 high=127 spans realistic MIDI range. code_quality: - score: 9 + score: 10 max: 10 items: - id: CQ-01 name: KISS Structure - score: 2 + score: 3 max: 3 - passed: false - comment: _lerp_hex function defined at module level is a minor KISS violation. - Otherwise follows imports→data→plot→save well. + passed: true + comment: No functions or classes. Flat, readable script structure. - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: All data is hardcoded — fully deterministic, no random seed needed. + comment: Fully deterministic — all notes hardcoded, no random state. - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: 'All imports used: io, os, sys, time, Path, numpy, bokeh modules, - PIL, selenium.' + comment: All imports used. No unused imports. - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: Clean, Pythonic. No fake UI. HoverTool appropriate for Bokeh. Loop-based - data construction is clear. + comment: No fake UI. Appropriate complexity. Inline VELOCITY_PALETTE computation + is clean. - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves plot-{THEME}.html and plot-{THEME}.png. Uses current Bokeh - API. + comment: Saves plot-{THEME}.png and plot-{THEME}.html. Correct API. library_mastery: score: 9 max: 10 @@ -247,36 +231,33 @@ review: score: 5 max: 5 passed: true - comment: ColumnDataSource for both bg and note layers, Range1d for axis ranges, - FixedTicker+major_label_overrides for note names, level='underlay' for background, - ColorBar+LinearColorMapper declarative pattern, HoverTool with template - — all idiomatic Bokeh. + comment: ColumnDataSource, LinearColorMapper, ColorBar, HoverTool, FixedTicker, + major_label_overrides, level='underlay' for background rects, toolbar_location=None. + Fully idiomatic. - id: LM-02 name: Distinctive Features score: 4 max: 5 passed: true - comment: ColumnDataSource multi-layer rendering (underlay background + note - rects), HoverTool with custom tooltip templates, LinearColorMapper+ColorBar - declarative continuous color, FixedTicker+major_label_overrides for domain-specific - axis labels, HTML artifact with toolbar — leverages several Bokeh-specific - capabilities. - verdict: REJECTED + comment: 'Strong use of bokeh-specific features: level=''underlay'' for background + rects, major_label_overrides for note name y-axis, LinearColorMapper+ColorBar + for velocity, HoverTool with format strings, interactive HTML output. Missing + advanced transforms or server-side callbacks.' + verdict: APPROVED impl_tags: dependencies: - selenium - pillow techniques: - colorbar - - manual-ticks - hover-tooltips - html-export + - manual-ticks patterns: - data-generation - columndatasource - - iteration-over-groups dataprep: [] styling: - custom-colormap - - alpha-blending - edge-highlighting + - grid-styling