Skip to content

Commit 1cc95dc

Browse files
feat(altair): implement line-annotated-events (#3010)
## Implementation: `line-annotated-events` - altair Implements the **altair** version of `line-annotated-events`. **File:** `plots/line-annotated-events/implementations/altair.py` **Parent Issue:** #2997 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20617491440)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 8f374e5 commit 1cc95dc

2 files changed

Lines changed: 130 additions & 0 deletions

File tree

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
""" pyplots.ai
2+
line-annotated-events: Annotated Line Plot with Event Markers
3+
Library: altair 6.0.0 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-31
5+
"""
6+
7+
import altair as alt
8+
import numpy as np
9+
import pandas as pd
10+
11+
12+
# Data
13+
np.random.seed(42)
14+
15+
# Generate daily stock price data for one year
16+
dates = pd.date_range(start="2024-01-01", periods=250, freq="B") # Business days
17+
base_price = 150
18+
returns = np.random.normal(0.0005, 0.015, len(dates))
19+
prices = base_price * np.exp(np.cumsum(returns))
20+
21+
df = pd.DataFrame({"date": dates, "price": prices})
22+
23+
# Define key events (quarterly earnings and other milestones)
24+
events = pd.DataFrame(
25+
{
26+
"event_date": pd.to_datetime(
27+
["2024-02-15", "2024-04-25", "2024-06-10", "2024-07-24", "2024-09-18", "2024-11-05"]
28+
),
29+
"event_label": [
30+
"Q4 Earnings",
31+
"Q1 Earnings",
32+
"Product Launch",
33+
"Q2 Earnings",
34+
"Analyst Upgrade",
35+
"Q3 Earnings",
36+
],
37+
}
38+
)
39+
40+
# Get y positions for event labels (alternating heights to avoid overlap)
41+
events["y_position"] = [
42+
prices.max() * 1.08,
43+
prices.max() * 1.02,
44+
prices.max() * 1.08,
45+
prices.max() * 1.02,
46+
prices.max() * 1.08,
47+
prices.max() * 1.02,
48+
]
49+
50+
# Base line chart for stock price
51+
line = (
52+
alt.Chart(df)
53+
.mark_line(strokeWidth=3, color="#306998")
54+
.encode(
55+
x=alt.X("date:T", title="Date", axis=alt.Axis(labelFontSize=18, titleFontSize=22)),
56+
y=alt.Y(
57+
"price:Q",
58+
title="Stock Price ($)",
59+
scale=alt.Scale(domain=[prices.min() * 0.95, prices.max() * 1.12]),
60+
axis=alt.Axis(labelFontSize=18, titleFontSize=22),
61+
),
62+
)
63+
)
64+
65+
# Vertical rule marks for events
66+
rules = (
67+
alt.Chart(events)
68+
.mark_rule(strokeWidth=2, strokeDash=[6, 4], color="#FFD43B")
69+
.encode(x=alt.X("event_date:T"), y=alt.value(0), y2=alt.value(900))
70+
)
71+
72+
# Event markers (points at the top)
73+
markers = (
74+
alt.Chart(events)
75+
.mark_point(size=300, filled=True, color="#FFD43B", stroke="#306998", strokeWidth=2)
76+
.encode(x=alt.X("event_date:T"), y=alt.Y("y_position:Q"))
77+
)
78+
79+
# Event labels
80+
labels = (
81+
alt.Chart(events)
82+
.mark_text(align="center", baseline="bottom", fontSize=16, fontWeight="bold", color="#333333", dy=-15)
83+
.encode(x=alt.X("event_date:T"), y=alt.Y("y_position:Q"), text="event_label:N")
84+
)
85+
86+
# Combine all layers
87+
chart = (
88+
alt.layer(line, rules, markers, labels)
89+
.properties(
90+
width=1600,
91+
height=900,
92+
title=alt.Title("line-annotated-events · altair · pyplots.ai", fontSize=28, anchor="middle"),
93+
)
94+
.configure_view(strokeWidth=0)
95+
.configure_axis(labelFontSize=18, titleFontSize=22, gridColor="#cccccc", gridOpacity=0.3)
96+
)
97+
98+
# Save as PNG
99+
chart.save("plot.png", scale_factor=3.0)
100+
101+
# Save interactive HTML version
102+
chart.interactive().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: line-annotated-events
3+
created: '2025-12-31T10:54:27Z'
4+
updated: '2025-12-31T10:59:34Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20617491440
7+
issue: 2997
8+
python_version: 3.13.11
9+
library_version: 6.0.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/line-annotated-events/altair/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/line-annotated-events/altair/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/line-annotated-events/altair/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent use of alternating y-positions for event labels to prevent overlap
17+
- Clean layered chart composition with separate charts for line, rules, markers,
18+
and labels
19+
- Good color scheme with Python blue (#306998) and contrasting yellow (#FFD43B)
20+
- Realistic stock price data with appropriate volatility
21+
- Proper use of Altair encoding types (:T, :Q, :N)
22+
- Both PNG and interactive HTML outputs generated
23+
weaknesses:
24+
- Missing legend/key for event types as suggested in spec notes
25+
- Vertical rules use hardcoded y2=alt.value(900) which may not align with actual
26+
chart height
27+
- No tooltips on event markers for interactivity (missed opportunity for Altair's
28+
strength)

0 commit comments

Comments
 (0)