Skip to content

Commit 9a3e634

Browse files
feat(pygal): implement pie-basic (#354)
## Summary Implements `pie-basic` for **pygal** library. **Parent Issue:** #206 **Sub-Issue:** #273 **Base Branch:** `plot/pie-basic` **Attempt:** 1/3 ## Implementation - `plots/pygal/pie/pie-basic/default.py` ## Changes - Simplified implementation following KISS principles - Removed function wrapper, type hints, and docstrings per plot-generator.md guidelines - Direct sequential code matching gallery example style - Uses PyPlots color palette from style guide - 4800x2700 px output with recommended font sizes - Legend at bottom for clear visibility Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
1 parent 759606c commit 9a3e634

1 file changed

Lines changed: 31 additions & 134 deletions

File tree

plots/pygal/pie/pie-basic/default.py

Lines changed: 31 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -3,145 +3,42 @@
33
Library: pygal
44
"""
55

6-
import pandas as pd
76
import pygal
87
from pygal.style import Style
98

109

11-
# PyPlots.ai color palette
12-
PYPLOTS_COLORS = (
13-
"#306998", # Python Blue (Primary)
14-
"#FFD43B", # Python Yellow
15-
"#DC2626", # Signal Red
16-
"#059669", # Teal Green
17-
"#8B5CF6", # Violet
18-
"#F97316", # Orange
10+
# Data
11+
categories = ["Product A", "Product B", "Product C", "Product D", "Other"]
12+
values = [35, 25, 20, 15, 5]
13+
14+
# Custom style matching default-style-guide.md colors
15+
custom_style = Style(
16+
background="white",
17+
plot_background="white",
18+
foreground="#333333",
19+
foreground_strong="#333333",
20+
foreground_subtle="#666666",
21+
colors=("#306998", "#FFD43B", "#DC2626", "#059669", "#8B5CF6"),
22+
title_font_size=60,
23+
legend_font_size=48,
24+
value_font_size=48,
25+
tooltip_font_size=36,
1926
)
2027

28+
# Create pie chart
29+
chart = pygal.Pie(
30+
width=4800,
31+
height=2700,
32+
title="Market Share Distribution",
33+
style=custom_style,
34+
inner_radius=0,
35+
show_legend=True,
36+
legend_at_bottom=True,
37+
)
2138

22-
def create_plot(
23-
data: pd.DataFrame,
24-
category: str,
25-
value: str,
26-
figsize: tuple[int, int] = (1600, 900),
27-
title: str | None = None,
28-
colors: list[str] | None = None,
29-
startangle: float = 90,
30-
legend: bool = True,
31-
legend_loc: str = "right",
32-
inner_radius: float = 0,
33-
**kwargs,
34-
) -> pygal.Pie:
35-
"""
36-
Create a basic pie chart for visualizing proportions of categorical data.
37-
38-
Args:
39-
data: Input DataFrame containing the data to plot.
40-
category: Column name for category labels.
41-
value: Column name for numeric values representing each slice's proportion.
42-
figsize: Figure size as (width, height) in pixels.
43-
title: Optional plot title.
44-
colors: Custom color palette for slices (defaults to PyPlots palette).
45-
startangle: Starting angle for first slice in degrees (not used in pygal).
46-
legend: Whether to display legend.
47-
legend_loc: Legend location ('right', 'bottom', or 'top').
48-
inner_radius: Inner radius for donut chart (0-1, 0 for solid pie).
49-
**kwargs: Additional parameters passed to pygal.Pie.
50-
51-
Returns:
52-
pygal.Pie chart object.
53-
54-
Raises:
55-
ValueError: If data is empty or contains negative values.
56-
KeyError: If required columns are not found in data.
57-
58-
Example:
59-
>>> data = pd.DataFrame({
60-
... 'category': ['Product A', 'Product B', 'Product C'],
61-
... 'value': [35, 25, 40]
62-
... })
63-
>>> chart = create_plot(data, 'category', 'value', title='Market Share')
64-
"""
65-
# Input validation
66-
if data.empty:
67-
raise ValueError("Data cannot be empty")
68-
69-
for col in [category, value]:
70-
if col not in data.columns:
71-
available = ", ".join(data.columns)
72-
raise KeyError(f"Column '{col}' not found. Available: {available}")
73-
74-
# Handle missing values
75-
clean_data = data[[category, value]].dropna()
76-
77-
if clean_data.empty:
78-
raise ValueError("Data cannot be empty after removing missing values")
79-
80-
# Validate non-negative values
81-
if (clean_data[value] < 0).any():
82-
raise ValueError("Pie chart values must be non-negative")
83-
84-
# Check if all values sum to zero
85-
total = clean_data[value].sum()
86-
if total == 0:
87-
raise ValueError("Values sum to zero; cannot create pie chart")
88-
89-
# Use provided colors or default PyPlots palette
90-
chart_colors = tuple(colors) if colors else PYPLOTS_COLORS
91-
92-
# Create custom style
93-
custom_style = Style(
94-
background="white",
95-
plot_background="white",
96-
foreground="#333333",
97-
foreground_strong="#333333",
98-
foreground_subtle="#666666",
99-
colors=chart_colors,
100-
font_family="Inter, DejaVu Sans, Arial, Helvetica, sans-serif",
101-
title_font_size=20,
102-
legend_font_size=16,
103-
value_font_size=14,
104-
tooltip_font_size=14,
105-
)
106-
107-
# Determine legend position
108-
legend_at_bottom = legend_loc == "bottom"
109-
legend_box_size = 16 if legend else 0
110-
111-
# Create chart
112-
chart = pygal.Pie(
113-
width=figsize[0],
114-
height=figsize[1],
115-
title=title,
116-
style=custom_style,
117-
show_legend=legend,
118-
legend_at_bottom=legend_at_bottom,
119-
legend_box_size=legend_box_size,
120-
inner_radius=inner_radius,
121-
print_values=True,
122-
value_formatter=lambda x: f"{x:.1f}%",
123-
**kwargs,
124-
)
125-
126-
# Add each category as a separate slice with percentage value
127-
for _, row in clean_data.iterrows():
128-
cat_name = str(row[category])
129-
cat_value = float(row[value])
130-
percentage = (cat_value / total) * 100
131-
chart.add(cat_name, [{"value": percentage, "label": cat_name}])
132-
133-
return chart
134-
135-
136-
if __name__ == "__main__":
137-
# Sample data for testing
138-
sample_data = pd.DataFrame(
139-
{"category": ["Product A", "Product B", "Product C", "Product D", "Other"], "value": [35, 25, 20, 15, 5]}
140-
)
141-
142-
# Create plot
143-
chart = create_plot(sample_data, "category", "value", title="Market Share Distribution")
39+
# Add data slices
40+
for category, value in zip(categories, values, strict=True):
41+
chart.add(category, value)
14442

145-
# Save to PNG
146-
chart.render_to_png("plot.png")
147-
print("Plot saved to plot.png")
43+
# Save as PNG
44+
chart.render_to_png("plot.png")

0 commit comments

Comments
 (0)