Skip to content

Commit 676f2ac

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

2 files changed

Lines changed: 116 additions & 0 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
""" pyplots.ai
2+
andrews-curves: Andrews Curves for Multivariate Data
3+
Library: altair 6.0.0 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-30
5+
"""
6+
7+
import altair as alt
8+
import numpy as np
9+
import pandas as pd
10+
from sklearn.datasets import load_iris
11+
from sklearn.preprocessing import StandardScaler
12+
13+
14+
# Set random seed for reproducibility
15+
np.random.seed(42)
16+
17+
# Load and prepare data
18+
iris = load_iris()
19+
X = iris.data
20+
y = iris.target
21+
species_names = ["Setosa", "Versicolor", "Virginica"]
22+
23+
# Normalize variables to similar scales
24+
scaler = StandardScaler()
25+
X_scaled = scaler.fit_transform(X)
26+
27+
# Andrews curve transformation
28+
# f(t) = x1/sqrt(2) + x2*sin(t) + x3*cos(t) + x4*sin(2t) + x5*cos(2t) + ...
29+
n_points = 100
30+
t = np.linspace(-np.pi, np.pi, n_points)
31+
32+
# Compute Andrews curves for each observation
33+
curves_data = []
34+
for obs_idx in range(len(X_scaled)):
35+
x = X_scaled[obs_idx]
36+
curve = np.zeros(n_points)
37+
curve += x[0] / np.sqrt(2)
38+
39+
for i in range(1, len(x)):
40+
freq = (i + 1) // 2
41+
if i % 2 == 1:
42+
curve += x[i] * np.sin(freq * t)
43+
else:
44+
curve += x[i] * np.cos(freq * t)
45+
46+
for pt_idx in range(n_points):
47+
curves_data.append(
48+
{"t": t[pt_idx], "value": curve[pt_idx], "observation": obs_idx, "species": species_names[y[obs_idx]]}
49+
)
50+
51+
df = pd.DataFrame(curves_data)
52+
53+
# Define colors for species
54+
species_colors = ["#306998", "#FFD43B", "#6B8E23"]
55+
56+
# Create chart
57+
chart = (
58+
alt.Chart(df)
59+
.mark_line(opacity=0.4, strokeWidth=2)
60+
.encode(
61+
x=alt.X("t:Q", title="t (radians)", axis=alt.Axis(labelFontSize=18, titleFontSize=22)),
62+
y=alt.Y("value:Q", title="Andrews Curve Value", axis=alt.Axis(labelFontSize=18, titleFontSize=22)),
63+
color=alt.Color(
64+
"species:N",
65+
title="Species",
66+
scale=alt.Scale(domain=["Setosa", "Versicolor", "Virginica"], range=species_colors),
67+
legend=alt.Legend(titleFontSize=22, labelFontSize=20),
68+
),
69+
detail="observation:N",
70+
)
71+
.properties(
72+
width=1600,
73+
height=900,
74+
title=alt.Title(
75+
"Iris Classification · andrews-curves · altair · pyplots.ai",
76+
fontSize=28,
77+
subtitle="Fourier series transformation of multivariate data for visual pattern comparison",
78+
subtitleFontSize=18,
79+
),
80+
)
81+
.configure_axis(labelFontSize=18, titleFontSize=22)
82+
.configure_view(strokeWidth=0)
83+
.configure_title(fontSize=28)
84+
)
85+
86+
# Save as PNG and HTML
87+
chart.save("plot.png", scale_factor=3.0)
88+
chart.save("plot.html")
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
library: altair
2+
specification_id: andrews-curves
3+
created: '2025-12-30T23:57:49Z'
4+
updated: '2025-12-31T00:17:13Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20608497564
7+
issue: 2859
8+
python_version: 3.13.11
9+
library_version: 6.0.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/altair/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/altair/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/andrews-curves/altair/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Correct Fourier series implementation for Andrews curves transformation
17+
- Clear visual separation between iris species demonstrating the clustering capability
18+
- Proper data normalization using StandardScaler as recommended in spec
19+
- Clean, declarative Altair code with appropriate encoding types
20+
- Title format follows the required spec-id · library · pyplots.ai pattern with
21+
informative subtitle
22+
- Good use of transparency (opacity=0.4) for overlapping curves as recommended
23+
weaknesses:
24+
- Legend could benefit from a semi-transparent background for better contrast against
25+
the curves
26+
- Yellow color (#FFD43B) could be slightly less bright for better visibility on
27+
white background
28+
- Could add tooltips to enable interactive exploration of individual observations

0 commit comments

Comments
 (0)