Skip to content

Commit 5f4f7fa

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

2 files changed

Lines changed: 126 additions & 0 deletions

File tree

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
""" pyplots.ai
2+
andrews-curves: Andrews Curves for Multivariate Data
3+
Library: letsplot 4.8.2 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-31
5+
"""
6+
7+
import numpy as np
8+
import pandas as pd
9+
from lets_plot import (
10+
LetsPlot,
11+
aes,
12+
element_text,
13+
geom_line,
14+
ggplot,
15+
ggsize,
16+
labs,
17+
scale_color_manual,
18+
scale_x_continuous,
19+
theme,
20+
theme_minimal,
21+
)
22+
from lets_plot.export import ggsave
23+
from sklearn.datasets import load_iris
24+
from sklearn.preprocessing import StandardScaler
25+
26+
27+
LetsPlot.setup_html()
28+
29+
# Load and prepare data
30+
iris = load_iris()
31+
X = iris.data
32+
y = iris.target
33+
feature_names = iris.feature_names
34+
target_names = iris.target_names
35+
36+
# Normalize variables to similar scales
37+
scaler = StandardScaler()
38+
X_scaled = scaler.fit_transform(X)
39+
40+
# Create DataFrame with normalized features and species
41+
df_features = pd.DataFrame(X_scaled, columns=feature_names)
42+
df_features["species"] = [target_names[i] for i in y]
43+
44+
# Andrews curves transformation
45+
# f(t) = x1/sqrt(2) + x2*sin(t) + x3*cos(t) + x4*sin(2t) + x5*cos(2t) + ...
46+
t_values = np.linspace(-np.pi, np.pi, 200)
47+
48+
curves_data = []
49+
for idx, row in df_features.iterrows():
50+
values = row[feature_names].values
51+
species = row["species"]
52+
53+
for t in t_values:
54+
# Fourier expansion
55+
y_val = values[0] / np.sqrt(2)
56+
for i in range(1, len(values)):
57+
if i % 2 == 1:
58+
y_val += values[i] * np.sin((i // 2 + 1) * t)
59+
else:
60+
y_val += values[i] * np.cos((i // 2) * t)
61+
62+
curves_data.append({"t": t, "y": y_val, "observation": idx, "species": species})
63+
64+
df_curves = pd.DataFrame(curves_data)
65+
66+
# Define colors for species - Python blue, yellow, and a third color
67+
species_colors = {"setosa": "#306998", "versicolor": "#FFD43B", "virginica": "#DC2626"}
68+
69+
# Create plot
70+
plot = (
71+
ggplot(df_curves, aes(x="t", y="y", group="observation", color="species"))
72+
+ geom_line(alpha=0.4, size=0.8)
73+
+ scale_color_manual(values=list(species_colors.values()))
74+
+ scale_x_continuous(breaks=[-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi], labels=["-π", "-π/2", "0", "π/2", "π"])
75+
+ labs(
76+
x="Parameter t (radians)",
77+
y="Fourier Function Value",
78+
title="andrews-curves · letsplot · pyplots.ai",
79+
color="Species",
80+
)
81+
+ theme_minimal()
82+
+ theme(
83+
axis_title=element_text(size=20),
84+
axis_text=element_text(size=16),
85+
plot_title=element_text(size=24),
86+
legend_title=element_text(size=18),
87+
legend_text=element_text(size=16),
88+
legend_position="right",
89+
)
90+
+ ggsize(1600, 900)
91+
)
92+
93+
# Save PNG (scale 3x to get 4800 × 2700 px)
94+
ggsave(plot, "plot.png", path=".", scale=3)
95+
96+
# Save HTML for interactivity
97+
ggsave(plot, "plot.html", path=".")
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
library: letsplot
2+
specification_id: andrews-curves
3+
created: '2025-12-31T21:36:48Z'
4+
updated: '2025-12-31T21:39:19Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20627522568
7+
issue: 2859
8+
python_version: 3.13.11
9+
library_version: 4.8.2
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/letsplot/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/letsplot/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/letsplot/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent implementation of Andrews curves Fourier transformation algorithm
17+
- Proper normalization of data using StandardScaler before transformation
18+
- Good use of transparency (alpha=0.4) for overlapping curves as recommended in
19+
spec
20+
- Clear cluster separation visible between species
21+
- Proper use of π symbols in x-axis tick labels
22+
- Correct title format following pyplots.ai convention
23+
- Clean, readable code structure
24+
- Both PNG and HTML outputs generated for interactivity
25+
weaknesses:
26+
- No visible grid lines to aid visual reference (theme_minimal may have removed
27+
them, but subtle grid would help)
28+
- Missing explicit random seed (though data is deterministic from sklearn, good
29+
practice to include)

0 commit comments

Comments
 (0)