Skip to content

Commit eecbb2c

Browse files
update(violin-basic): letsplot — comprehensive quality review (#4330)
## Summary Updated **letsplot** implementation for **violin-basic**. **Changes:** Comprehensive quality review improving code quality, data choice, visual design, spec compliance, and library feature usage. ### Changes - Improved data generation with distinct distribution shapes per category - Enhanced visual design (explicit font sizes, refined color palette, layout balance) - Fixed review weaknesses from previous evaluation - Updated metadata with current library/Python versions - Preview images uploaded to GCS staging ## Test Plan - [x] Preview images uploaded to GCS staging - [x] Implementation file passes ruff format/check - [x] Metadata YAML updated with current versions - [ ] Automated review triggered --- Generated with [Claude Code](https://claude.com/claude-code) `/update` command --------- 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 a64b056 commit eecbb2c

2 files changed

Lines changed: 172 additions & 151 deletions

File tree

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
""" pyplots.ai
22
violin-basic: Basic Violin Plot
3-
Library: letsplot 4.8.1 | Python 3.13.11
4-
Quality: 91/100 | Created: 2025-12-23
3+
Library: letsplot 4.8.2 | Python 3.14.3
4+
Quality: 90/100 | Updated: 2026-02-21
55
"""
66

77
import numpy as np
@@ -15,53 +15,66 @@
1515
# Data
1616
np.random.seed(42)
1717

18-
categories = ["Engineering", "Marketing", "Sales", "Design"]
19-
colors = ["#306998", "#FFD43B", "#4B8BBE", "#FFE873"]
18+
# Ordered by median salary (high → low) for visual storytelling
19+
dept_order = ["Engineering", "Design", "Marketing", "Sales"]
20+
palette = ["#306998", "#2E8B57", "#E8A317", "#E07A5F"]
2021

21-
# Generate realistic salary distributions per department
2222
data = []
23-
distributions = {
24-
"Engineering": {"mean": 95000, "std": 20000, "n": 200},
25-
"Marketing": {"mean": 75000, "std": 15000, "n": 150},
26-
"Sales": {"mean": 70000, "std": 25000, "n": 180},
27-
"Design": {"mean": 80000, "std": 18000, "n": 120},
28-
}
2923

30-
for cat in categories:
31-
dist = distributions[cat]
32-
values = np.random.normal(dist["mean"], dist["std"], dist["n"])
33-
values = np.clip(values, 30000, 200000) # Realistic salary bounds
34-
for v in values:
35-
data.append({"Department": cat, "Salary": v})
24+
# Engineering: bimodal (junior ~$70k + senior ~$115k) — showcases violin strength
25+
eng_junior = np.random.normal(70000, 8000, 80)
26+
eng_senior = np.random.normal(115000, 12000, 120)
27+
eng_values = np.clip(np.concatenate([eng_junior, eng_senior]), 30000, 200000)
28+
for v in eng_values:
29+
data.append({"Department": "Engineering", "Salary": v})
30+
31+
# Design: moderate spread, roughly normal
32+
design_values = np.random.normal(80000, 18000, 120)
33+
design_values = np.clip(design_values, 30000, 200000)
34+
for v in design_values:
35+
data.append({"Department": "Design", "Salary": v})
36+
37+
# Marketing: narrower with a small cluster of high earners
38+
mkt_base = np.random.normal(72000, 12000, 130)
39+
mkt_high = np.random.normal(105000, 8000, 20)
40+
mkt_values = np.clip(np.concatenate([mkt_base, mkt_high]), 30000, 200000)
41+
for v in mkt_values:
42+
data.append({"Department": "Marketing", "Salary": v})
43+
44+
# Sales: right-skewed (many moderate earners, few top performers)
45+
sales_values = np.random.exponential(20000, 180) + 45000
46+
sales_values = np.clip(sales_values, 30000, 200000)
47+
for v in sales_values:
48+
data.append({"Department": "Sales", "Salary": v})
3649

3750
df = pd.DataFrame(data)
3851

3952
# Plot
4053
plot = (
4154
ggplot(df, aes(x="Department", y="Salary", fill="Department")) # noqa: F405
4255
+ geom_violin( # noqa: F405
43-
quantiles=[0.25, 0.5, 0.75], # Show quartiles including median
44-
quantile_lines=True, # Draw lines at quantiles
45-
size=1.5, # Border thickness
46-
alpha=0.8,
47-
trim=False, # Show full tails
56+
quantiles=[0.25, 0.5, 0.75], quantile_lines=True, size=1.2, alpha=0.85, trim=False, color="#2C3E50"
57+
)
58+
+ scale_x_discrete(limits=dept_order) # noqa: F405
59+
+ scale_fill_manual(values=dict(zip(dept_order, palette, strict=True))) # noqa: F405
60+
+ scale_y_continuous( # noqa: F405
61+
format="${,.0f}"
4862
)
49-
+ scale_fill_manual(values=colors) # noqa: F405
5063
+ labs( # noqa: F405
51-
x="Department", y="Salary ($)", title="violin-basic · lets-plot · pyplots.ai"
64+
x="Department", y="Salary", title="violin-basic \u00b7 letsplot \u00b7 pyplots.ai"
5265
)
5366
+ theme_minimal() # noqa: F405
5467
+ theme( # noqa: F405
5568
axis_title=element_text(size=20), # noqa: F405
5669
axis_text=element_text(size=16), # noqa: F405
5770
plot_title=element_text(size=24), # noqa: F405
58-
legend_position="none", # Legend not needed, x-axis shows categories
71+
legend_position="none",
72+
panel_grid_major_x=element_blank(), # noqa: F405
73+
axis_ticks=element_blank(), # noqa: F405
5974
)
6075
+ ggsize(1600, 900) # noqa: F405
6176
)
6277

63-
# Save PNG (scale 3x to get 4800 × 2700 px)
78+
# Save
6479
export_ggsave(plot, filename="plot.png", path=".", scale=3)
65-
66-
# Save HTML for interactive version
6780
export_ggsave(plot, filename="plot.html", path=".")

0 commit comments

Comments
 (0)