Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 36 additions & 31 deletions plots/waffle-basic/implementations/python/plotnine.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" anyplot.ai
"""anyplot.ai
waffle-basic: Basic Waffle Chart
Library: plotnine 0.15.4 | Python 3.13.13
Quality: 79/100 | Created: 2026-05-05
Expand All @@ -14,7 +14,6 @@
from plotnine import (
aes,
coord_equal,
element_blank,
element_rect,
element_text,
geom_tile,
Expand All @@ -24,7 +23,7 @@
labs,
scale_fill_manual,
theme,
theme_minimal,
theme_void,
)


Expand All @@ -33,19 +32,24 @@
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 — 8 hues, theme-independent, hybrid-v3 sort
IMPRINT = ["#009E73", "#C475FD", "#4467A3", "#BD8233"]

# Data - Budget allocation by category
# Data — a $5,000 monthly household budget, allocated by category.
# Values sum to exactly 100 (one waffle square = 1% = $50).
categories = ["Housing", "Food", "Transport", "Entertainment"]
values = [35, 25, 18, 12]
category_order = categories
values = [39, 28, 20, 13]
monthly_budget = 5000
amounts = [round(v / 100 * monthly_budget) for v in values]
assert sum(values) == 100

# Create waffle grid (10x10 = 100 squares)
# Waffle grid: 10x10 = 100 squares, filled row-major so each category
# forms a contiguous reading-order block.
grid_size = 10
squares = []
square_id = 0

for val, cat in zip(values, categories, strict=True):
for _ in range(val):
row = square_id // grid_size
Expand All @@ -54,41 +58,42 @@
square_id += 1

df = pd.DataFrame(squares)
df["category"] = pd.Categorical(df["category"], categories=category_order, ordered=True)
df["category"] = pd.Categorical(df["category"], categories=categories, ordered=True)

# Create color mapping with Okabe-Ito palette
color_map = dict(zip(category_order, IMPRINT, strict=True))
color_map = dict(zip(categories, IMPRINT, strict=True))
value_map = dict(zip(categories, values, strict=True))
amount_map = dict(zip(categories, amounts, strict=True))
legend_labels = {cat: f"{cat} — {value_map[cat]}% (${amount_map[cat]:,})" for cat in categories}

# Build legend labels with percentages
legend_labels = {cat: f"{cat} ({value_map[cat]}%)" for cat in category_order}

# Theme configuration
anyplot_theme = theme(
figure_size=(16, 9),
figure_size=(6, 6),
plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
plot_title=element_text(size=24, color=INK, ha="center"),
legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),
legend_title=element_text(size=18, color=INK),
legend_text=element_text(size=16, color=INK_SOFT),
legend_position="right",
axis_text=element_blank(),
axis_title=element_blank(),
axis_ticks=element_blank(),
panel_grid=element_blank(),
plot_title=element_text(size=20, weight="bold", color=INK, ha="center"),
plot_subtitle=element_text(size=12, color=INK_SOFT, ha="center", style="italic"),
plot_caption=element_text(size=9, color=INK_MUTED, ha="center"),
legend_position="bottom",
legend_direction="horizontal",
legend_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
legend_key=element_rect(fill=PAGE_BG, color=PAGE_BG),
legend_title=element_text(size=14, weight="bold", color=INK),
legend_text=element_text(size=12, color=INK_SOFT),
)

# Plot
plot = (
ggplot(df, aes(x="x", y="y", fill="category"))
+ geom_tile(color=PAGE_BG, size=0.8)
+ scale_fill_manual(values=color_map, labels=lambda x: [legend_labels[c] for c in x])
+ geom_tile(color=PAGE_BG, size=1.4)
+ scale_fill_manual(values=color_map, labels=lambda cats: [legend_labels[c] for c in cats])
+ coord_equal()
+ labs(title="waffle-basic · plotnine · anyplot.ai", fill="Category")
+ labs(
title="waffle-basic · plotnine · anyplot.ai",
subtitle=f"Monthly Household Budget Allocation — ${monthly_budget:,} Total",
caption="Each square represents 1% of the total monthly budget",
fill="Category",
)
+ guides(fill=guide_legend(ncol=1))
+ theme_minimal()
+ theme_void()
+ anyplot_theme
)

plot.save(f"plot-{THEME}.png", dpi=300, verbose=False)
plot.save(f"plot-{THEME}.png", dpi=400, width=6, height=6, units="in", verbose=False)
222 changes: 11 additions & 211 deletions plots/waffle-basic/metadata/python/plotnine.yaml
Original file line number Diff line number Diff line change
@@ -1,221 +1,21 @@
# Per-library metadata for plotnine implementation of waffle-basic
# Auto-generated by impl-generate.yml

library: plotnine
language: python
specification_id: waffle-basic
created: 2025-12-16 07:44:55+00:00
updated: '2026-05-05T18:25:01Z'
generated_by: claude-haiku
workflow_run: 25393441505
updated: '2026-07-26T10:32:50Z'
generated_by: claude-sonnet
workflow_run: 30198308403
issue: 998
python_version: 3.13.13
library_version: 0.15.4
language_version: 3.13.14
library_version: 0.15.7
preview_url_light: https://storage.googleapis.com/anyplot-images/plots/waffle-basic/python/plotnine/plot-light.png
preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/waffle-basic/python/plotnine/plot-dark.png
preview_html_light: null
preview_html_dark: null
quality_score: 79
quality_score: null
review:
strengths:
- Perfect theme adaptation with correct light/dark backgrounds and text colors
- Proper Okabe-Ito palette with brand green as first series
- All text legible and explicitly sized for large canvas
- Clean waffle grid implementation with clear proportional squares
- Correct title format and legend with percentages
- No theme-chrome failures in either render
weaknesses:
- Data values sum to 90 instead of 100 — creates ~10% proportional gap
- Generic design relying on library defaults with minimal visual refinement
- No visual hierarchy or storytelling — data displayed factually without emphasis
- Legend styling is minimal; could leverage plotnine theme features for sophistication
- Typography could be more intentional beyond minimum readable sizes
image_description: |-
Light render (plot-light.png):
Background: Warm off-white (#FAF8F1) — correct theme surface
Chrome: Title centered in dark text (#1A1A17), legend on right with dark labels (#4A4A44) — all clearly readable
Data: 10×9 waffle grid with Housing (green #009E73, 35 squares), Food (vermillion #D55E00, 25), Transport (blue #0072B2, 18), Entertainment (purple #CC79A7, 12); white grid dividers separate squares cleanly
Legibility verdict: PASS — all elements readable, no contrast failures

Dark render (plot-dark.png):
Background: Warm near-black (#1A1A17) — correct dark surface
Chrome: Title in light text (#F0EFE8), legend labels in secondary light (#B8B7B0) — all clearly readable; dark grid dividers visible against surface
Data: Identical colors to light render (#009E73, #D55E00, #0072B2, #CC79A7 unchanged); brand green remains vivid against dark background
Legibility verdict: PASS — no dark-on-dark failures, all text light-colored and readable
criteria_checklist:
visual_quality:
score: 29
max: 30
items:
- id: VQ-01
name: Text Legibility
score: 7
max: 8
passed: true
comment: Explicit sizing (title 24pt, legend 16pt), all readable but typography
could be more refined
- id: VQ-02
name: No Overlap
score: 6
max: 6
passed: true
comment: Zero overlap, all elements fully legible
- id: VQ-03
name: Element Visibility
score: 6
max: 6
passed: true
comment: Squares properly sized and distinct
- id: VQ-04
name: Color Accessibility
score: 2
max: 2
passed: true
comment: Okabe-Ito palette is CVD-safe with excellent contrast
- id: VQ-05
name: Layout & Canvas
score: 4
max: 4
passed: true
comment: Plot fills 50-60% of canvas with balanced margins
- id: VQ-06
name: Axis Labels & Title
score: 2
max: 2
passed: true
comment: Descriptive title in correct format
- id: VQ-07
name: Palette Compliance
score: 2
max: 2
passed: true
comment: 'First series #009E73, colors follow Okabe-Ito order, backgrounds
correct in both themes'
design_excellence:
score: 8
max: 20
items:
- id: DE-01
name: Aesthetic Sophistication
score: 4
max: 8
passed: false
comment: Well-configured defaults but no distinctive visual innovation
- id: DE-02
name: Visual Refinement
score: 2
max: 6
passed: false
comment: Grid styling functional but minimal; legend styling default
- id: DE-03
name: Data Storytelling
score: 2
max: 6
passed: false
comment: Displays data without 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 10×9 waffle chart
- id: SC-02
name: Required Features
score: 3
max: 4
passed: false
comment: Grid and legend present; values sum to 90 instead of 100
- id: SC-03
name: Data Mapping
score: 3
max: 3
passed: true
comment: Categories correctly mapped to grid
- id: SC-04
name: Title & Legend
score: 3
max: 3
passed: true
comment: Correct format with percentages
data_quality:
score: 13
max: 15
items:
- id: DQ-01
name: Feature Coverage
score: 5
max: 6
passed: true
comment: Shows four distinct categories
- id: DQ-02
name: Realistic Context
score: 5
max: 5
passed: true
comment: Budget allocation is realistic and neutral
- id: DQ-03
name: Appropriate Scale
score: 3
max: 4
passed: false
comment: Values reasonable but sum to 90% not 100%
code_quality:
score: 10
max: 10
items:
- id: CQ-01
name: KISS Structure
score: 3
max: 3
passed: true
comment: Linear structure with clear flow
- id: CQ-02
name: Reproducibility
score: 2
max: 2
passed: true
comment: Deterministic hardcoded data
- id: CQ-03
name: Clean Imports
score: 2
max: 2
passed: true
comment: Only necessary plotnine imports
- id: CQ-04
name: Code Elegance
score: 2
max: 2
passed: true
comment: Clean and Pythonic
- id: CQ-05
name: Output & API
score: 1
max: 1
passed: true
comment: Correct plot-{THEME}.png format
library_mastery:
score: 5
max: 10
items:
- id: LM-01
name: Idiomatic Usage
score: 4
max: 5
passed: true
comment: Correct ggplot + geom_tile pattern
- id: LM-02
name: Distinctive Features
score: 1
max: 5
passed: false
comment: Generic grammar-of-graphics usage; doesn't leverage distinctive plotnine
features
verdict: APPROVED
impl_tags:
dependencies: []
techniques: []
patterns:
- data-generation
dataprep: []
styling: []
strengths: []
weaknesses: []