Skip to content

Commit 6efb24c

Browse files
feat(pygal): implement sunburst-basic (#5683)
## Implementation: `sunburst-basic` - python/pygal Implements the **python/pygal** version of `sunburst-basic`. **File:** `plots/sunburst-basic/implementations/python/pygal.py` **Parent Issue:** #821 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25347406390)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
1 parent 3fc0ae8 commit 6efb24c

2 files changed

Lines changed: 314 additions & 0 deletions

File tree

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
""" anyplot.ai
2+
sunburst-basic: Basic Sunburst Chart
3+
Library: pygal 3.1.0 | Python 3.13.13
4+
Quality: 73/100 | Created: 2026-05-04
5+
"""
6+
7+
import os
8+
9+
import pygal
10+
from pygal.style import Style
11+
12+
13+
THEME = os.getenv("ANYPLOT_THEME", "light")
14+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
15+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
16+
INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F"
17+
18+
OKABE_ITO = ("#009E73", "#D55E00", "#0072B2", "#CC79A7", "#E69F00", "#56B4E9", "#F0E442")
19+
20+
custom_style = Style(
21+
background=PAGE_BG,
22+
plot_background=PAGE_BG,
23+
foreground=INK,
24+
foreground_strong=INK,
25+
foreground_subtle=INK_MUTED,
26+
colors=OKABE_ITO,
27+
title_font_size=72,
28+
label_font_size=40,
29+
major_label_font_size=36,
30+
legend_font_size=40,
31+
value_font_size=32,
32+
stroke_width=2,
33+
)
34+
35+
# Organizational budget breakdown (in $K)
36+
# Each department: (name, primary_color, [(team, team_color, value), ...])
37+
# Team colors are shades of their parent department color
38+
departments = [
39+
(
40+
"Technology",
41+
"#009E73",
42+
[
43+
("Backend Engineering", "#009E73", 180),
44+
("Frontend Engineering", "#40B88E", 140),
45+
("Data Science", "#7DD3AB", 100),
46+
],
47+
),
48+
("Business", "#D55E00", [("Sales", "#D55E00", 150), ("Finance", "#E07D33", 100), ("Legal", "#EB9C66", 60)]),
49+
("Operations", "#0072B2", [("IT Support", "#0072B2", 90), ("Human Resources", "#3396C8", 80)]),
50+
("Marketing", "#CC79A7", [("Brand Design", "#CC79A7", 60), ("Digital Marketing", "#D99ABD", 40)]),
51+
]
52+
53+
# pygal.Pie with multiple series creates concentric rings — a sunburst chart
54+
# inner_radius=0.4 creates a donut; first series = inner ring (departments)
55+
chart = pygal.Pie(
56+
style=custom_style,
57+
width=3600,
58+
height=3600,
59+
title="sunburst-basic · pygal · anyplot.ai",
60+
inner_radius=0.4,
61+
show_legend=True,
62+
legend_at_bottom=True,
63+
legend_at_bottom_columns=4,
64+
print_values=False,
65+
)
66+
67+
# Inner ring: department totals — each slice color matches the department
68+
chart.add(
69+
"Departments",
70+
[{"value": sum(v for _, _, v in teams), "label": name, "color": color} for name, color, teams in departments],
71+
)
72+
73+
# Outer ring: individual teams — shades of their parent department color
74+
chart.add(
75+
"Teams",
76+
[{"value": value, "label": name, "color": color} for _, _, teams in departments for name, color, value in teams],
77+
)
78+
79+
chart.render_to_png(f"plot-{THEME}.png")
80+
with open(f"plot-{THEME}.html", "wb") as f:
81+
f.write(chart.render())
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
library: pygal
2+
language: python
3+
specification_id: sunburst-basic
4+
created: '2026-05-04T22:56:10Z'
5+
updated: '2026-05-04T23:52:15Z'
6+
generated_by: claude-sonnet
7+
workflow_run: 25347406390
8+
issue: 821
9+
python_version: 3.13.13
10+
library_version: 3.1.0
11+
preview_url_light: https://storage.googleapis.com/anyplot-images/plots/sunburst-basic/python/pygal/plot-light.png
12+
preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/sunburst-basic/python/pygal/plot-dark.png
13+
preview_html_light: https://storage.googleapis.com/anyplot-images/plots/sunburst-basic/python/pygal/plot-light.html
14+
preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/sunburst-basic/python/pygal/plot-dark.html
15+
quality_score: 73
16+
review:
17+
strengths:
18+
- Correct sunburst simulation using pygal multi-series Pie API
19+
- Color-shading hierarchy connects team segments visually to parent departments
20+
- Proper theme-adaptive chrome with correct backgrounds and foreground tokens for
21+
both themes
22+
- Deterministic flat code with clean imports and list comprehensions
23+
- HTML interactive output provides hover labels and full interactivity
24+
weaknesses:
25+
- No segment labels visible in static PNG render — major segments should be labeled
26+
even in static output
27+
- Legend declared but not rendered in PNG export by cairosvg — remove or accept
28+
HTML-only legend
29+
- Only 2 hierarchy levels used; a 3rd tier would better showcase the spec range
30+
of 2-4 levels
31+
image_description: |-
32+
Light render (plot-light.png):
33+
Background: warm off-white #FAF8F1 — correct
34+
Chrome: title "sunburst-basic · pygal · anyplot.ai" in dark text, clearly readable at top; no segment labels or tick labels present
35+
Data: inner ring shows 4 department slices in Okabe-Ito #009E73 (green/Technology), #D55E00 (orange-vermillion/Business), #0072B2 (blue/Operations), #CC79A7 (pink-purple/Marketing); outer ring shows shaded tint variants of each parent color for team segments; no legend visible in PNG
36+
Legibility verdict: PASS (title readable; segment labels absent but not a legibility failure for text that exists)
37+
38+
Dark render (plot-dark.png):
39+
Background: near-black #1A1A17 — correct
40+
Chrome: title in light text, clearly legible against dark background; no dark-on-dark failures detected
41+
Data: same segment positions and proportions as light render; Okabe-Ito hues consistent between themes (only chrome flips); legend again absent in PNG
42+
Legibility verdict: PASS
43+
criteria_checklist:
44+
visual_quality:
45+
score: 24
46+
max: 30
47+
items:
48+
- id: VQ-01
49+
name: Text Legibility
50+
score: 4
51+
max: 8
52+
passed: false
53+
comment: Title readable in both themes but no segment labels visible in static
54+
PNG render
55+
- id: VQ-02
56+
name: No Overlap
57+
score: 6
58+
max: 6
59+
passed: true
60+
comment: Clean ring layout, no overlapping elements
61+
- id: VQ-03
62+
name: Element Visibility
63+
score: 5
64+
max: 6
65+
passed: true
66+
comment: All ring segments clearly visible and distinctly colored; minor deduction
67+
for absent labels
68+
- id: VQ-04
69+
name: Color Accessibility
70+
score: 2
71+
max: 2
72+
passed: true
73+
comment: Okabe-Ito palette; CVD-safe
74+
- id: VQ-05
75+
name: Layout & Canvas
76+
score: 3
77+
max: 4
78+
passed: true
79+
comment: Good canvas fill; legend declared but absent in static render
80+
- id: VQ-06
81+
name: Axis Labels & Title
82+
score: 2
83+
max: 2
84+
passed: true
85+
comment: Correct title format; no axis labels needed for sunburst
86+
- id: VQ-07
87+
name: Palette Compliance
88+
score: 2
89+
max: 2
90+
passed: true
91+
comment: 'Light #FAF8F1 and dark #1A1A17 backgrounds correct; first series
92+
#009E73; Okabe-Ito order 1-4'
93+
design_excellence:
94+
score: 8
95+
max: 20
96+
items:
97+
- id: DE-01
98+
name: Aesthetic Sophistication
99+
score: 4
100+
max: 8
101+
passed: false
102+
comment: Color-shading hierarchy is intentional but overall design uses default
103+
pygal styling
104+
- id: DE-02
105+
name: Visual Refinement
106+
score: 2
107+
max: 6
108+
passed: false
109+
comment: Pie chart type leaves little room for spine removal; minimal chrome
110+
customization
111+
- id: DE-03
112+
name: Data Storytelling
113+
score: 2
114+
max: 6
115+
passed: false
116+
comment: Two-ring structure conveys hierarchy but no focal point or narrative
117+
emphasis
118+
spec_compliance:
119+
score: 11
120+
max: 15
121+
items:
122+
- id: SC-01
123+
name: Plot Type
124+
score: 4
125+
max: 5
126+
passed: true
127+
comment: pygal.Pie multi-series correctly simulates sunburst; not native but
128+
idiomatic pygal approach
129+
- id: SC-02
130+
name: Required Features
131+
score: 2
132+
max: 4
133+
passed: false
134+
comment: Branch colors consistent, ring separation clear, inner segments encompass
135+
children; major segment labels missing from static PNG
136+
- id: SC-03
137+
name: Data Mapping
138+
score: 3
139+
max: 3
140+
passed: true
141+
comment: Department totals in inner ring, teams in outer ring; proportional
142+
to values
143+
- id: SC-04
144+
name: Title & Legend
145+
score: 2
146+
max: 3
147+
passed: true
148+
comment: Title format correct; legend declared but absent from static PNG
149+
render
150+
data_quality:
151+
score: 13
152+
max: 15
153+
items:
154+
- id: DQ-01
155+
name: Feature Coverage
156+
score: 4
157+
max: 6
158+
passed: true
159+
comment: 2 hierarchy levels demonstrated; spec allows 2-4; a 3rd tier would
160+
earn full marks
161+
- id: DQ-02
162+
name: Realistic Context
163+
score: 5
164+
max: 5
165+
passed: true
166+
comment: Organizational budget breakdown is realistic, plausible, and neutral
167+
- id: DQ-03
168+
name: Appropriate Scale
169+
score: 4
170+
max: 4
171+
passed: true
172+
comment: Values 40-180 $K are sensible for team-level budgets
173+
code_quality:
174+
score: 10
175+
max: 10
176+
items:
177+
- id: CQ-01
178+
name: KISS Structure
179+
score: 3
180+
max: 3
181+
passed: true
182+
comment: Flat linear script, no functions or classes
183+
- id: CQ-02
184+
name: Reproducibility
185+
score: 2
186+
max: 2
187+
passed: true
188+
comment: Fully deterministic; no random elements
189+
- id: CQ-03
190+
name: Clean Imports
191+
score: 2
192+
max: 2
193+
passed: true
194+
comment: Only os, pygal, pygal.style.Style imported and used
195+
- id: CQ-04
196+
name: Code Elegance
197+
score: 2
198+
max: 2
199+
passed: true
200+
comment: List comprehensions for data series are concise and readable
201+
- id: CQ-05
202+
name: Output & API
203+
score: 1
204+
max: 1
205+
passed: true
206+
comment: Saves plot-{THEME}.png and plot-{THEME}.html; correct pygal pattern
207+
library_mastery:
208+
score: 7
209+
max: 10
210+
items:
211+
- id: LM-01
212+
name: Idiomatic Usage
213+
score: 4
214+
max: 5
215+
passed: true
216+
comment: Multi-series pygal.Pie for concentric rings is idiomatic; Style object
217+
properly carries all theme tokens
218+
- id: LM-02
219+
name: Distinctive Features
220+
score: 3
221+
max: 5
222+
passed: true
223+
comment: Uses pygal HTML interactive output for labeling; leverages per-datum
224+
color overrides via dict format
225+
verdict: APPROVED
226+
impl_tags:
227+
dependencies: []
228+
techniques:
229+
- html-export
230+
patterns:
231+
- iteration-over-groups
232+
dataprep: []
233+
styling: []

0 commit comments

Comments
 (0)