Skip to content

Commit 18dd0f4

Browse files
feat(matplotlib): implement pie-drilldown (#3124)
## Implementation: `pie-drilldown` - matplotlib Implements the **matplotlib** version of `pie-drilldown`. **File:** `plots/pie-drilldown/implementations/matplotlib.py` **Parent Issue:** #3072 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20620468775)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 44cd36c commit 18dd0f4

2 files changed

Lines changed: 236 additions & 0 deletions

File tree

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
""" pyplots.ai
2+
pie-drilldown: Drilldown Pie Chart with Click Navigation
3+
Library: matplotlib 3.10.8 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-31
5+
"""
6+
7+
import matplotlib.pyplot as plt
8+
import numpy as np
9+
from matplotlib.patches import FancyArrowPatch
10+
11+
12+
# Hierarchical data: Sales by Region -> Country -> State (3 levels)
13+
# Level 1: Sales by Region
14+
regions = ["North America", "Europe", "Asia Pacific", "Latin America"]
15+
region_values = [4500, 3200, 2800, 1500]
16+
region_colors = ["#306998", "#4A90D9", "#7AB8F5", "#A8D4FF"]
17+
18+
# Level 2: North America breakdown
19+
na_countries = ["USA", "Canada", "Mexico"]
20+
na_values = [3200, 800, 500]
21+
na_colors = ["#306998", "#3D7AB3", "#5A8FC4"]
22+
23+
# Level 3: USA breakdown (demonstrating 3rd hierarchy level)
24+
usa_states = ["California", "Texas", "New York", "Florida", "Others"]
25+
usa_values = [850, 720, 680, 550, 400]
26+
usa_colors = ["#1A3A5C", "#24517A", "#306998", "#4A90D9", "#7AB8F5"]
27+
28+
# Create figure with 3 pie charts showing hierarchy progression
29+
fig = plt.figure(figsize=(16, 9))
30+
fig.patch.set_facecolor("white")
31+
32+
# Three axes for 3 hierarchy levels
33+
ax1 = fig.add_axes([0.02, 0.15, 0.30, 0.60])
34+
ax2 = fig.add_axes([0.35, 0.15, 0.30, 0.60])
35+
ax3 = fig.add_axes([0.68, 0.15, 0.30, 0.60])
36+
37+
# Level 1: Main pie chart (all regions)
38+
wedges1, texts1, autotexts1 = ax1.pie(
39+
region_values,
40+
labels=None,
41+
autopct=lambda pct: f"{pct:.0f}%",
42+
colors=region_colors,
43+
startangle=90,
44+
explode=[0.08, 0, 0, 0],
45+
wedgeprops={"linewidth": 2, "edgecolor": "white"},
46+
textprops={"fontsize": 18, "fontweight": "bold", "color": "white"},
47+
pctdistance=0.55,
48+
)
49+
50+
# Add click indicator icons on main chart slices (using "+" symbol)
51+
for wedge in wedges1:
52+
ang = (wedge.theta2 + wedge.theta1) / 2
53+
x = 0.78 * np.cos(np.deg2rad(ang))
54+
y = 0.78 * np.sin(np.deg2rad(ang))
55+
ax1.annotate(
56+
"+",
57+
xy=(x, y),
58+
fontsize=20,
59+
fontweight="bold",
60+
ha="center",
61+
va="center",
62+
color="white",
63+
alpha=0.85,
64+
bbox={"boxstyle": "circle,pad=0.15", "fc": "#306998", "ec": "white", "lw": 1.5},
65+
)
66+
67+
# Add value labels outside level 1 pie
68+
for wedge, value, name in zip(wedges1, region_values, regions, strict=True):
69+
ang = (wedge.theta2 + wedge.theta1) / 2
70+
x = 1.30 * np.cos(np.deg2rad(ang))
71+
y = 1.30 * np.sin(np.deg2rad(ang))
72+
ax1.annotate(
73+
f"{name}\n${value:,}M",
74+
xy=(0.95 * np.cos(np.deg2rad(ang)), 0.95 * np.sin(np.deg2rad(ang))),
75+
xytext=(x, y),
76+
fontsize=11,
77+
ha="center",
78+
va="center",
79+
arrowprops={"arrowstyle": "-", "color": "#666666", "lw": 1},
80+
)
81+
82+
ax1.set_title("Level 1: All Regions", fontsize=18, fontweight="bold", pad=15)
83+
84+
# Level 2: North America drilldown
85+
wedges2, texts2, autotexts2 = ax2.pie(
86+
na_values,
87+
labels=None,
88+
autopct=lambda pct: f"{pct:.0f}%",
89+
colors=na_colors,
90+
startangle=90,
91+
explode=[0.08, 0, 0],
92+
wedgeprops={"linewidth": 2, "edgecolor": "white"},
93+
textprops={"fontsize": 18, "fontweight": "bold", "color": "white"},
94+
pctdistance=0.55,
95+
)
96+
97+
# Add click indicator icons on level 2 slices (using "+" symbol)
98+
for wedge in wedges2:
99+
ang = (wedge.theta2 + wedge.theta1) / 2
100+
x = 0.78 * np.cos(np.deg2rad(ang))
101+
y = 0.78 * np.sin(np.deg2rad(ang))
102+
ax2.annotate(
103+
"+",
104+
xy=(x, y),
105+
fontsize=20,
106+
fontweight="bold",
107+
ha="center",
108+
va="center",
109+
color="white",
110+
alpha=0.85,
111+
bbox={"boxstyle": "circle,pad=0.15", "fc": "#306998", "ec": "white", "lw": 1.5},
112+
)
113+
114+
# Add value labels outside level 2 pie
115+
for wedge, value, name in zip(wedges2, na_values, na_countries, strict=True):
116+
ang = (wedge.theta2 + wedge.theta1) / 2
117+
x = 1.30 * np.cos(np.deg2rad(ang))
118+
y = 1.30 * np.sin(np.deg2rad(ang))
119+
ax2.annotate(
120+
f"{name}\n${value:,}M",
121+
xy=(0.95 * np.cos(np.deg2rad(ang)), 0.95 * np.sin(np.deg2rad(ang))),
122+
xytext=(x, y),
123+
fontsize=11,
124+
ha="center",
125+
va="center",
126+
arrowprops={"arrowstyle": "-", "color": "#666666", "lw": 1},
127+
)
128+
129+
ax2.set_title("Level 2: North America", fontsize=18, fontweight="bold", pad=15)
130+
131+
# Level 3: USA drilldown
132+
wedges3, texts3, autotexts3 = ax3.pie(
133+
usa_values,
134+
labels=None,
135+
autopct=lambda pct: f"{pct:.0f}%",
136+
colors=usa_colors,
137+
startangle=90,
138+
wedgeprops={"linewidth": 2, "edgecolor": "white"},
139+
textprops={"fontsize": 18, "fontweight": "bold", "color": "white"},
140+
pctdistance=0.55,
141+
)
142+
143+
# Add value labels outside level 3 pie
144+
for wedge, value, name in zip(wedges3, usa_values, usa_states, strict=True):
145+
ang = (wedge.theta2 + wedge.theta1) / 2
146+
x = 1.30 * np.cos(np.deg2rad(ang))
147+
y = 1.30 * np.sin(np.deg2rad(ang))
148+
ax3.annotate(
149+
f"{name}\n${value:,}M",
150+
xy=(0.95 * np.cos(np.deg2rad(ang)), 0.95 * np.sin(np.deg2rad(ang))),
151+
xytext=(x, y),
152+
fontsize=11,
153+
ha="center",
154+
va="center",
155+
arrowprops={"arrowstyle": "-", "color": "#666666", "lw": 1},
156+
)
157+
158+
ax3.set_title("Level 3: USA", fontsize=18, fontweight="bold", pad=15)
159+
160+
# Add drill-down arrows between charts
161+
arrow1 = FancyArrowPatch(
162+
(0.325, 0.45),
163+
(0.365, 0.45),
164+
transform=fig.transFigure,
165+
color="#306998",
166+
linewidth=3,
167+
arrowstyle="-|>",
168+
mutation_scale=25,
169+
)
170+
fig.add_artist(arrow1)
171+
172+
arrow2 = FancyArrowPatch(
173+
(0.655, 0.45),
174+
(0.695, 0.45),
175+
transform=fig.transFigure,
176+
color="#306998",
177+
linewidth=3,
178+
arrowstyle="-|>",
179+
mutation_scale=25,
180+
)
181+
fig.add_artist(arrow2)
182+
183+
# Add breadcrumb navigation showing full path
184+
breadcrumb_box = fig.text(
185+
0.5,
186+
0.88,
187+
"All > North America > USA",
188+
fontsize=16,
189+
ha="center",
190+
va="center",
191+
fontweight="bold",
192+
bbox={"boxstyle": "round,pad=0.5", "facecolor": "#FFD43B", "edgecolor": "#306998", "linewidth": 2},
193+
)
194+
195+
# Add interactive hint
196+
fig.text(
197+
0.5,
198+
0.06,
199+
"Click any slice to drill down | Click breadcrumb to navigate up",
200+
fontsize=13,
201+
ha="center",
202+
va="center",
203+
color="#555555",
204+
style="italic",
205+
)
206+
207+
# Add title
208+
fig.suptitle("pie-drilldown · matplotlib · pyplots.ai", fontsize=24, fontweight="bold", y=0.97)
209+
210+
plt.savefig("plot.png", dpi=300, bbox_inches="tight", facecolor="white")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
library: matplotlib
2+
specification_id: pie-drilldown
3+
created: '2025-12-31T14:06:10Z'
4+
updated: '2025-12-31T14:27:38Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20620468775
7+
issue: 3072
8+
python_version: 3.13.11
9+
library_version: 3.10.8
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/pie-drilldown/matplotlib/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/pie-drilldown/matplotlib/plot_thumb.png
12+
preview_html: null
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent visual representation of the drilldown concept for a static image
17+
- Clear breadcrumb navigation with distinctive yellow styling
18+
- Consistent blue color scheme maintains visual hierarchy across levels
19+
- Well-designed arrow connecting the pie charts with explanatory text
20+
- Professional external labels with both category names and values
21+
- Good use of exploded slices to indicate selected/active elements
22+
weaknesses:
23+
- The code defines 3 hierarchy levels but only 2 appear in the generated image
24+
- Layout could better utilize horizontal space - right pie chart area feels slightly
25+
cramped
26+
- The + click indicators visible in code are not shown in the actual rendered image

0 commit comments

Comments
 (0)