Skip to content

Commit b671b96

Browse files
feat(bokeh): implement andrews-curves (#2894)
## Implementation: `andrews-curves` - bokeh Implements the **bokeh** version of `andrews-curves`. **File:** `plots/andrews-curves/implementations/bokeh.py` **Parent Issue:** #2859 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20608492713)* --------- 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 b1182e2 commit b671b96

2 files changed

Lines changed: 128 additions & 0 deletions

File tree

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
""" pyplots.ai
2+
andrews-curves: Andrews Curves for Multivariate Data
3+
Library: bokeh 3.8.1 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-30
5+
"""
6+
7+
import numpy as np
8+
from bokeh.io import export_png, output_file, save
9+
from bokeh.models import ColumnDataSource, Legend
10+
from bokeh.plotting import figure
11+
from sklearn.datasets import load_iris
12+
from sklearn.preprocessing import StandardScaler
13+
14+
15+
# Load and prepare data
16+
iris = load_iris()
17+
X = iris.data
18+
y = iris.target
19+
species_names = ["Setosa", "Versicolor", "Virginica"]
20+
21+
# Normalize variables to similar scales
22+
scaler = StandardScaler()
23+
X_scaled = scaler.fit_transform(X)
24+
25+
26+
# Andrews curve function: f(t) = x1/sqrt(2) + x2*sin(t) + x3*cos(t) + x4*sin(2t) + ...
27+
def andrews_curve(coeffs, t):
28+
n = len(coeffs)
29+
result = coeffs[0] / np.sqrt(2)
30+
for i in range(1, n):
31+
if i % 2 == 1:
32+
result += coeffs[i] * np.sin((i // 2 + 1) * t)
33+
else:
34+
result += coeffs[i] * np.cos((i // 2) * t)
35+
return result
36+
37+
38+
# Generate t values from -π to π
39+
t_values = np.linspace(-np.pi, np.pi, 200)
40+
41+
# Colors for each species (Python Blue, Python Yellow, and a colorblind-safe teal)
42+
colors = ["#306998", "#FFD43B", "#2AA198"]
43+
44+
# Create figure
45+
p = figure(
46+
width=4800,
47+
height=2700,
48+
title="andrews-curves · bokeh · pyplots.ai",
49+
x_axis_label="t (radians)",
50+
y_axis_label="f(t)",
51+
)
52+
53+
# Store legend items
54+
legend_items = []
55+
56+
# Plot curves for each species
57+
for species_idx in range(3):
58+
species_mask = y == species_idx
59+
X_species = X_scaled[species_mask]
60+
61+
# Track first line for legend
62+
first_line = None
63+
64+
for coeffs in X_species:
65+
curve_values = andrews_curve(coeffs, t_values)
66+
67+
source = ColumnDataSource(data={"x": t_values, "y": curve_values})
68+
69+
line = p.line(x="x", y="y", source=source, line_color=colors[species_idx], line_alpha=0.4, line_width=2)
70+
71+
if first_line is None:
72+
first_line = line
73+
74+
legend_items.append((species_names[species_idx], [first_line]))
75+
76+
# Create and add legend
77+
legend = Legend(items=legend_items, location="top_right")
78+
legend.label_text_font_size = "20pt"
79+
legend.background_fill_alpha = 0.8
80+
p.add_layout(legend, "right")
81+
82+
# Style the plot
83+
p.title.text_font_size = "28pt"
84+
p.xaxis.axis_label_text_font_size = "22pt"
85+
p.yaxis.axis_label_text_font_size = "22pt"
86+
p.xaxis.major_label_text_font_size = "18pt"
87+
p.yaxis.major_label_text_font_size = "18pt"
88+
89+
# Grid styling
90+
p.xgrid.grid_line_alpha = 0.3
91+
p.ygrid.grid_line_alpha = 0.3
92+
p.xgrid.grid_line_dash = "dashed"
93+
p.ygrid.grid_line_dash = "dashed"
94+
95+
# Save as PNG and HTML
96+
export_png(p, filename="plot.png")
97+
output_file("plot.html", title="Andrews Curves - Bokeh")
98+
save(p)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library: bokeh
2+
specification_id: andrews-curves
3+
created: '2025-12-30T23:57:27Z'
4+
updated: '2025-12-31T00:04:51Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20608492713
7+
issue: 2859
8+
python_version: 3.13.11
9+
library_version: 3.8.1
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/bokeh/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/bokeh/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/bokeh/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent implementation of the Andrews curves mathematical transformation with
17+
correct Fourier expansion
18+
- Perfect use of the Iris dataset as a canonical multivariate example demonstrating
19+
clear cluster separation
20+
- Good application of StandardScaler for normalization as recommended in the specification
21+
- Appropriate transparency (alpha=0.4) reveals density patterns where curves overlap
22+
- Colorblind-safe palette with good distinction between species
23+
- Correct title format following pyplots.ai conventions
24+
- Both PNG and HTML outputs generated, leveraging Bokeh dual output capability
25+
weaknesses:
26+
- Contains a helper function (andrews_curve) which deviates from strict KISS structure;
27+
the Fourier computation could be vectorized inline
28+
- Legend background could have slightly higher opacity for better readability
29+
- Does not leverage Bokeh interactive features like hover tooltips which would enhance
30+
the visualization

0 commit comments

Comments
 (0)