Skip to content

Commit 790fc31

Browse files
feat(bokeh): implement timeline-basic (#2461)
## Implementation: `timeline-basic` - bokeh Implements the **bokeh** version of `timeline-basic`. **File:** `plots/timeline-basic/implementations/bokeh.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20584329995)* --------- 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 453fe78 commit 790fc31

2 files changed

Lines changed: 162 additions & 0 deletions

File tree

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
""" pyplots.ai
2+
timeline-basic: Event Timeline
3+
Library: bokeh 3.8.1 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-29
5+
"""
6+
7+
import pandas as pd
8+
from bokeh.io import export_png, output_file, save
9+
from bokeh.models import ColumnDataSource, Label
10+
from bokeh.palettes import Category10
11+
from bokeh.plotting import figure
12+
13+
14+
# Data - Software project milestones
15+
events = [
16+
("2024-01-15", "Project Kickoff", "Planning"),
17+
("2024-02-01", "Requirements Complete", "Planning"),
18+
("2024-03-10", "Design Review", "Design"),
19+
("2024-04-20", "Prototype Ready", "Development"),
20+
("2024-05-15", "Alpha Release", "Development"),
21+
("2024-06-30", "Beta Testing", "Testing"),
22+
("2024-07-25", "Bug Fix Sprint", "Testing"),
23+
("2024-08-15", "Performance Audit", "Testing"),
24+
("2024-09-10", "Security Review", "Release"),
25+
("2024-10-01", "v1.0 Launch", "Release"),
26+
]
27+
28+
df = pd.DataFrame(events, columns=["date", "event", "category"])
29+
df["date"] = pd.to_datetime(df["date"])
30+
31+
# Assign alternating y positions for label readability (above/below axis)
32+
df["y_pos"] = [0.6 if i % 2 == 0 else -0.6 for i in range(len(df))]
33+
34+
# Category colors
35+
categories = df["category"].unique().tolist()
36+
color_map = {cat: Category10[10][i] for i, cat in enumerate(categories)}
37+
df["color"] = df["category"].map(color_map)
38+
39+
# Create figure
40+
p = figure(
41+
width=4800,
42+
height=2700,
43+
title="timeline-basic · bokeh · pyplots.ai",
44+
x_axis_type="datetime",
45+
y_range=(-1.5, 1.5),
46+
tools="",
47+
toolbar_location=None,
48+
)
49+
50+
# Draw the central timeline axis (horizontal line)
51+
p.line(
52+
x=[df["date"].min() - pd.Timedelta(days=10), df["date"].max() + pd.Timedelta(days=10)],
53+
y=[0, 0],
54+
line_width=6,
55+
line_color="#306998",
56+
line_alpha=0.8,
57+
)
58+
59+
# Draw vertical connector lines and markers for each event
60+
for _, row in df.iterrows():
61+
# Vertical connector line from axis to marker
62+
p.line(x=[row["date"], row["date"]], y=[0, row["y_pos"]], line_width=3, line_color=row["color"], line_alpha=0.7)
63+
64+
# Plot event markers with category colors
65+
for cat in categories:
66+
cat_df = df[df["category"] == cat]
67+
cat_source = ColumnDataSource(cat_df)
68+
p.scatter(
69+
x="date",
70+
y="y_pos",
71+
source=cat_source,
72+
size=35,
73+
color=color_map[cat],
74+
alpha=0.9,
75+
marker="circle",
76+
legend_label=cat,
77+
line_color="white",
78+
line_width=3,
79+
)
80+
81+
# Add event labels manually with proper positioning
82+
for _, row in df.iterrows():
83+
y_offset = 80 if row["y_pos"] > 0 else -80
84+
baseline = "bottom" if row["y_pos"] > 0 else "top"
85+
label = Label(
86+
x=row["date"],
87+
y=row["y_pos"],
88+
text=row["event"],
89+
text_font_size="18pt",
90+
text_color="#333333",
91+
text_align="center",
92+
text_baseline=baseline,
93+
y_offset=y_offset,
94+
)
95+
p.add_layout(label)
96+
97+
# Style the plot
98+
p.title.text_font_size = "32pt"
99+
p.title.text_color = "#306998"
100+
p.title.align = "center"
101+
102+
p.xaxis.axis_label = "Date"
103+
p.xaxis.axis_label_text_font_size = "24pt"
104+
p.xaxis.major_label_text_font_size = "18pt"
105+
p.xaxis.major_label_orientation = 0.4
106+
p.xaxis.axis_line_width = 2
107+
p.xaxis.major_tick_line_width = 2
108+
p.xaxis.minor_tick_line_width = 1
109+
110+
p.yaxis.visible = False
111+
p.ygrid.visible = False
112+
p.xgrid.grid_line_alpha = 0.3
113+
p.xgrid.grid_line_dash = "dashed"
114+
p.xgrid.grid_line_width = 2
115+
116+
p.outline_line_color = None
117+
p.background_fill_color = "#fafafa"
118+
119+
# Configure legend
120+
p.legend.location = "top_right"
121+
p.legend.title = "Phase"
122+
p.legend.title_text_font_size = "22pt"
123+
p.legend.label_text_font_size = "20pt"
124+
p.legend.glyph_height = 30
125+
p.legend.glyph_width = 30
126+
p.legend.border_line_color = "#cccccc"
127+
p.legend.background_fill_alpha = 0.9
128+
p.legend.padding = 15
129+
p.legend.spacing = 10
130+
131+
# Save outputs
132+
export_png(p, filename="plot.png")
133+
134+
# Also save HTML for interactive version
135+
output_file("plot.html", title="Event Timeline")
136+
save(p)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
library: bokeh
2+
specification_id: timeline-basic
3+
created: '2025-12-29T22:48:09Z'
4+
updated: '2025-12-29T22:56:55Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20584329995
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/timeline-basic/bokeh/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/timeline-basic/bokeh/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/timeline-basic/bokeh/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent alternating label positioning above/below axis prevents text overlap
17+
- Clean category color-coding with proper legend showing all 5 project phases
18+
- Good use of Bokeh ColumnDataSource for categorical grouping in scatter plot
19+
- Proper 4800x2700 sizing with appropriate font sizes for the canvas
20+
- Realistic software project milestone scenario with logical progression
21+
- Both PNG and HTML outputs generated for static and interactive viewing
22+
weaknesses:
23+
- Event label font size (18pt) could be slightly larger for better readability at
24+
full resolution
25+
- Legend positioned far from data area in top-right corner
26+
- Could benefit from Bokeh-specific features like HoverTool for interactivity

0 commit comments

Comments
 (0)