Skip to content

Commit 7ace0ba

Browse files
feat(pygal): implement scatter-regression-lowess (#2878)
## Implementation: `scatter-regression-lowess` - pygal Implements the **pygal** version of `scatter-regression-lowess`. **File:** `plots/scatter-regression-lowess/implementations/pygal.py` **Parent Issue:** #2855 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20608464403)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 25e270a commit 7ace0ba

2 files changed

Lines changed: 105 additions & 0 deletions

File tree

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
""" pyplots.ai
2+
scatter-regression-lowess: Scatter Plot with LOWESS Regression
3+
Library: pygal 3.1.0 | Python 3.13.11
4+
Quality: 90/100 | Created: 2025-12-30
5+
"""
6+
7+
import numpy as np
8+
import pygal
9+
from pygal.style import Style
10+
from statsmodels.nonparametric.smoothers_lowess import lowess
11+
12+
13+
# Data - Drug dose-response relationship with non-linear effect
14+
# Simulates enzyme activity response to varying drug concentrations
15+
np.random.seed(42)
16+
n_points = 150
17+
18+
# Drug concentration in mg/L (log-spaced for pharmacological realism)
19+
concentration = np.linspace(0.1, 50, n_points)
20+
21+
# Enzyme activity response: sigmoidal with saturation and hormesis effect
22+
# Low doses show slight stimulation, mid-range shows increase, high doses plateau
23+
base_response = 25 + 55 * (1 - np.exp(-concentration / 8)) - 10 * np.exp(-concentration / 3)
24+
noise = np.random.normal(0, 4, n_points)
25+
activity = base_response + noise
26+
27+
# Calculate LOWESS smoothed curve
28+
lowess_result = lowess(activity, concentration, frac=0.35, return_sorted=True)
29+
conc_smooth = lowess_result[:, 0]
30+
activity_smooth = lowess_result[:, 1]
31+
32+
# Custom style for large canvas with increased font sizes
33+
custom_style = Style(
34+
background="white",
35+
plot_background="white",
36+
foreground="#333333",
37+
foreground_strong="#333333",
38+
foreground_subtle="#666666",
39+
colors=("#306998", "#FFD43B", "#E74C3C"),
40+
title_font_size=56,
41+
label_font_size=42,
42+
major_label_font_size=32,
43+
legend_font_size=32,
44+
value_font_size=28,
45+
stroke_width=5,
46+
opacity=0.6,
47+
opacity_hover=0.9,
48+
)
49+
50+
# Create XY chart for scatter plot
51+
chart = pygal.XY(
52+
width=4800,
53+
height=2700,
54+
style=custom_style,
55+
title="scatter-regression-lowess · pygal · pyplots.ai",
56+
x_title="Drug Concentration (mg/L)",
57+
y_title="Enzyme Activity (%)",
58+
show_dots=True,
59+
dots_size=8,
60+
stroke=False,
61+
show_x_guides=True,
62+
show_y_guides=True,
63+
legend_at_bottom=True,
64+
legend_at_bottom_columns=2,
65+
)
66+
67+
# Add scatter points (as XY data with no stroke)
68+
scatter_data = list(zip(concentration, activity, strict=True))
69+
chart.add("Observed Response", scatter_data, stroke=False, dots_size=10)
70+
71+
# Add LOWESS curve (as line with no dots)
72+
lowess_data = list(zip(conc_smooth, activity_smooth, strict=True))
73+
chart.add("LOWESS Fit (frac=0.35)", lowess_data, stroke=True, show_dots=False, stroke_style={"width": 6})
74+
75+
# Save as PNG and SVG/HTML
76+
chart.render_to_png("plot.png")
77+
chart.render_to_file("plot.html")
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
library: pygal
2+
specification_id: scatter-regression-lowess
3+
created: '2025-12-30T23:54:43Z'
4+
updated: '2025-12-31T00:10:44Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20608464403
7+
issue: 2855
8+
python_version: 3.13.11
9+
library_version: 3.1.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/scatter-regression-lowess/pygal/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/scatter-regression-lowess/pygal/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/scatter-regression-lowess/pygal/plot.html
13+
quality_score: 90
14+
review:
15+
strengths:
16+
- LOWESS curve is visually distinct from scatter points with good color contrast
17+
(blue vs yellow)
18+
- Clean code structure following KISS principles with proper use of statsmodels
19+
for LOWESS calculation
20+
- Custom pygal Style properly configured for large canvas with appropriate font
21+
sizes
22+
- Correct title format following spec-id · library · pyplots.ai convention
23+
- Good use of transparency (opacity=0.6) for scatter points to show density
24+
- Appropriate LOWESS smoothing parameter (frac=0.35) within recommended range
25+
weaknesses:
26+
- Axis labels in rendered output are generic (X Value, Y Value) rather than the
27+
domain-specific labels defined in the code
28+
- Legend entries in output differ from code-defined labels

0 commit comments

Comments
 (0)