Skip to content

Commit 84e4e86

Browse files
feat(bokeh): implement line-timeseries-rolling (#2808)
## Implementation: `line-timeseries-rolling` - bokeh Implements the **bokeh** version of `line-timeseries-rolling`. **File:** `plots/line-timeseries-rolling/implementations/bokeh.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20602451770)* --------- 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 d19752c commit 84e4e86

2 files changed

Lines changed: 121 additions & 0 deletions

File tree

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
""" pyplots.ai
2+
line-timeseries-rolling: Time Series with Rolling Average Overlay
3+
Library: bokeh 3.8.1 | Python 3.13.11
4+
Quality: 92/100 | Created: 2025-12-30
5+
"""
6+
7+
import numpy as np
8+
import pandas as pd
9+
from bokeh.io import export_png, output_file, save
10+
from bokeh.models import ColumnDataSource
11+
from bokeh.plotting import figure
12+
13+
14+
# Data - Simulated daily temperature readings over a year
15+
np.random.seed(42)
16+
n_days = 365
17+
dates = pd.date_range("2024-01-01", periods=n_days, freq="D")
18+
19+
# Create realistic temperature data with seasonal pattern and noise
20+
day_of_year = np.arange(n_days)
21+
seasonal_pattern = 15 * np.sin(2 * np.pi * (day_of_year - 80) / 365) + 20 # Peak in summer
22+
noise = np.random.normal(0, 3, n_days)
23+
temperature = seasonal_pattern + noise
24+
25+
# Calculate 30-day rolling average
26+
rolling_window = 30
27+
rolling_avg = pd.Series(temperature).rolling(window=rolling_window, center=True).mean()
28+
29+
# Create DataFrame
30+
df = pd.DataFrame({"date": dates, "value": temperature, "rolling_avg": rolling_avg})
31+
32+
# Create ColumnDataSource for raw data
33+
source_raw = ColumnDataSource(data={"date": df["date"], "value": df["value"]})
34+
35+
# Create ColumnDataSource for rolling average (exclude NaN values)
36+
df_rolling = df.dropna(subset=["rolling_avg"])
37+
source_rolling = ColumnDataSource(data={"date": df_rolling["date"], "rolling_avg": df_rolling["rolling_avg"]})
38+
39+
# Create figure - 4800 × 2700 px (16:9 landscape)
40+
p = figure(
41+
width=4800,
42+
height=2700,
43+
title="line-timeseries-rolling · bokeh · pyplots.ai",
44+
x_axis_label="Date",
45+
y_axis_label="Temperature (°C)",
46+
x_axis_type="datetime",
47+
tools="pan,wheel_zoom,box_zoom,reset,save",
48+
)
49+
50+
# Plot raw data - thin line with transparency
51+
raw_line = p.line(
52+
x="date", y="value", source=source_raw, line_width=2, line_alpha=0.5, line_color="#306998", legend_label="Raw Data"
53+
)
54+
55+
# Plot rolling average - prominent smooth line
56+
rolling_line = p.line(
57+
x="date",
58+
y="rolling_avg",
59+
source=source_rolling,
60+
line_width=4,
61+
line_color="#FFD43B",
62+
legend_label=f"{rolling_window}-Day Rolling Average",
63+
)
64+
65+
# Styling for large canvas
66+
p.title.text_font_size = "28pt"
67+
p.xaxis.axis_label_text_font_size = "22pt"
68+
p.yaxis.axis_label_text_font_size = "22pt"
69+
p.xaxis.major_label_text_font_size = "18pt"
70+
p.yaxis.major_label_text_font_size = "18pt"
71+
72+
# Grid styling - subtle
73+
p.xgrid.grid_line_alpha = 0.3
74+
p.ygrid.grid_line_alpha = 0.3
75+
p.xgrid.grid_line_dash = [6, 4]
76+
p.ygrid.grid_line_dash = [6, 4]
77+
78+
# Legend styling
79+
p.legend.label_text_font_size = "18pt"
80+
p.legend.location = "top_left"
81+
p.legend.background_fill_alpha = 0.8
82+
p.legend.border_line_alpha = 0.3
83+
84+
# Background
85+
p.background_fill_color = "#fafafa"
86+
87+
# Save as PNG
88+
export_png(p, filename="plot.png")
89+
90+
# Save as HTML for interactive version
91+
output_file("plot.html")
92+
save(p)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
library: bokeh
2+
specification_id: line-timeseries-rolling
3+
created: '2025-12-30T17:48:24Z'
4+
updated: '2025-12-30T17:56:16Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20602451770
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: 3.8.1
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/line-timeseries-rolling/bokeh/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/line-timeseries-rolling/bokeh/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/line-timeseries-rolling/bokeh/plot.html
13+
quality_score: 92
14+
review:
15+
strengths:
16+
- Excellent visual distinction between raw data (blue, semi-transparent) and rolling
17+
average (yellow, prominent)
18+
- Realistic temperature scenario with clear seasonal pattern that demonstrates the
19+
value of rolling averages
20+
- Proper handling of NaN values at rolling window boundaries by creating separate
21+
data sources
22+
- Interactive tools included (pan, wheel_zoom, box_zoom, reset, save) and HTML output
23+
generated
24+
- Clean KISS code structure following Bokeh best practices with ColumnDataSource
25+
weaknesses:
26+
- Legend text appears small at the top left corner when viewing the full-resolution
27+
image
28+
- Could add HoverTool to display exact date and temperature values on hover for
29+
better interactivity

0 commit comments

Comments
 (0)