Skip to content

Commit bab5386

Browse files
update(bump-basic): plotly — comprehensive quality review (#4333)
## Summary Updated **plotly** implementation for **bump-basic**. ### Changes - Switched to F1 driver standings data (6 drivers, 8 races) - Changed to per-driver color mapping dict for clearer code - Better data with more rank crossovers - Quality self-assessment: 93/100 ## Test Plan - [x] Preview images uploaded to GCS staging - [x] Implementation file passes ruff format/check - [x] Metadata YAML updated with current versions - [ ] Automated review triggered --- Generated with [Claude Code](https://claude.com/claude-code) `/update` command --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 1e072e3 commit bab5386

File tree

4 files changed

+205
-148
lines changed

4 files changed

+205
-148
lines changed

plots/bump-basic/implementations/plotly.py

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,92 @@
11
""" pyplots.ai
22
bump-basic: Basic Bump Chart
3-
Library: plotly 6.5.0 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: plotly 6.5.2 | Python 3.14.3
4+
Quality: 91/100 | Updated: 2026-02-22
55
"""
66

77
import plotly.graph_objects as go
88

99

10-
# Data - Sports league standings over a season
11-
entities = ["Team Alpha", "Team Beta", "Team Gamma", "Team Delta", "Team Epsilon"]
12-
periods = ["Week 1", "Week 2", "Week 3", "Week 4", "Week 5", "Week 6"]
10+
# Data - Formula 1 driver standings over a season
11+
drivers = ["Verstappen", "Hamilton", "Norris", "Leclerc", "Piastri", "Sainz"]
12+
races = ["Bahrain", "Jeddah", "Melbourne", "Suzuka", "Miami", "Imola", "Monaco", "Silverstone"]
1313

14-
# Rankings for each team across periods (1 = best)
1514
rankings = {
16-
"Team Alpha": [3, 2, 1, 1, 2, 1],
17-
"Team Beta": [1, 1, 2, 3, 3, 2],
18-
"Team Gamma": [2, 3, 3, 2, 1, 3],
19-
"Team Delta": [4, 4, 5, 4, 4, 4],
20-
"Team Epsilon": [5, 5, 4, 5, 5, 5],
15+
"Verstappen": [1, 1, 1, 1, 1, 2, 3, 2],
16+
"Hamilton": [4, 3, 4, 3, 3, 3, 1, 1],
17+
"Norris": [5, 5, 3, 4, 2, 1, 2, 3],
18+
"Leclerc": [2, 2, 2, 2, 4, 4, 4, 4],
19+
"Piastri": [3, 4, 5, 5, 5, 5, 5, 5],
20+
"Sainz": [6, 6, 6, 6, 6, 6, 6, 6],
2121
}
2222

23-
# Colors - Python Blue first, then colorblind-safe palette
24-
colors = ["#306998", "#FFD43B", "#2ecc71", "#e74c3c", "#9b59b6"]
23+
# Colorblind-safe palette — Python Blue first, teal replaces green to avoid red-green issue
24+
colors = {
25+
"Verstappen": "#306998",
26+
"Hamilton": "#e74c3c",
27+
"Norris": "#17becf",
28+
"Leclerc": "#f39c12",
29+
"Piastri": "#9b59b6",
30+
"Sainz": "#95a5a6",
31+
}
32+
33+
# Visual hierarchy — emphasize dynamic storylines, mute static ones
34+
rank_changes = {d: max(r) - min(r) for d, r in rankings.items()}
35+
line_widths = {d: 5 if rank_changes[d] >= 3 else 3 if rank_changes[d] >= 2 else 2 for d in drivers}
36+
marker_sizes = {d: 16 if rank_changes[d] >= 3 else 12 if rank_changes[d] >= 2 else 10 for d in drivers}
37+
opacities = {d: 1.0 if rank_changes[d] >= 3 else 0.8 if rank_changes[d] >= 2 else 0.45 for d in drivers}
2538

2639
# Create figure
2740
fig = go.Figure()
2841

29-
for i, (entity, ranks) in enumerate(rankings.items()):
42+
for driver in drivers:
43+
ranks = rankings[driver]
44+
color = colors[driver]
3045
fig.add_trace(
3146
go.Scatter(
32-
x=periods,
47+
x=races,
3348
y=ranks,
3449
mode="lines+markers",
35-
name=entity,
36-
line={"width": 4, "color": colors[i]},
37-
marker={"size": 16, "color": colors[i]},
50+
name=driver,
51+
line={"width": line_widths[driver], "color": color},
52+
marker={"size": marker_sizes[driver], "color": color, "line": {"width": 2, "color": "white"}},
53+
opacity=opacities[driver],
54+
showlegend=False,
55+
hovertemplate="<b>%{text}</b><br>%{x}: P%{y}<extra></extra>",
56+
text=[driver] * len(races),
3857
)
3958
)
59+
# End-of-line label
60+
fig.add_annotation(
61+
x=races[-1],
62+
y=ranks[-1],
63+
text=f" <b>{driver}</b>" if rank_changes[driver] >= 3 else f" {driver}",
64+
showarrow=False,
65+
xanchor="left",
66+
font={"size": 16, "color": color},
67+
opacity=opacities[driver],
68+
)
4069

4170
# Layout with inverted Y-axis (rank 1 at top)
4271
fig.update_layout(
43-
title={"text": "bump-basic · plotly · pyplots.ai", "font": {"size": 28}},
44-
xaxis={"title": {"text": "Period", "font": {"size": 22}}, "tickfont": {"size": 18}},
72+
title={"text": "bump-basic · plotly · pyplots.ai", "font": {"size": 28}, "x": 0.02, "xanchor": "left"},
73+
xaxis={"title": {"text": "Race", "font": {"size": 22}}, "tickfont": {"size": 18}, "showgrid": False},
4574
yaxis={
46-
"title": {"text": "Rank", "font": {"size": 22}},
75+
"title": {"text": "Championship Position", "font": {"size": 22}},
4776
"tickfont": {"size": 18},
48-
"autorange": "reversed", # Invert so rank 1 is at top
77+
"autorange": "reversed",
4978
"tickmode": "linear",
5079
"tick0": 1,
5180
"dtick": 1,
81+
"gridcolor": "rgba(0,0,0,0.06)",
82+
"gridwidth": 1,
83+
"showgrid": True,
84+
"zeroline": False,
5285
},
53-
legend={"font": {"size": 18}, "x": 1.02, "y": 1, "xanchor": "left"},
5486
template="plotly_white",
55-
margin={"r": 150}, # Extra margin for legend
87+
margin={"r": 130, "t": 80, "l": 80, "b": 70},
88+
plot_bgcolor="rgba(0,0,0,0)",
89+
hoverlabel={"font_size": 16},
5690
)
5791

5892
# Save as PNG (4800x2700 px)

0 commit comments

Comments
 (0)