Skip to content

Commit 8e6f310

Browse files
feat(plotly): implement lollipop-basic (#5443)
## Implementation: `lollipop-basic` - python/plotly Implements the **python/plotly** version of `lollipop-basic`. **File:** `plots/lollipop-basic/implementations/python/plotly.py` **Parent Issue:** #934 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/24956801988)* --------- 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 986dc64 commit 8e6f310

2 files changed

Lines changed: 223 additions & 166 deletions

File tree

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
lollipop-basic: Basic Lollipop Chart
3-
Library: plotly 6.5.0 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: plotly 6.7.0 | Python 3.14.4
4+
Quality: 87/100 | Updated: 2026-04-26
55
"""
66

7+
import os
8+
79
import plotly.graph_objects as go
810

911

10-
# Data - Product sales by category, sorted by value
12+
# Theme tokens (see prompts/default-style-guide.md "Theme-adaptive Chrome")
13+
THEME = os.getenv("ANYPLOT_THEME", "light")
14+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
15+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
16+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
17+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
18+
GRID = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)"
19+
BRAND = "#009E73" # Okabe-Ito position 1 — ALWAYS first series
20+
21+
# Data — Product sales by category (deterministic, sorted descending)
1122
categories = [
1223
"Electronics",
1324
"Clothing",
@@ -20,55 +31,74 @@
2031
"Food & Grocery",
2132
"Health",
2233
]
23-
values = [125000, 98000, 87000, 76000, 65000, 54000, 48000, 42000, 38000, 31000]
34+
values = [124820, 97340, 86715, 75260, 64480, 53905, 47620, 41370, 37815, 30945]
2435

25-
# Create figure
36+
# Plot
2637
fig = go.Figure()
2738

28-
# Add stems (thin lines from baseline to value)
39+
# Stems — one segmented Scatter trace via None separators (single trace, fewer DOM nodes)
40+
stem_x = []
41+
stem_y = []
2942
for cat, val in zip(categories, values, strict=True):
30-
fig.add_trace(
31-
go.Scatter(
32-
x=[cat, cat],
33-
y=[0, val],
34-
mode="lines",
35-
line={"color": "#306998", "width": 3},
36-
showlegend=False,
37-
hoverinfo="skip",
38-
)
39-
)
43+
stem_x.extend([cat, cat, None])
44+
stem_y.extend([0, val, None])
4045

41-
# Add markers (dots at the top of each stem)
46+
fig.add_trace(
47+
go.Scatter(x=stem_x, y=stem_y, mode="lines", line={"color": BRAND, "width": 3}, showlegend=False, hoverinfo="skip")
48+
)
49+
50+
# Markers — circular dots at the top of each stem
4251
fig.add_trace(
4352
go.Scatter(
4453
x=categories,
4554
y=values,
4655
mode="markers",
47-
marker={"color": "#306998", "size": 18, "line": {"color": "white", "width": 2}},
56+
marker={"color": BRAND, "size": 22, "line": {"color": PAGE_BG, "width": 2.5}, "symbol": "circle"},
4857
showlegend=False,
49-
hovertemplate="%{x}<br>$%{y:,.0f}<extra></extra>",
58+
hovertemplate="<b>%{x}</b><br>Sales: $%{y:,.0f}<extra></extra>",
59+
cliponaxis=False,
5060
)
5161
)
5262

53-
# Update layout for 4800x2700 px
63+
# Style
5464
fig.update_layout(
55-
title={"text": "lollipop-basic · plotly · pyplots.ai", "font": {"size": 40}, "x": 0.5, "xanchor": "center"},
56-
xaxis={"title": {"text": "Product Category", "font": {"size": 40}}, "tickfont": {"size": 32}, "tickangle": -45},
65+
title={
66+
"text": "Product Sales by Category · lollipop-basic · plotly · anyplot.ai",
67+
"font": {"size": 28, "color": INK},
68+
"x": 0.5,
69+
"xanchor": "center",
70+
"y": 0.95,
71+
},
72+
xaxis={
73+
"title": {"text": "Product Category", "font": {"size": 22, "color": INK}},
74+
"tickfont": {"size": 18, "color": INK_SOFT},
75+
"tickangle": -35,
76+
"showgrid": False,
77+
"linecolor": INK_SOFT,
78+
"ticks": "outside",
79+
"tickcolor": INK_SOFT,
80+
"ticklen": 6,
81+
},
5782
yaxis={
58-
"title": {"text": "Sales ($)", "font": {"size": 40}},
59-
"tickfont": {"size": 32},
83+
"title": {"text": "Sales ($)", "font": {"size": 22, "color": INK}},
84+
"tickfont": {"size": 18, "color": INK_SOFT},
6085
"tickformat": "$,.0f",
61-
"gridcolor": "rgba(0,0,0,0.1)",
86+
"gridcolor": GRID,
6287
"gridwidth": 1,
88+
"zeroline": True,
89+
"zerolinecolor": INK_SOFT,
90+
"zerolinewidth": 1.5,
91+
"linecolor": INK_SOFT,
6392
"range": [0, max(values) * 1.1],
6493
},
65-
template="plotly_white",
66-
margin={"l": 100, "r": 50, "t": 120, "b": 150},
94+
paper_bgcolor=PAGE_BG,
95+
plot_bgcolor=PAGE_BG,
96+
font={"color": INK, "family": "Inter, system-ui, sans-serif"},
97+
margin={"l": 110, "r": 60, "t": 110, "b": 160},
6798
showlegend=False,
99+
hoverlabel={"bgcolor": ELEVATED_BG, "bordercolor": INK_SOFT, "font": {"color": INK, "size": 16}},
68100
)
69101

70-
# Save as PNG (4800x2700 px)
71-
fig.write_image("plot.png", width=1600, height=900, scale=3)
72-
73-
# Save interactive HTML
74-
fig.write_html("plot.html")
102+
# Save
103+
fig.write_image(f"plot-{THEME}.png", width=1600, height=900, scale=3)
104+
fig.write_html(f"plot-{THEME}.html", include_plotlyjs="cdn")

0 commit comments

Comments
 (0)