Skip to content

Commit 309acb5

Browse files
feat(pygal): implement box-grouped (#5995)
## Implementation: `box-grouped` - python/pygal Implements the **python/pygal** version of `box-grouped`. **File:** `plots/box-grouped/implementations/python/pygal.py` **Parent Issue:** #2017 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25535051660)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 5bcab3e commit 309acb5

2 files changed

Lines changed: 262 additions & 40 deletions

File tree

plots/box-grouped/implementations/python/pygal.py

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
box-grouped: Grouped Box Plot
3-
Library: pygal 3.1.0 | Python 3.13.11
4-
Quality: 85/100 | Created: 2025-12-25
3+
Library: pygal 3.1.0 | Python 3.13.13
4+
Quality: 85/100 | Updated: 2026-05-08
55
"""
66

7+
import os
8+
79
import numpy as np
810
import pygal
911
from pygal.style import Style
1012

1113

14+
THEME = os.getenv("ANYPLOT_THEME", "light")
15+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
16+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
17+
INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F"
18+
19+
OKABE_ITO = ("#009E73", "#D55E00", "#0072B2", "#CC79A7", "#E69F00", "#56B4E9", "#F0E442")
20+
1221
# Data - Employee performance scores across departments and experience levels
1322
np.random.seed(42)
1423

@@ -37,36 +46,34 @@
3746
data[("Sales", "Senior")] = np.append(data[("Sales", "Senior")], [40, 105])
3847
data[("Marketing", "Lead")] = np.append(data[("Marketing", "Lead")], [60, 100])
3948

40-
# Subcategory colors (colorblind-safe: blue, orange, teal)
41-
subcategory_colors = ("#306998", "#E69F00", "#009E73")
49+
# Subcategory colors: use Okabe-Ito palette starting with brand green
50+
subcategory_colors = OKABE_ITO[:3]
4251

4352
# Build full color tuple: repeat pattern for each department group
4453
all_colors = subcategory_colors * len(departments)
4554

46-
# Custom style for large canvas with increased font sizes
4755
custom_style = Style(
48-
background="white",
49-
plot_background="white",
50-
foreground="#333333",
51-
foreground_strong="#333333",
52-
foreground_subtle="#666666",
56+
background=PAGE_BG,
57+
plot_background=PAGE_BG,
58+
foreground=INK,
59+
foreground_strong=INK,
60+
foreground_subtle=INK_MUTED,
5361
colors=all_colors,
54-
title_font_size=72,
55-
label_font_size=44,
56-
major_label_font_size=40,
57-
legend_font_size=48,
58-
value_font_size=32,
62+
title_font_size=28,
63+
label_font_size=22,
64+
major_label_font_size=18,
65+
legend_font_size=16,
66+
value_font_size=14,
5967
opacity=0.85,
6068
opacity_hover=1.0,
6169
)
6270

6371
# Create box chart with legend showing only 3 experience levels
64-
# Set y-axis range to focus on actual data range (35-110)
6572
chart = pygal.Box(
6673
width=4800,
6774
height=2700,
6875
style=custom_style,
69-
title="box-grouped · pygal · pyplots.ai",
76+
title="box-grouped · pygal · anyplot.ai",
7077
x_title="Department",
7178
y_title="Performance Score",
7279
show_legend=True,
@@ -79,8 +86,10 @@
7986
margin=80,
8087
box_mode="tukey",
8188
x_label_rotation=0,
89+
yrange=(35, 110),
8290
range=(35, 110),
8391
y_labels=[40, 50, 60, 70, 80, 90, 100, 110],
92+
dots_size=8,
8493
)
8594

8695
# Track which experience levels have been labeled in legend
@@ -103,5 +112,5 @@
103112
chart.x_labels = x_labels
104113

105114
# Save outputs
106-
chart.render_to_file("plot.html")
107-
chart.render_to_png("plot.png")
115+
chart.render_to_file(f"plot-{THEME}.html")
116+
chart.render_to_png(f"plot-{THEME}.png")

plots/box-grouped/metadata/python/pygal.yaml

Lines changed: 233 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,245 @@
11
library: pygal
2+
language: python
23
specification_id: box-grouped
34
created: '2025-12-25T19:57:08Z'
4-
updated: '2025-12-25T20:27:17Z'
5-
generated_by: claude-opus-4-5-20251101
6-
workflow_run: 20510142994
5+
updated: '2026-05-08T03:42:31Z'
6+
generated_by: claude-haiku
7+
workflow_run: 25535051660
78
issue: 2017
8-
python_version: 3.13.11
9+
python_version: 3.13.13
910
library_version: 3.1.0
10-
preview_url: https://storage.googleapis.com/anyplot-images/plots/box-grouped/pygal/plot.png
11-
preview_html: https://storage.googleapis.com/anyplot-images/plots/box-grouped/pygal/plot.html
11+
preview_url_light: https://storage.googleapis.com/anyplot-images/plots/box-grouped/python/pygal/plot-light.png
12+
preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/box-grouped/python/pygal/plot-dark.png
13+
preview_html_light: https://storage.googleapis.com/anyplot-images/plots/box-grouped/python/pygal/plot-light.html
14+
preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/box-grouped/python/pygal/plot-dark.html
1215
quality_score: 85
16+
review:
17+
strengths:
18+
- Perfect text legibility in both light and dark themes with explicit font sizing
19+
- Flawless palette compliance - first series is brand green (#009E73), Okabe-Ito
20+
colors in correct order, theme-adaptive chrome perfect
21+
- Excellent spec compliance - grouped box plot correctly shows side-by-side boxes
22+
with distinct colors and legend
23+
- Realistic, neutral data scenario (employee performance by department and level)
24+
with authentic distributions and outliers
25+
- Clean, reproducible code with proper seed, KISS structure, and correct pygal API
26+
usage
27+
weaknesses:
28+
- Design could be more sophisticated - well-configured defaults but lacks visual
29+
distinctiveness or intentional hierarchy
30+
- Visual refinement could be improved - top and right spines remain; could be removed
31+
for cleaner aesthetic
32+
- No visual storytelling - plot displays data without emphasis on insights (e.g.,
33+
which department/level combinations excel)
34+
image_description: |-
35+
Light render (plot-light.png):
36+
Background: Warm off-white (#FAF8F1) with subtle top border
37+
Chrome: Title "box-grouped · pygal · anyplot.ai" at top center, axis labels "Department" (X) and "Performance Score" (Y) clearly visible, tick labels readable, subtle horizontal grid lines
38+
Data: 9 grouped box plots (3 departments × 3 experience levels) with green (#009E73, Junior), orange (#D55E00, Senior), and blue (#0072B2, Lead) boxes. Whiskers extend to 1.5×IQR, outliers shown as dots. Box widths consistent across groups.
39+
Legend: Bottom-center, three entries showing Junior/Senior/Lead with corresponding colors
40+
Legibility verdict: PASS - All text readable, colors distinct, plot well-balanced on canvas
41+
42+
Dark render (plot-dark.png):
43+
Background: Warm near-black (#1A1A17) with subtle top border
44+
Chrome: Title visible in light color, axis labels readable, tick labels all readable in light color against dark background (no dark-on-dark failures), subtle horizontal grid lines
45+
Data: Identical to light render - same 9 grouped boxes with green, orange, blue colors. Whiskers and outliers clearly visible against dark background. Box colors are identical to light render (only chrome flipped).
46+
Legend: Bottom-center, same three entries
47+
Legibility verdict: PASS - All text readable, no dark-on-dark failures, data colors identical to light render, excellent theme adaptation
48+
criteria_checklist:
49+
visual_quality:
50+
score: 30
51+
max: 30
52+
items:
53+
- id: VQ-01
54+
name: Text Legibility
55+
score: 8
56+
max: 8
57+
passed: true
58+
comment: All font sizes explicitly set (title 28px, labels 22px, major labels
59+
18px, legend 16px), perfectly readable in both themes
60+
- id: VQ-02
61+
name: No Overlap
62+
score: 6
63+
max: 6
64+
passed: true
65+
comment: No overlapping text, department labels centered using clever x_labels
66+
positioning, all elements readable
67+
- id: VQ-03
68+
name: Element Visibility
69+
score: 6
70+
max: 6
71+
passed: true
72+
comment: 9 box plots clearly visible with optimized sizing for moderate data
73+
density, whiskers and outliers well visible
74+
- id: VQ-04
75+
name: Color Accessibility
76+
score: 2
77+
max: 2
78+
passed: true
79+
comment: Okabe-Ito colors 1-3 (green, orange, blue) are colorblind-safe, excellent
80+
contrast between boxes and backgrounds
81+
- id: VQ-05
82+
name: Layout & Canvas
83+
score: 4
84+
max: 4
85+
passed: true
86+
comment: Plot fills 60-70% of canvas with generous 80px margins, well-balanced
87+
layout, legend positioned appropriately
88+
- id: VQ-06
89+
name: Axis Labels & Title
90+
score: 2
91+
max: 2
92+
passed: true
93+
comment: 'Descriptive labels: ''Department'' (X), ''Performance Score'' (Y),
94+
with appropriate title format'
95+
- id: VQ-07
96+
name: Palette Compliance
97+
score: 2
98+
max: 2
99+
passed: true
100+
comment: 'First series #009E73 (brand green), multi-series follows Okabe-Ito
101+
order, backgrounds #FAF8F1 (light) and #1A1A17 (dark), theme chrome perfect
102+
in both renders'
103+
design_excellence:
104+
score: 8
105+
max: 20
106+
items:
107+
- id: DE-01
108+
name: Aesthetic Sophistication
109+
score: 4
110+
max: 8
111+
passed: false
112+
comment: Well-configured library defaults with custom Style and Okabe-Ito
113+
palette, professional but generic - no exceptional design thought
114+
- id: DE-02
115+
name: Visual Refinement
116+
score: 2
117+
max: 6
118+
passed: false
119+
comment: Minimal customization - Y-grid shown (appropriate) but all four spines
120+
remain (could remove top/right for cleaner look)
121+
- id: DE-03
122+
name: Data Storytelling
123+
score: 2
124+
max: 6
125+
passed: false
126+
comment: Plot displays distributions across departments and levels clearly,
127+
but lacks visual emphasis or hierarchy to highlight insights
128+
spec_compliance:
129+
score: 15
130+
max: 15
131+
items:
132+
- id: SC-01
133+
name: Plot Type
134+
score: 5
135+
max: 5
136+
passed: true
137+
comment: Perfect grouped box plot implementation with side-by-side boxes
138+
- id: SC-02
139+
name: Required Features
140+
score: 4
141+
max: 4
142+
passed: true
143+
comment: 'All features present: boxes side-by-side, distinct colors, clear
144+
legend, consistent widths, box/whiskers/outliers'
145+
- id: SC-03
146+
name: Data Mapping
147+
score: 3
148+
max: 3
149+
passed: true
150+
comment: X-axis departments, Y-axis performance scores, subcategories as grouped
151+
boxes
152+
- id: SC-04
153+
name: Title & Legend
154+
score: 3
155+
max: 3
156+
passed: true
157+
comment: Title 'box-grouped · pygal · anyplot.ai' correct, legend labels accurate
158+
(Junior/Senior/Lead)
159+
data_quality:
160+
score: 15
161+
max: 15
162+
items:
163+
- id: DQ-01
164+
name: Feature Coverage
165+
score: 6
166+
max: 6
167+
passed: true
168+
comment: 'All aspects shown: tight distributions (Engineering) and wide distributions
169+
(Sales), experience progression, outliers in multiple groups'
170+
- id: DQ-02
171+
name: Realistic Context
172+
score: 5
173+
max: 5
174+
passed: true
175+
comment: Employee performance by department/level - authentic business scenario,
176+
neutral, realistic patterns (seniority correlation)
177+
- id: DQ-03
178+
name: Appropriate Scale
179+
score: 4
180+
max: 4
181+
passed: true
182+
comment: Performance range 35-110 (realistic for performance score), distributions
183+
logically follow experience levels
184+
code_quality:
185+
score: 10
186+
max: 10
187+
items:
188+
- id: CQ-01
189+
name: KISS Structure
190+
score: 3
191+
max: 3
192+
passed: true
193+
comment: 'Simple linear flow: imports → constants → data → chart → save, no
194+
functions/classes'
195+
- id: CQ-02
196+
name: Reproducibility
197+
score: 2
198+
max: 2
199+
passed: true
200+
comment: np.random.seed(42) set, deterministic data generation
201+
- id: CQ-03
202+
name: Clean Imports
203+
score: 2
204+
max: 2
205+
passed: true
206+
comment: 'Only used imports: os, numpy, pygal, Style'
207+
- id: CQ-04
208+
name: Code Elegance
209+
score: 2
210+
max: 2
211+
passed: true
212+
comment: Appropriate complexity, no over-engineering, no fake functionality
213+
- id: CQ-05
214+
name: Output & API
215+
score: 1
216+
max: 1
217+
passed: true
218+
comment: 'Correct output: plot-{THEME}.html and plot-{THEME}.png'
219+
library_mastery:
220+
score: 7
221+
max: 10
222+
items:
223+
- id: LM-01
224+
name: Idiomatic Usage
225+
score: 4
226+
max: 5
227+
passed: true
228+
comment: Proper use of pygal.Box(), Style customization, chart.add(), legend
229+
management. Fairly standard high-level API usage.
230+
- id: LM-02
231+
name: Distinctive Features
232+
score: 3
233+
max: 5
234+
passed: true
235+
comment: Uses Style for theme adaptation and custom legend tracking (showing
236+
each level only once) - somewhat distinctive but still within standard practices
237+
verdict: APPROVED
13238
impl_tags:
14239
dependencies: []
15240
techniques: []
16241
patterns:
17-
- data-generation
242+
- data-generation
243+
- iteration-over-groups
18244
dataprep: []
19245
styling: []
20-
review:
21-
strengths:
22-
- Colorblind-safe color palette (blue, orange, teal) provides excellent accessibility
23-
- Clean legend placement at bottom with 3 columns showing experience levels clearly
24-
- Realistic employee performance data context with meaningful variation between
25-
groups
26-
- Proper use of box_mode=tukey for standard box plot whisker calculation
27-
- Well-structured code following KISS principles with fixed random seed
28-
weaknesses:
29-
- Y-axis renders from 0 despite range=(35, 110) setting, creating excessive whitespace
30-
below the data
31-
- Outlier markers are very small dots that are difficult to see clearly
32-
- Grid lines are somewhat prominent and could be more subtle for better visual balance

0 commit comments

Comments
 (0)