From 15b62cf8048ea2994616b7616b3811ff2ae25bb2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Jul 2026 10:31:26 +0000 Subject: [PATCH 1/2] feat(altair): implement waffle-basic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regen from quality 83. Addressed: - Title format (SC-04 failed → fixed): now uses the mandated `{spec-id} · {language} · {library} · anyplot.ai` format with the required language token, plus a data-driven subtitle for storytelling. - Design Excellence (DE-01/DE-03): added a subtitle calling out the largest allocation, and squared up the canvas (10x10 grid reads naturally as a symmetric square format rather than landscape). - Library Mastery (LM-02 failed → fixed): added a legend-bound `selection_point` that dims non-selected categories on click in the interactive HTML export — idiomatic altair, doesn't touch the default static PNG state. - Canvas contract: switched to square orientation (2400x2400) with the canonical altair inner-view sizing (430x430 @ scale_factor=4.0) plus the mandatory pad-to-target block; previous figsize (1600x900 @ scale_factor=3.0) was historical drift, off-target for the current hard-contract sizes. - Kept: 10x10 grid structure, budget-allocation data scenario, Imprint categorical order, theme-adaptive chrome, legend-with-percentages. Co-Authored-By: Claude Sonnet 5 --- .../implementations/python/altair.py | 76 +++++++++++++------ 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/plots/waffle-basic/implementations/python/altair.py b/plots/waffle-basic/implementations/python/altair.py index b070a06b44..7fdcf5df6f 100644 --- a/plots/waffle-basic/implementations/python/altair.py +++ b/plots/waffle-basic/implementations/python/altair.py @@ -1,13 +1,14 @@ -""" anyplot.ai +"""anyplot.ai waffle-basic: Basic Waffle Chart -Library: altair 6.1.0 | Python 3.13.13 -Quality: 83/100 | Updated: 2026-05-05 +Library: altair 6.2.2 | Python 3.13.14 +Quality: 83/100 | Updated: 2026-07-26 """ import os import sys import pandas as pd +from PIL import Image # Fix import conflict: import from parent directory to avoid local module shadowing @@ -26,7 +27,7 @@ INK = "#1A1A17" if THEME == "light" else "#F0EFE8" INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" -# Okabe-Ito palette (first series is #009E73) +# Imprint palette (first series is always #009E73) IMPRINT = ["#009E73", "#C475FD", "#4467A3", "#BD8233", "#AE3030"] # Data - Budget allocation with 5 categories including a small one @@ -36,19 +37,30 @@ # Build 10x10 grid (100 squares, each = 1%) squares = [] square_idx = 0 -for cat, val, color in zip(categories, values, IMPRINT, strict=True): +for cat, val in zip(categories, values, strict=True): for _ in range(val): row = square_idx // 10 col = square_idx % 10 - squares.append({"category": cat, "row": row, "col": col, "color": color}) + squares.append({"category": cat, "row": row, "col": col}) square_idx += 1 df = pd.DataFrame(squares) -# Create waffle chart +# Mandated title format, plus a data-driven subtitle for storytelling +title_text = "waffle-basic · python · altair · anyplot.ai" +subtitle_text = f"{categories[0]} commands {values[0]}% of the budget — the single largest allocation" +title_fontsize = max(11, round(16 * min(1.0, 67 / len(title_text)))) + +# Click a legend entry to isolate its share of the grid (idiomatic altair +# interactivity — dims the rest; only visible in the exported HTML, the +# static PNG keeps the default "nothing selected yet" full-opacity state). +legend_click = alt.selection_point(fields=["category"], bind="legend") + +label_map = ", ".join(f"'{cat}': '{val}'" for cat, val in zip(categories, values, strict=True)) + chart = ( alt.Chart(df) - .mark_rect(stroke="white", strokeWidth=2, cornerRadius=4) + .mark_rect(stroke=ELEVATED_BG, strokeWidth=3, cornerRadius=5) .encode( x=alt.X("col:O", axis=None), y=alt.Y("row:O", axis=None, sort="descending"), @@ -57,33 +69,51 @@ scale=alt.Scale(domain=categories, range=IMPRINT), legend=alt.Legend( title="Category", - titleFontSize=22, - labelFontSize=18, - symbolSize=300, + titleFontSize=14, + labelFontSize=12, + symbolSize=220, orient="right", - labelExpr="datum.label + ' (' + {" - + ", ".join([f"'{cat}': '{val}%'" for cat, val in zip(categories, values, strict=True)]) - + "}[datum.label] + ')'", + labelExpr=f"datum.label + ' (' + {{{label_map}}}[datum.label] + '%)'", ), ), - tooltip=["category:N"], + opacity=alt.condition(legend_click, alt.value(1.0), alt.value(0.25)), + tooltip=[alt.Tooltip("category:N", title="Category")], ) + .add_params(legend_click) .properties( - width=1600, - height=900, + width=430, + height=430, background=PAGE_BG, title=alt.Title( - "Budget Allocation · waffle-basic · altair · anyplot.ai", fontSize=28, anchor="middle", color=INK + title_text, + subtitle=subtitle_text, + fontSize=title_fontsize, + subtitleFontSize=round(title_fontsize * 0.55), + subtitleColor=INK_SOFT, + anchor="middle", + color=INK, ), ) - .configure_view(fill=PAGE_BG, stroke=INK_SOFT) - .configure_axis( - domainColor=INK_SOFT, tickColor=INK_SOFT, gridColor=INK, gridOpacity=0.10, labelColor=INK_SOFT, titleColor=INK - ) + .configure_view(fill=PAGE_BG, stroke=None) .configure_title(color=INK) .configure_legend(fillColor=ELEVATED_BG, strokeColor=INK_SOFT, labelColor=INK_SOFT, titleColor=INK) ) # Save outputs -chart.save(f"plot-{THEME}.png", scale_factor=3.0) +chart.save(f"plot-{THEME}.png", scale_factor=4.0) chart.save(f"plot-{THEME}.html") + +# PAD-only to the canonical square target (2400x2400) — never crop, cropping +# would clip the title/subtitle/legend and trigger the AR-09 edge-clip check. +TW, TH = 2400, 2400 +_img = Image.open(f"plot-{THEME}.png").convert("RGB") +_w, _h = _img.size +if _w > TW or _h > TH: + raise SystemExit( + f"altair vl-convert produced {_w}x{_h}, exceeds target {TW}x{TH}. " + f"Shrink chart .properties(width=, height=) values and re-render." + ) +if _w < TW or _h < TH: + _canvas = Image.new("RGB", (TW, TH), PAGE_BG) + _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2)) + _canvas.save(f"plot-{THEME}.png") From 5391e27148f24b550075a68146afbfba0d749b8c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Jul 2026 10:31:41 +0000 Subject: [PATCH 2/2] chore(altair): add metadata for waffle-basic --- .../waffle-basic/metadata/python/altair.yaml | 231 +----------------- 1 file changed, 11 insertions(+), 220 deletions(-) diff --git a/plots/waffle-basic/metadata/python/altair.yaml b/plots/waffle-basic/metadata/python/altair.yaml index 08ae46d19e..8a664544a7 100644 --- a/plots/waffle-basic/metadata/python/altair.yaml +++ b/plots/waffle-basic/metadata/python/altair.yaml @@ -1,230 +1,21 @@ +# Per-library metadata for altair implementation of waffle-basic +# Auto-generated by impl-generate.yml + library: altair language: python specification_id: waffle-basic created: '2025-12-24T09:49:39Z' -updated: '2026-05-05T18:13:59Z' -generated_by: claude-haiku -workflow_run: 25393338380 +updated: '2026-07-26T10:31:41Z' +generated_by: claude-sonnet +workflow_run: 30198249484 issue: 998 -python_version: 3.13.13 -library_version: 6.1.0 +language_version: 3.13.14 +library_version: 6.2.2 preview_url_light: https://storage.googleapis.com/anyplot-images/plots/waffle-basic/python/altair/plot-light.png preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/waffle-basic/python/altair/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/waffle-basic/python/altair/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/waffle-basic/python/altair/plot-dark.html -quality_score: 83 +quality_score: null review: - strengths: - - 'Perfect Visual Quality (29/30): Legible text with explicit sizing, no overlap, - all elements visible; flawless palette compliance and theme handling' - - 'Flawless Data Quality (15/15): Realistic, neutral budget allocation context with - correct proportions and full feature coverage' - - 'Clean Code (10/10): Simple structure, deterministic, proper output format' - - 'Proper Theme Adaptation: Both light and dark renders work perfectly; data colors - identical, only chrome adapts' - - 'Correct Waffle Implementation: 10x10 grid with proper proportions, clear square - definition via white borders' - weaknesses: - - 'Title Format (SC-04): Includes Budget Allocation prefix; should be just waffle-basic - · altair · anyplot.ai per spec requirement' - - 'Generic Design Excellence (10/20): Implementation is correct but lacks distinctive - aesthetic choices or visual sophistication' - - 'Limited Storytelling (DE-03): Displays data clearly but doesn''t create special - visual emphasis or hierarchy beyond the inherent proportional structure' - - 'No Distinctive Features (LM-02): Doesn''t use altair-specific techniques like - interactive selection or cross-filtering' - image_description: |- - Light render (plot-light.png): - Background: Warm off-white (#FAF8F1) - correct - Chrome: Title "Budget Allocation · waffle-basic · altair · anyplot.ai" visible in dark text; legend titled "Category" with category names and percentages; all text clearly readable - Data: Five categories shown as colored squares (100 total): Engineering green #009E73 (40 squares), Marketing orange #D55E00 (28), Operations blue #0072B2 (18), Design pink #CC79A7 (10), Legal yellow #E69F00 (4); white borders separate each square clearly; first series is correct #009E73 - Legibility verdict: PASS - All text readable against light background; no light-on-light issues; square borders provide excellent definition - - Dark render (plot-dark.png): - Background: Warm near-black (#1A1A17) - correct - Chrome: Title is light-colored; legend box has dark background with light text; all labels are light-colored; no dark-on-dark text failures - Data: Identical colors to light render - green #009E73, orange #D55E00, blue #0072B2, pink #CC79A7, yellow #E69F00 all present in same positions; white borders maintain visibility - Legibility verdict: PASS - All text clearly visible on dark background; brand green #009E73 clearly readable; no contrast failures; proper theme-adaptive chrome - criteria_checklist: - visual_quality: - score: 29 - max: 30 - items: - - id: VQ-01 - name: Text Legibility - score: 8 - max: 8 - passed: true - comment: All text explicitly sized and readable in both themes - - id: VQ-02 - name: No Overlap - score: 6 - max: 6 - passed: true - comment: Clean layout, legend positioned right, no text overlaps - - id: VQ-03 - name: Element Visibility - score: 6 - max: 6 - passed: true - comment: All 100 waffle squares clearly visible with white borders - - id: VQ-04 - name: Color Accessibility - score: 2 - max: 2 - passed: true - comment: Okabe-Ito palette is colorblind-safe with good contrast - - id: VQ-05 - name: Layout & Canvas - score: 4 - max: 4 - passed: true - comment: Perfect layout with balanced margins, plot fills 60-70% of canvas - - id: VQ-06 - name: Axis Labels & Title - score: 1 - max: 2 - passed: false - comment: Title present but format includes Budget Allocation when spec requires - waffle-basic format - - id: VQ-07 - name: Palette Compliance - score: 2 - max: 2 - passed: true - comment: 'First series is #009E73, colors follow Okabe-Ito order, backgrounds - and chrome are theme-correct' - design_excellence: - score: 10 - max: 20 - items: - - id: DE-01 - name: Aesthetic Sophistication - score: 4 - max: 8 - passed: false - comment: Well-configured defaults but lacks exceptional design or custom touches - - id: DE-02 - name: Visual Refinement - score: 4 - max: 6 - passed: true - comment: Good refinement with white borders, legend styling, generous margins - - id: DE-03 - name: Data Storytelling - score: 2 - max: 6 - passed: false - comment: Data displayed clearly but no special visual hierarchy or emphasis - spec_compliance: - score: 14 - max: 15 - items: - - id: SC-01 - name: Plot Type - score: 5 - max: 5 - passed: true - comment: Correct waffle chart with 10x10 grid - - id: SC-02 - name: Required Features - score: 4 - max: 4 - passed: true - comment: 'All features present: proportions, colors, legend with percentages' - - id: SC-03 - name: Data Mapping - score: 3 - max: 3 - passed: true - comment: Categories to colors, values to squares (100 total) - - id: SC-04 - name: Title & Legend - score: 2 - max: 3 - passed: false - comment: Legend correct but title format non-compliant - data_quality: - score: 15 - max: 15 - items: - - id: DQ-01 - name: Feature Coverage - score: 6 - max: 6 - passed: true - comment: 'Shows all aspects: proportions, categories, colors, value range' - - id: DQ-02 - name: Realistic Context - score: 5 - max: 5 - passed: true - comment: Budget allocation is real, realistic, neutral scenario - - id: DQ-03 - name: Appropriate Scale - score: 4 - max: 4 - passed: true - comment: Percentages sum to 100, factually correct proportions - code_quality: - score: 10 - max: 10 - items: - - id: CQ-01 - name: KISS Structure - score: 3 - max: 3 - passed: true - comment: Linear flow, no functions/classes, no over-engineering - - id: CQ-02 - name: Reproducibility - score: 2 - max: 2 - passed: true - comment: Fixed data, deterministic output - - id: CQ-03 - name: Clean Imports - score: 2 - max: 2 - passed: true - comment: Only necessary imports, all used - - id: CQ-04 - name: Code Elegance - score: 2 - max: 2 - passed: true - comment: Clean, Pythonic, no fake UI - - id: CQ-05 - name: Output & API - score: 1 - max: 1 - passed: true - comment: 'Correct naming: plot-{THEME}.png and .html' - library_mastery: - score: 5 - max: 10 - items: - - id: LM-01 - name: Idiomatic Usage - score: 4 - max: 5 - passed: true - comment: Good altair patterns with Chart.mark_rect(), proper encodings, theme-aware - config - - id: LM-02 - name: Distinctive Features - score: 1 - max: 5 - passed: false - comment: Uses basic features, doesn't leverage interactive or distinctive - altair capabilities - verdict: APPROVED -impl_tags: - dependencies: [] - techniques: - - custom-legend - patterns: - - data-generation - dataprep: [] - styling: - - publication-ready + strengths: [] + weaknesses: []