Skip to content

Commit 2ab64f8

Browse files
feat(bokeh): implement scatter-regression-lowess (#2874)
## Implementation: `scatter-regression-lowess` - bokeh Implements the **bokeh** version of `scatter-regression-lowess`. **File:** `plots/scatter-regression-lowess/implementations/bokeh.py` **Parent Issue:** #2855 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20608462380)* --------- 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 f3a8a46 commit 2ab64f8

2 files changed

Lines changed: 96 additions & 0 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
""" pyplots.ai
2+
scatter-regression-lowess: Scatter Plot with LOWESS Regression
3+
Library: bokeh 3.8.1 | Python 3.13.11
4+
Quality: 92/100 | Created: 2025-12-30
5+
"""
6+
7+
import numpy as np
8+
from bokeh.io import export_png, save
9+
from bokeh.models import ColumnDataSource
10+
from bokeh.plotting import figure
11+
from bokeh.resources import CDN
12+
from statsmodels.nonparametric.smoothers_lowess import lowess
13+
14+
15+
# Data: Simulate a complex non-linear relationship (e.g., temperature vs enzyme activity)
16+
np.random.seed(42)
17+
n = 200
18+
19+
# Create x values (temperature in Celsius)
20+
x = np.linspace(10, 50, n) + np.random.normal(0, 1, n)
21+
x = np.sort(x)
22+
23+
# Create y with complex non-linear relationship (enzyme activity %)
24+
# Activity increases, peaks around 35°C, then decreases (typical enzyme behavior)
25+
y_true = 20 + 60 * np.exp(-0.5 * ((x - 35) / 8) ** 2) # Gaussian peak
26+
y = y_true + np.random.normal(0, 5, n) # Add noise
27+
28+
# Calculate LOWESS regression
29+
lowess_result = lowess(y, x, frac=0.4)
30+
x_lowess = lowess_result[:, 0]
31+
y_lowess = lowess_result[:, 1]
32+
33+
# Create figure
34+
p = figure(
35+
width=4800,
36+
height=2700,
37+
title="scatter-regression-lowess · bokeh · pyplots.ai",
38+
x_axis_label="Temperature (°C)",
39+
y_axis_label="Enzyme Activity (%)",
40+
)
41+
42+
# Scatter points
43+
source_scatter = ColumnDataSource(data={"x": x, "y": y})
44+
p.scatter(x="x", y="y", source=source_scatter, size=18, color="#306998", alpha=0.6, legend_label="Data Points")
45+
46+
# LOWESS curve
47+
source_lowess = ColumnDataSource(data={"x": x_lowess, "y": y_lowess})
48+
p.line(x="x", y="y", source=source_lowess, line_width=5, color="#FFD43B", legend_label="LOWESS Fit")
49+
50+
# Styling - larger text for 4800x2700 canvas
51+
p.title.text_font_size = "36pt"
52+
p.xaxis.axis_label_text_font_size = "28pt"
53+
p.yaxis.axis_label_text_font_size = "28pt"
54+
p.xaxis.major_label_text_font_size = "22pt"
55+
p.yaxis.major_label_text_font_size = "22pt"
56+
57+
# Grid styling
58+
p.grid.grid_line_alpha = 0.3
59+
p.grid.grid_line_dash = "dashed"
60+
61+
# Legend styling
62+
p.legend.label_text_font_size = "22pt"
63+
p.legend.location = "top_right"
64+
p.legend.background_fill_alpha = 0.8
65+
66+
# Save outputs
67+
export_png(p, filename="plot.png")
68+
save(p, filename="plot.html", resources=CDN, title="scatter-regression-lowess")
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
library: bokeh
2+
specification_id: scatter-regression-lowess
3+
created: '2025-12-30T23:53:54Z'
4+
updated: '2025-12-30T23:58:02Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20608462380
7+
issue: 2855
8+
python_version: 3.13.11
9+
library_version: 3.8.1
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/scatter-regression-lowess/bokeh/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/scatter-regression-lowess/bokeh/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/scatter-regression-lowess/bokeh/plot.html
13+
quality_score: 92
14+
review:
15+
strengths:
16+
- Excellent biological data example (enzyme activity curve) that perfectly demonstrates
17+
LOWESS smoothing on non-linear data
18+
- Clean color contrast between blue points and yellow LOWESS curve makes the relationship
19+
immediately clear
20+
- Proper use of ColumnDataSource pattern for data management
21+
- Text sizing scaled appropriately for 4800x2700 canvas
22+
- Correctly uses statsmodels LOWESS with appropriate smoothing fraction (0.4)
23+
- Generates both static PNG and interactive HTML output
24+
weaknesses:
25+
- Legend text could be larger to match the canvas scale (currently 22pt vs 28pt
26+
axis labels)
27+
- Could add HoverTool to show individual point values in interactive version
28+
- Grid dashed style may be unnecessary - solid subtle lines would be cleaner

0 commit comments

Comments
 (0)