Skip to content

Commit 76c8d69

Browse files
feat(plotnine): implement wordcloud-basic (#1031)
## Implementation: `wordcloud-basic` - plotnine Implements the **plotnine** version of `wordcloud-basic`. **File:** `plots/wordcloud-basic/implementations/plotnine.py` **Parent Issue:** #1012 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20257492021)* --------- 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 ab2c984 commit 76c8d69

2 files changed

Lines changed: 218 additions & 0 deletions

File tree

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
"""
2+
wordcloud-basic: Basic Word Cloud
3+
Library: plotnine
4+
"""
5+
6+
import numpy as np
7+
import pandas as pd
8+
from plotnine import (
9+
aes,
10+
element_blank,
11+
element_rect,
12+
element_text,
13+
geom_text,
14+
ggplot,
15+
labs,
16+
scale_color_identity,
17+
scale_size_identity,
18+
theme,
19+
)
20+
21+
22+
# Word frequency data - technology survey responses
23+
np.random.seed(42)
24+
words_data = {
25+
"word": [
26+
"Python",
27+
"Data",
28+
"Machine",
29+
"Learning",
30+
"AI",
31+
"Cloud",
32+
"API",
33+
"Database",
34+
"Security",
35+
"DevOps",
36+
"Analytics",
37+
"Automation",
38+
"Software",
39+
"Code",
40+
"Development",
41+
"Integration",
42+
"Platform",
43+
"Infrastructure",
44+
"Performance",
45+
"Scalability",
46+
"Testing",
47+
"Deployment",
48+
"Monitoring",
49+
"Architecture",
50+
"Framework",
51+
"Microservices",
52+
"Container",
53+
"Kubernetes",
54+
"Docker",
55+
"AWS",
56+
"Azure",
57+
"Innovation",
58+
"Digital",
59+
"Transform",
60+
"Agile",
61+
],
62+
"frequency": [
63+
95,
64+
88,
65+
82,
66+
78,
67+
75,
68+
70,
69+
65,
70+
62,
71+
58,
72+
55,
73+
52,
74+
48,
75+
45,
76+
42,
77+
38,
78+
35,
79+
32,
80+
30,
81+
28,
82+
26,
83+
24,
84+
22,
85+
20,
86+
18,
87+
16,
88+
14,
89+
13,
90+
12,
91+
11,
92+
10,
93+
9,
94+
8,
95+
7,
96+
6,
97+
5,
98+
],
99+
}
100+
101+
df = pd.DataFrame(words_data)
102+
103+
# Calculate font sizes scaled by frequency (range 10-36 for readability)
104+
min_freq, max_freq = df["frequency"].min(), df["frequency"].max()
105+
df["size"] = 10 + (df["frequency"] - min_freq) / (max_freq - min_freq) * 26
106+
107+
# Sort by frequency descending for placement (largest words first)
108+
df = df.sort_values("frequency", ascending=False).reset_index(drop=True)
109+
110+
# Fixed positions using concentric rings to guarantee no overlaps
111+
np.random.seed(42)
112+
width, height = 100, 56.25
113+
center_x, center_y = width / 2, height / 2
114+
115+
# Define rings with word counts: inner ring has fewer, larger words
116+
rings = [
117+
{"count": 5, "radius": 0, "y_offset": 0}, # Center - 5 largest words
118+
{"count": 8, "radius": 16, "y_offset": 0}, # Ring 1
119+
{"count": 10, "radius": 28, "y_offset": 0}, # Ring 2
120+
{"count": 12, "radius": 40, "y_offset": 0}, # Ring 3 (outer)
121+
]
122+
123+
positions_x = []
124+
positions_y = []
125+
word_idx = 0
126+
127+
# Place center words in a horizontal line with spacing
128+
center_words = 5
129+
center_spacing = 14
130+
center_start_x = center_x - (center_words - 1) * center_spacing / 2
131+
for i in range(center_words):
132+
x = center_start_x + i * center_spacing
133+
y = center_y
134+
positions_x.append(x)
135+
positions_y.append(y)
136+
word_idx = center_words
137+
138+
# Place remaining words in concentric rings
139+
for ring in rings[1:]:
140+
ring_count = min(ring["count"], len(df) - word_idx)
141+
if ring_count <= 0:
142+
break
143+
for i in range(ring_count):
144+
angle = (2 * np.pi * i / ring_count) + np.random.uniform(-0.1, 0.1)
145+
# Adjust radius based on 16:9 aspect ratio
146+
x = center_x + ring["radius"] * np.cos(angle) * 1.1
147+
y = center_y + ring["radius"] * np.sin(angle) * 0.6
148+
149+
# Keep within bounds
150+
x = np.clip(x, 12, width - 12)
151+
y = np.clip(y, 6, height - 6)
152+
153+
positions_x.append(x)
154+
positions_y.append(y)
155+
word_idx += ring_count
156+
157+
df = df.head(len(positions_x))
158+
df["x"] = positions_x
159+
df["y"] = positions_y
160+
161+
# Assign colors based on frequency tiers
162+
colors = []
163+
for freq in df["frequency"]:
164+
if freq >= 65:
165+
colors.append("#306998") # Python Blue - high frequency
166+
elif freq >= 35:
167+
colors.append("#FFD43B") # Python Yellow - medium frequency
168+
elif freq >= 15:
169+
colors.append("#4ECDC4") # Teal - lower medium
170+
else:
171+
colors.append("#95E1A3") # Light green - low frequency
172+
df["color"] = colors
173+
174+
# Create plot
175+
plot = (
176+
ggplot(df, aes(x="x", y="y", label="word", size="size", color="color"))
177+
+ geom_text(family="sans-serif", fontstyle="normal", show_legend=False)
178+
+ scale_size_identity()
179+
+ scale_color_identity()
180+
+ labs(title="Tech Survey Keywords · wordcloud-basic · plotnine · pyplots.ai")
181+
+ theme(
182+
figure_size=(16, 9),
183+
plot_title=element_text(size=24, ha="center", weight="bold", margin={"b": 15}),
184+
panel_background=element_rect(fill="white"),
185+
plot_background=element_rect(fill="white"),
186+
panel_grid_major=element_blank(),
187+
panel_grid_minor=element_blank(),
188+
axis_text=element_blank(),
189+
axis_title=element_blank(),
190+
axis_ticks=element_blank(),
191+
)
192+
)
193+
194+
# Save
195+
plot.save("plot.png", dpi=300, verbose=False)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Per-library metadata for plotnine implementation of wordcloud-basic
2+
# Auto-generated by impl-generate.yml
3+
4+
library: plotnine
5+
specification_id: wordcloud-basic
6+
7+
# Preview URLs (filled by workflow)
8+
preview_url: https://storage.googleapis.com/pyplots-images/plots/wordcloud-basic/plotnine/plot.png
9+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/wordcloud-basic/plotnine/plot_thumb.png
10+
preview_html: null
11+
12+
current:
13+
version: 0
14+
generated_at: 2025-12-16T05:30:06Z
15+
generated_by: claude-opus-4-5-20251101
16+
workflow_run: 20257492021
17+
issue: 1012
18+
quality_score: 92
19+
# Version info (filled by workflow)
20+
python_version: "3.13.11"
21+
library_version: "unknown"
22+
23+
history: []

0 commit comments

Comments
 (0)