Skip to content

Commit a354bc0

Browse files
update(violin-basic): bokeh — comprehensive quality review
Comprehensive quality review improving code quality, data choice, visual design, spec compliance, and library feature usage.
1 parent e9894a3 commit a354bc0

2 files changed

Lines changed: 35 additions & 38 deletions

File tree

plots/violin-basic/implementations/bokeh.py

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
""" pyplots.ai
22
violin-basic: Basic Violin Plot
3-
Library: bokeh 3.8.1 | Python 3.13.11
4-
Quality: 91/100 | Created: 2025-12-23
3+
Library: bokeh 3.8.2 | Python 3.14.3
4+
Quality: /100 | Updated: 2026-02-21
55
"""
66

77
import numpy as np
88
from bokeh.io import export_png, output_file, save
9+
from bokeh.models import NumeralTickFormatter
910
from bokeh.plotting import figure
11+
from scipy.stats import gaussian_kde
1012

1113

1214
# Data - Salary distributions by department (realistic scenario)
@@ -15,66 +17,62 @@
1517
data = {
1618
"Engineering": np.random.normal(85000, 15000, 150),
1719
"Marketing": np.random.normal(65000, 12000, 150),
18-
"Sales": np.random.normal(70000, 20000, 150), # Higher variance
19-
"Support": np.random.normal(50000, 8000, 150), # Lower variance
20+
"Sales": np.random.normal(70000, 20000, 150),
21+
"Support": np.random.normal(50000, 8000, 150),
2022
}
2123

22-
# Colors - Python Blue and Yellow first, then accessible colors
24+
# Colors - Python Blue first, then accessible palette
2325
colors = ["#306998", "#FFD43B", "#4B8BBE", "#FFE873"]
2426

25-
# Create figure with categorical x-axis
27+
# Create figure
2628
p = figure(
2729
width=4800,
2830
height=2700,
29-
title="violin-basic · bokeh · pyplots.ai",
31+
title="violin-basic \u00b7 bokeh \u00b7 pyplots.ai",
3032
x_axis_label="Department",
3133
y_axis_label="Annual Salary (USD)",
3234
x_range=categories,
3335
toolbar_location=None,
3436
)
3537

36-
# Styling for 4800x2700 px
38+
# Text sizing for 4800x2700 px
3739
p.title.text_font_size = "36pt"
3840
p.xaxis.axis_label_text_font_size = "28pt"
3941
p.yaxis.axis_label_text_font_size = "28pt"
4042
p.xaxis.major_label_text_font_size = "22pt"
4143
p.yaxis.major_label_text_font_size = "22pt"
4244

43-
# Grid styling
45+
# Format y-axis as readable currency
46+
p.yaxis.formatter = NumeralTickFormatter(format="$0,0")
47+
48+
# Visual refinement - clean design
4449
p.xgrid.grid_line_color = None
45-
p.ygrid.grid_line_alpha = 0.3
50+
p.ygrid.grid_line_alpha = 0.2
4651
p.ygrid.grid_line_dash = "dashed"
52+
p.outline_line_color = None
53+
p.axis.minor_tick_line_color = None
54+
p.axis.major_tick_line_color = None
55+
p.axis.axis_line_color = "#cccccc"
4756

48-
# Violin width scaling (0.4 = 40% of category spacing)
57+
# Violin width scaling
4958
violin_width = 0.4
5059

5160
# Draw violins for each category
5261
for i, cat in enumerate(categories):
5362
values = data[cat]
54-
n = len(values)
5563

56-
# Compute KDE using Gaussian kernel (Silverman's rule for bandwidth)
64+
# Compute KDE using scipy (idiomatic, robust bandwidth selection)
65+
kde = gaussian_kde(values)
5766
std = np.std(values)
58-
iqr = np.percentile(values, 75) - np.percentile(values, 25)
59-
bandwidth = 0.9 * min(std, iqr / 1.34) * n ** (-0.2)
60-
bandwidth = max(bandwidth, 0.1)
61-
6267
y_grid = np.linspace(values.min() - std, values.max() + std, 100)
63-
density = np.zeros_like(y_grid, dtype=float)
64-
for xi in values:
65-
density += np.exp(-0.5 * ((y_grid - xi) / bandwidth) ** 2)
66-
density /= n * bandwidth * np.sqrt(2 * np.pi)
68+
density = kde(y_grid)
6769

6870
# Scale density to violin width
6971
density_scaled = density / density.max() * violin_width
7072

71-
# Create violin shape (mirrored on both sides)
72-
x_left = -density_scaled
73-
x_right = density_scaled
74-
75-
# Convert to categorical offset format for bokeh
76-
xs_left = [(cat, float(xl)) for xl in x_left]
77-
xs_right = [(cat, float(xr)) for xr in x_right[::-1]]
73+
# Create mirrored violin shape using categorical offset tuples
74+
xs_left = [(cat, float(-d)) for d in density_scaled]
75+
xs_right = [(cat, float(d)) for d in density_scaled[::-1]]
7876

7977
# Draw violin patch
8078
p.patch(
@@ -86,10 +84,10 @@
8684
line_width=3,
8785
)
8886

89-
# Compute quartiles
87+
# Quartiles and median
9088
q1, median, q3 = np.percentile(values, [25, 50, 75])
9189

92-
# Draw thin box inside violin (quartile markers)
90+
# Inner box (Q1-Q3)
9391
box_width = 0.06
9492
p.quad(
9593
left=[(cat, -box_width)],
@@ -102,7 +100,7 @@
102100
line_width=3,
103101
)
104102

105-
# Draw median line
103+
# Median line
106104
p.segment(
107105
x0=[(cat, -box_width * 1.5)],
108106
y0=[median],
@@ -112,12 +110,11 @@
112110
line_width=5,
113111
)
114112

115-
# Whiskers (to 1.5*IQR or data extent)
113+
# Whiskers (1.5*IQR or data extent)
116114
iqr_val = q3 - q1
117115
whisker_low = max(values.min(), q1 - 1.5 * iqr_val)
118116
whisker_high = min(values.max(), q3 + 1.5 * iqr_val)
119117

120-
# Vertical whisker lines
121118
p.segment(x0=[cat], y0=[q1], x1=[cat], y1=[whisker_low], line_color="black", line_width=3)
122119
p.segment(x0=[cat], y0=[q3], x1=[cat], y1=[whisker_high], line_color="black", line_width=3)
123120

plots/violin-basic/metadata/bokeh.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
library: bokeh
22
specification_id: violin-basic
33
created: '2025-12-23T00:36:10Z'
4-
updated: '2025-12-23T00:39:05Z'
5-
generated_by: claude-opus-4-5-20251101
4+
updated: '2026-02-21T22:25:00+00:00'
5+
generated_by: claude-opus-4-6
66
workflow_run: 20447780513
77
issue: 0
8-
python_version: 3.13.11
9-
library_version: 3.8.1
8+
python_version: '3.14.3'
9+
library_version: '3.8.2'
1010
preview_url: https://storage.googleapis.com/pyplots-images/plots/violin-basic/bokeh/plot.png
1111
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/violin-basic/bokeh/plot_thumb.png
1212
preview_html: https://storage.googleapis.com/pyplots-images/plots/violin-basic/bokeh/plot.html
13-
quality_score: 91
13+
quality_score: null
1414
impl_tags:
1515
dependencies: []
1616
techniques:

0 commit comments

Comments
 (0)