Skip to content

Commit bd1b954

Browse files
feat(pygal): implement timeline-basic (#2472)
## Implementation: `timeline-basic` - pygal Implements the **pygal** version of `timeline-basic`. **File:** `plots/timeline-basic/implementations/pygal.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20584332106)* --------- 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 eedf116 commit bd1b954

2 files changed

Lines changed: 173 additions & 0 deletions

File tree

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
""" pyplots.ai
2+
timeline-basic: Event Timeline
3+
Library: pygal 3.1.0 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-29
5+
"""
6+
7+
from datetime import date
8+
9+
import cairosvg
10+
import pygal
11+
from pygal.style import Style
12+
13+
14+
# Data - Software project milestones
15+
events = [
16+
(date(2024, 1, 15), "Project Kickoff", "Planning"),
17+
(date(2024, 2, 10), "Requirements Complete", "Planning"),
18+
(date(2024, 3, 20), "Architecture Design", "Design"),
19+
(date(2024, 4, 25), "Development Start", "Development"),
20+
(date(2024, 6, 15), "Alpha Release", "Development"),
21+
(date(2024, 8, 1), "Beta Release", "Testing"),
22+
(date(2024, 9, 10), "User Acceptance", "Testing"),
23+
(date(2024, 10, 20), "Production Launch", "Deployment"),
24+
]
25+
26+
# Sort events by date
27+
events = sorted(events, key=lambda x: x[0])
28+
29+
# Category colors mapped to pygal color indices
30+
categories = ["Planning", "Design", "Development", "Testing", "Deployment"]
31+
category_colors = {
32+
"Planning": "#306998",
33+
"Design": "#FFD43B",
34+
"Development": "#4ECDC4",
35+
"Testing": "#FF6B6B",
36+
"Deployment": "#45B7D1",
37+
}
38+
39+
# Custom style for large canvas (4800x2700)
40+
custom_style = Style(
41+
background="white",
42+
plot_background="white",
43+
foreground="#333333",
44+
foreground_strong="#333333",
45+
foreground_subtle="#666666",
46+
colors=tuple(category_colors[c] for c in categories),
47+
title_font_size=60,
48+
label_font_size=32,
49+
major_label_font_size=32,
50+
legend_font_size=36,
51+
value_font_size=28,
52+
tooltip_font_size=28,
53+
)
54+
55+
# Reference date for x-axis positioning
56+
reference_date = date(2024, 1, 1)
57+
58+
# Create XY chart - using native pygal scatter capabilities
59+
chart = pygal.XY(
60+
width=4800,
61+
height=2700,
62+
style=custom_style,
63+
title="Software Project Milestones · timeline-basic · pygal · pyplots.ai",
64+
show_legend=True,
65+
legend_at_bottom=False,
66+
legend_box_size=32,
67+
x_title="Month (2024)",
68+
y_title="Project Phase",
69+
show_dots=True,
70+
dots_size=18,
71+
stroke=False,
72+
show_x_guides=True,
73+
show_y_guides=True,
74+
margin=120,
75+
x_labels_major_every=1,
76+
truncate_legend=-1,
77+
)
78+
79+
# Custom x-axis labels for months
80+
chart.x_labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov"]
81+
chart.x_labels_major = chart.x_labels
82+
83+
# Y positions for alternating above/below layout - spread vertically to use more canvas
84+
y_positions = {
85+
0: 4, # Above
86+
1: 1, # Below
87+
2: 4, # Above
88+
3: 1, # Below
89+
4: 4, # Above
90+
5: 1, # Below
91+
6: 4, # Above
92+
7: 1, # Below
93+
}
94+
95+
# Group events by category for legend
96+
category_data = {cat: [] for cat in categories}
97+
98+
for i, (event_date, event_name, category) in enumerate(events):
99+
# X position: days since Jan 1, scaled to month
100+
days = (event_date - reference_date).days
101+
x_val = days / 30.44 # Average days per month
102+
103+
# Y position for alternating layout
104+
y_val = y_positions[i]
105+
106+
# Add data point with label
107+
category_data[category].append({"value": (x_val, y_val), "label": f"{event_name}\n{event_date.strftime('%b %d')}"})
108+
109+
# Add each category as a series
110+
for category in categories:
111+
if category_data[category]:
112+
chart.add(category, category_data[category])
113+
114+
# Set y range to maximize vertical usage (values 0-5 with padding)
115+
chart.range = (0, 5)
116+
117+
# Render base SVG
118+
svg_string = chart.render().decode("utf-8")
119+
120+
# Add a horizontal timeline axis in the middle (y=2.5) as visual anchor
121+
# Calculate plot area based on pygal defaults with our margins
122+
PLOT_LEFT = 400
123+
PLOT_RIGHT = 4550
124+
PLOT_TOP = 300
125+
PLOT_BOTTOM = 2200
126+
PLOT_HEIGHT = PLOT_BOTTOM - PLOT_TOP
127+
128+
# Timeline at y=2.5 (middle of 0-5 range)
129+
timeline_y = PLOT_TOP + PLOT_HEIGHT * (1 - 2.5 / 5) # Invert because SVG y goes down
130+
131+
# Create timeline axis elements
132+
timeline_svg = f"""
133+
<g class="timeline-axis">
134+
<line x1="{PLOT_LEFT}" y1="{timeline_y:.0f}" x2="{PLOT_RIGHT}" y2="{timeline_y:.0f}"
135+
stroke="#999999" stroke-width="4" stroke-dasharray="15,8"/>
136+
<text x="{PLOT_LEFT - 80}" y="{timeline_y + 10:.0f}" font-family="Consolas, sans-serif"
137+
font-size="28" fill="#666666" text-anchor="end">Timeline</text>
138+
</g>
139+
"""
140+
141+
# Inject timeline before </svg>
142+
svg_output = svg_string.replace("</svg>", f"{timeline_svg}\n</svg>")
143+
144+
# Save outputs
145+
with open("plot.html", "w") as f:
146+
f.write(svg_output)
147+
148+
cairosvg.svg2png(bytestring=svg_output.encode(), write_to="plot.png")
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
library: pygal
2+
specification_id: timeline-basic
3+
created: '2025-12-29T22:48:52Z'
4+
updated: '2025-12-29T23:04:30Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20584332106
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: 3.1.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/timeline-basic/pygal/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/timeline-basic/pygal/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/timeline-basic/pygal/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent alternating above/below layout prevents text overlap and creates clear
17+
visual hierarchy
18+
- Good use of pygal XY chart with custom styling for timeline visualization
19+
- Creative SVG injection to add dashed timeline axis as visual anchor
20+
- Realistic software project milestone data with meaningful categories
21+
- Color-coded categories with distinct, accessible colors
22+
weaknesses:
23+
- Vertical canvas utilization could be improved - timeline occupies narrow horizontal
24+
band with large empty areas above and below
25+
- Legend placement at bottom left is distant from the actual data points

0 commit comments

Comments
 (0)