Skip to content

Commit ed598ef

Browse files
feat(letsplot): implement venn-basic (#2486)
## Implementation: `venn-basic` - letsplot Implements the **letsplot** version of `venn-basic`. **File:** `plots/venn-basic/implementations/letsplot.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20584335161)* --------- 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 841a5af commit ed598ef

2 files changed

Lines changed: 144 additions & 0 deletions

File tree

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
""" pyplots.ai
2+
venn-basic: Venn Diagram
3+
Library: letsplot 4.8.2 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-29
5+
"""
6+
7+
import os
8+
9+
import numpy as np
10+
import pandas as pd
11+
from lets_plot import *
12+
13+
14+
np.random.seed(42)
15+
16+
LetsPlot.setup_html()
17+
18+
# Data: Three research fields with overlapping expertise
19+
set_a_label = "Machine Learning"
20+
set_b_label = "Statistics"
21+
set_c_label = "Data Engineering"
22+
23+
# Set sizes and intersections
24+
only_a = 45 # Only ML
25+
only_b = 35 # Only Statistics
26+
only_c = 30 # Only Data Engineering
27+
ab_only = 25 # ML & Statistics (not DE)
28+
ac_only = 15 # ML & DE (not Stats)
29+
bc_only = 20 # Stats & DE (not ML)
30+
abc = 10 # All three
31+
32+
# Circle parameters (for 3-set Venn diagram) - larger for better canvas utilization
33+
r = 1.8 # radius (increased from 1.5)
34+
cx_a, cy_a = -0.85, 0.6 # Center of set A (top left)
35+
cx_b, cy_b = 0.85, 0.6 # Center of set B (top right)
36+
cx_c, cy_c = 0.0, -0.75 # Center of set C (bottom)
37+
38+
# Generate circle points
39+
theta = np.linspace(0, 2 * np.pi, 100)
40+
41+
# Create circle data
42+
circle_a_x = cx_a + r * np.cos(theta)
43+
circle_a_y = cy_a + r * np.sin(theta)
44+
circle_b_x = cx_b + r * np.cos(theta)
45+
circle_b_y = cy_b + r * np.sin(theta)
46+
circle_c_x = cx_c + r * np.cos(theta)
47+
circle_c_y = cy_c + r * np.sin(theta)
48+
49+
# Create DataFrames for circles
50+
df_a = pd.DataFrame({"x": circle_a_x, "y": circle_a_y, "set": set_a_label})
51+
df_b = pd.DataFrame({"x": circle_b_x, "y": circle_b_y, "set": set_b_label})
52+
df_c = pd.DataFrame({"x": circle_c_x, "y": circle_c_y, "set": set_c_label})
53+
df_circles = pd.concat([df_a, df_b, df_c], ignore_index=True)
54+
55+
# Label positions and values (adjusted for larger circles and better spacing)
56+
labels_data = pd.DataFrame(
57+
{
58+
"x": [
59+
cx_a - 0.6, # Only A (left side of A)
60+
cx_b + 0.6, # Only B (right side of B)
61+
cx_c, # Only C (bottom of C) - moved further down
62+
(cx_a + cx_b) / 2, # A & B intersection
63+
(cx_a + cx_c) / 2 - 0.35, # A & C intersection
64+
(cx_b + cx_c) / 2 + 0.35, # B & C intersection
65+
0.0, # Center (A & B & C)
66+
],
67+
"y": [
68+
cy_a + 0.4, # Only A
69+
cy_b + 0.4, # Only B
70+
cy_c - 0.75, # Only C - moved much further down to avoid center overlap
71+
cy_a + 0.75, # A & B intersection
72+
(cy_a + cy_c) / 2 - 0.4, # A & C intersection
73+
(cy_b + cy_c) / 2 - 0.4, # B & C intersection
74+
0.0, # Center (A & B & C)
75+
],
76+
"label": [str(only_a), str(only_b), str(only_c), str(ab_only), str(ac_only), str(bc_only), str(abc)],
77+
}
78+
)
79+
80+
# Set name labels (outside circles) - adjusted for larger circles
81+
set_labels_data = pd.DataFrame(
82+
{
83+
"x": [cx_a - 0.9, cx_b + 0.9, cx_c],
84+
"y": [cy_a + 1.5, cy_b + 1.5, cy_c - 1.6],
85+
"label": [set_a_label, set_b_label, set_c_label],
86+
}
87+
)
88+
89+
# Colors
90+
colors = {"Machine Learning": "#306998", "Statistics": "#FFD43B", "Data Engineering": "#DC2626"}
91+
92+
# Create plot
93+
plot = (
94+
ggplot()
95+
+ geom_polygon(aes(x="x", y="y", fill="set"), data=df_circles, alpha=0.35, color="white", size=2.5)
96+
+ geom_text(aes(x="x", y="y", label="label"), data=labels_data, size=20, fontface="bold", color="#1a1a1a")
97+
+ geom_text(aes(x="x", y="y", label="label"), data=set_labels_data, size=18, fontface="bold", color="#222222")
98+
+ scale_fill_manual(values=colors)
99+
+ coord_fixed(ratio=1)
100+
+ labs(title="venn-basic · lets-plot · pyplots.ai")
101+
+ theme_void()
102+
+ theme(
103+
plot_title=element_text(size=28, face="bold", hjust=0.5), legend_position="none", plot_margin=[50, 30, 30, 30]
104+
)
105+
+ ggsize(1200, 1200)
106+
)
107+
108+
# Save as PNG and HTML
109+
ggsave(plot, "plot.png", scale=3)
110+
ggsave(plot, "plot.html")
111+
112+
# Move files from lets-plot-images subdirectory to current directory
113+
if os.path.exists("lets-plot-images/plot.png"):
114+
os.rename("lets-plot-images/plot.png", "plot.png")
115+
if os.path.exists("lets-plot-images/plot.html"):
116+
os.rename("lets-plot-images/plot.html", "plot.html")
117+
if os.path.exists("lets-plot-images") and not os.listdir("lets-plot-images"):
118+
os.rmdir("lets-plot-images")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
library: letsplot
2+
specification_id: venn-basic
3+
created: '2025-12-29T22:53:27Z'
4+
updated: '2025-12-29T23:07:28Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20584335161
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: 4.8.2
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/venn-basic/letsplot/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/venn-basic/letsplot/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/venn-basic/letsplot/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent visual clarity with well-positioned labels and counts in all 7 regions
17+
- Creative implementation using geom_polygon to construct Venn circles from coordinate
18+
data
19+
- Good color choices (blue/yellow/pink) with appropriate transparency for overlap
20+
visualization
21+
- Realistic and relatable data context (research field skills overlap)
22+
- Proper title format and square aspect ratio appropriate for the diagram type
23+
weaknesses:
24+
- File output requires os workaround to move files from lets-plot-images subdirectory
25+
- Could use geom_path instead of geom_polygon with size parameter for circle borders
26+
(minor)

0 commit comments

Comments
 (0)