Skip to content

Commit ba73289

Browse files
Merge remote-tracking branch 'origin/main'
2 parents 37705e8 + 5ec5467 commit ba73289

File tree

24 files changed

+3559
-0
lines changed

24 files changed

+3559
-0
lines changed
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: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
""" pyplots.ai
2+
andrews-curves: Andrews Curves for Multivariate Data
3+
Library: plotly 6.5.0 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-31
5+
"""
6+
7+
import numpy as np
8+
import plotly.graph_objects as go
9+
from sklearn.datasets import load_iris
10+
11+
12+
# Data - Load Iris dataset
13+
iris = load_iris()
14+
X = iris.data # 150 samples, 4 features
15+
y = iris.target
16+
species_names = ["Setosa", "Versicolor", "Virginica"]
17+
colors = ["#306998", "#FFD43B", "#E74C3C"] # Python Blue, Python Yellow, Red
18+
19+
# Normalize data to prevent dominant variables
20+
X_normalized = (X - X.mean(axis=0)) / X.std(axis=0)
21+
22+
# Andrews curve transformation
23+
# f(t) = x1/sqrt(2) + x2*sin(t) + x3*cos(t) + x4*sin(2t) + x5*cos(2t) + ...
24+
t = np.linspace(-np.pi, np.pi, 200)
25+
26+
27+
def andrews_curve(x, t_vals):
28+
"""Transform a single observation to Andrews curve values."""
29+
n_features = len(x)
30+
curve = np.ones_like(t_vals) * x[0] / np.sqrt(2)
31+
for i in range(1, n_features):
32+
freq = (i + 1) // 2
33+
if i % 2 == 1:
34+
curve += x[i] * np.sin(freq * t_vals)
35+
else:
36+
curve += x[i] * np.cos(freq * t_vals)
37+
return curve
38+
39+
40+
# Create figure
41+
fig = go.Figure()
42+
43+
# Plot Andrews curves for each sample, colored by species
44+
for species_idx in range(3):
45+
species_mask = y == species_idx
46+
X_species = X_normalized[species_mask]
47+
48+
for i, x in enumerate(X_species):
49+
curve_y = andrews_curve(x, t)
50+
fig.add_trace(
51+
go.Scatter(
52+
x=t,
53+
y=curve_y,
54+
mode="lines",
55+
line=dict(color=colors[species_idx], width=2),
56+
opacity=0.4,
57+
name=species_names[species_idx],
58+
legendgroup=species_names[species_idx],
59+
showlegend=(i == 0), # Only show legend for first curve of each species
60+
hovertemplate=f"{species_names[species_idx]}<br>t: %{{x:.2f}}<br>f(t): %{{y:.2f}}<extra></extra>",
61+
)
62+
)
63+
64+
# Update layout for 4800x2700 canvas
65+
fig.update_layout(
66+
title=dict(text="Iris Dataset · andrews-curves · plotly · pyplots.ai", font=dict(size=32), x=0.5, xanchor="center"),
67+
xaxis=dict(
68+
title=dict(text="Parameter t (radians)", font=dict(size=24)),
69+
tickfont=dict(size=18),
70+
gridcolor="rgba(128, 128, 128, 0.3)",
71+
gridwidth=1,
72+
zeroline=True,
73+
zerolinecolor="rgba(128, 128, 128, 0.5)",
74+
zerolinewidth=1,
75+
range=[-np.pi, np.pi],
76+
tickvals=[-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi],
77+
ticktext=["-π", "-π/2", "0", "π/2", "π"],
78+
),
79+
yaxis=dict(
80+
title=dict(text="f(t) (normalized units)", font=dict(size=24)),
81+
tickfont=dict(size=18),
82+
gridcolor="rgba(128, 128, 128, 0.3)",
83+
gridwidth=1,
84+
zeroline=True,
85+
zerolinecolor="rgba(128, 128, 128, 0.5)",
86+
zerolinewidth=1,
87+
),
88+
template="plotly_white",
89+
legend=dict(
90+
font=dict(size=20),
91+
x=0.98,
92+
y=0.98,
93+
xanchor="right",
94+
yanchor="top",
95+
bgcolor="rgba(255, 255, 255, 0.8)",
96+
bordercolor="rgba(128, 128, 128, 0.3)",
97+
borderwidth=1,
98+
),
99+
margin=dict(l=100, r=80, t=100, b=80),
100+
plot_bgcolor="white",
101+
paper_bgcolor="white",
102+
)
103+
104+
# Save as PNG (4800 x 2700 px)
105+
fig.write_image("plot.png", width=1600, height=900, scale=3)
106+
107+
# Save interactive HTML version
108+
fig.write_html("plot.html", include_plotlyjs=True, full_html=True)
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)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
library: plotly
2+
specification_id: andrews-curves
3+
created: '2025-12-31T21:34:18Z'
4+
updated: '2025-12-31T21:36:51Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20627521331
7+
issue: 2859
8+
python_version: 3.13.11
9+
library_version: 6.5.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/plotly/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/plotly/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/plotly/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent implementation of the Fourier transformation formula for Andrews curves
17+
- Perfect use of transparency (alpha=0.4) to reveal curve density and overlap patterns
18+
- Clear visual separation between Iris species demonstrates the technique utility
19+
- 'Professional use of Plotly features: legendgroup for grouped legend entries,
20+
custom hover templates'
21+
- Proper data normalization prevents any single variable from dominating the curves
22+
- Clean π notation on x-axis tick labels enhances readability
23+
- Dual output (PNG + HTML) maximizes value for both static and interactive use cases
24+
weaknesses:
25+
- Code contains a helper function andrews_curve() violating the KISS no functions
26+
rule; should inline the transformation logic
27+
- Yellow color for Versicolor may be less distinguishable for colorblind users;
28+
consider using a more accessible palette

0 commit comments

Comments
 (0)