Skip to content

Commit 5e269a2

Browse files
feat(pygal): implement scatter-size-mapped (#2425)
## Implementation: `scatter-size-mapped` - pygal Implements the **pygal** version of `scatter-size-mapped`. **File:** `plots/scatter-size-mapped/implementations/pygal.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20543371845)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 212f2ae commit 5e269a2

2 files changed

Lines changed: 125 additions & 0 deletions

File tree

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
""" pyplots.ai
2+
scatter-size-mapped: Bubble Chart
3+
Library: pygal 3.1.0 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-27
5+
"""
6+
7+
import numpy as np
8+
import pygal
9+
from pygal.style import Style
10+
11+
12+
# Data: Country economic indicators
13+
np.random.seed(42)
14+
15+
# Generate 40 synthetic countries across different regions
16+
n_countries = 40
17+
regions = ["Europe", "Asia", "Americas", "Africa"]
18+
19+
# Assign regions with some variation
20+
region_assignments = np.random.choice(regions, n_countries)
21+
22+
# GDP per capita (1,000 - 80,000)
23+
gdp_per_capita = np.random.uniform(5000, 75000, n_countries)
24+
# Adjust by region for realism
25+
for i, region in enumerate(region_assignments):
26+
if region == "Europe":
27+
gdp_per_capita[i] = np.random.uniform(25000, 75000)
28+
elif region == "Asia":
29+
gdp_per_capita[i] = np.random.uniform(5000, 60000)
30+
elif region == "Americas":
31+
gdp_per_capita[i] = np.random.uniform(8000, 70000)
32+
else: # Africa
33+
gdp_per_capita[i] = np.random.uniform(1000, 20000)
34+
35+
# Life expectancy (50-85) correlated with GDP
36+
life_expectancy = 50 + 30 * (gdp_per_capita / 80000) + np.random.uniform(-5, 5, n_countries)
37+
life_expectancy = np.clip(life_expectancy, 50, 85)
38+
39+
# Population (log scale, 1M - 1.4B)
40+
population = 10 ** np.random.uniform(6, 9.2, n_countries)
41+
42+
# Create custom style with larger font sizes for better rendering
43+
custom_style = Style(
44+
background="white",
45+
plot_background="white",
46+
foreground="#333333",
47+
foreground_strong="#333333",
48+
foreground_subtle="#666666",
49+
colors=("#306998", "#FFD43B", "#E74C3C", "#27AE60", "#9B59B6"),
50+
title_font_size=84,
51+
label_font_size=56,
52+
major_label_font_size=48,
53+
legend_font_size=44,
54+
value_font_size=40,
55+
opacity=0.6,
56+
opacity_hover=0.8,
57+
)
58+
59+
# Title with size legend information
60+
title = "scatter-size-mapped · pygal · pyplots.ai\nBubble Size = Population (1M to 1B+)"
61+
62+
# Create XY chart for scatter plot
63+
chart = pygal.XY(
64+
width=4800,
65+
height=2700,
66+
style=custom_style,
67+
title=title,
68+
x_title="GDP per Capita (USD)",
69+
y_title="Life Expectancy (years)",
70+
show_legend=True,
71+
legend_at_bottom=True,
72+
legend_at_bottom_columns=4,
73+
dots_size=15,
74+
show_x_guides=True,
75+
show_y_guides=True,
76+
stroke=False,
77+
explicit_size=True,
78+
truncate_legend=-1,
79+
)
80+
81+
# Group data by region and add as series
82+
# Pygal XY chart uses value dict with 'value' for coordinates
83+
for region in regions:
84+
mask = region_assignments == region
85+
points = []
86+
for i in np.where(mask)[0]:
87+
# Scale population to reasonable dot size (log scale)
88+
# Population ranges from 1M to 1.4B, scale to 12-70 for better visibility
89+
# Increased minimum size from 5 to 12 so smaller bubbles are visible
90+
size = 12 + 58 * (np.log10(population[i]) - 6) / 3.2
91+
points.append({"value": (float(gdp_per_capita[i]), float(life_expectancy[i])), "node": {"r": size}})
92+
chart.add(region, points)
93+
94+
# Render to files
95+
chart.render_to_png("plot.png")
96+
chart.render_to_file("plot.html")
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
library: pygal
2+
specification_id: scatter-size-mapped
3+
created: '2025-12-27T19:31:03Z'
4+
updated: '2025-12-27T19:43:26Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20543371845
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: 3.1.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/scatter-size-mapped/pygal/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/scatter-size-mapped/pygal/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/scatter-size-mapped/pygal/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent realistic data generation with regional economic patterns (Europe higher
17+
GDP, Africa lower GDP)
18+
- Proper use of pygal XY chart with custom node sizes via the node dict parameter
19+
for bubble sizing
20+
- Well-implemented semi-transparency (opacity=0.6) for distinguishing overlapping
21+
bubbles
22+
- Clean code structure following KISS principles with proper seed for reproducibility
23+
- Size legend integrated into title subtitle (Bubble Size = Population 1M to 1B+)
24+
- Improved minimum bubble size (12) from previous attempt makes smaller populations
25+
more visible
26+
weaknesses:
27+
- Grid lines are too subtle and barely visible - could use more prominent guide
28+
styling
29+
- Title format includes subtitle which slightly deviates from the exact spec format

0 commit comments

Comments
 (0)