Skip to content

Commit a113900

Browse files
feat(altair): implement dumbbell-basic (#5419)
## Implementation: `dumbbell-basic` - python/altair Implements the **python/altair** version of `dumbbell-basic`. **File:** `plots/dumbbell-basic/implementations/python/altair.py` **Parent Issue:** #945 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/24945139784)* --------- 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 06a0cfe commit a113900

2 files changed

Lines changed: 220 additions & 172 deletions

File tree

Lines changed: 55 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
dumbbell-basic: Basic Dumbbell Chart
3-
Library: altair 6.0.0 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: altair 6.1.0 | Python 3.14.4
4+
Quality: 89/100 | Updated: 2026-04-26
55
"""
66

7+
import os
8+
79
import altair as alt
810
import pandas as pd
911

1012

11-
# Data - Employee satisfaction scores before and after policy changes
12-
# Sorted by improvement (difference) to reveal patterns
13+
# Theme-adaptive chrome
14+
THEME = os.getenv("ANYPLOT_THEME", "light")
15+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
16+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
17+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
18+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
19+
20+
# Okabe-Ito palette positions 1 and 2
21+
COLOR_BEFORE = "#009E73"
22+
COLOR_AFTER = "#D55E00"
23+
24+
# Data — Employee satisfaction scores before and after policy changes
1325
data = pd.DataFrame(
1426
{
1527
"category": [
@@ -24,68 +36,72 @@
2436
"R&D",
2537
"IT",
2638
],
27-
"before": [52, 61, 58, 65, 72, 68, 55, 74, 63, 59],
28-
"after": [78, 82, 76, 81, 85, 79, 64, 81, 69, 64],
39+
"Before": [52, 61, 58, 65, 72, 68, 55, 74, 63, 59],
40+
"After": [78, 82, 76, 81, 85, 79, 64, 81, 69, 64],
2941
}
3042
)
31-
32-
# Calculate difference and sort by improvement
33-
data["difference"] = data["after"] - data["before"]
43+
data["difference"] = data["After"] - data["Before"]
3444
data = data.sort_values("difference", ascending=True)
3545

36-
# Reshape data for Altair (long format for dots)
46+
# Long-form data for the two dot series
3747
dots_data = pd.melt(
38-
data, id_vars=["category", "difference"], value_vars=["before", "after"], var_name="period", value_name="score"
48+
data, id_vars=["category", "difference"], value_vars=["Before", "After"], var_name="period", value_name="score"
3949
)
4050

41-
# Shared scale for x-axis
4251
x_scale = alt.Scale(domain=[45, 90])
52+
y_sort = alt.EncodingSortField(field="difference", order="ascending")
4353

44-
# Create the connecting lines (using before/after as x values for line)
54+
# Connecting lines (theme-adaptive subtle ink)
4555
lines = (
4656
alt.Chart(data)
47-
.mark_rule(strokeWidth=2, color="#999999")
48-
.encode(
49-
y=alt.Y(
50-
"category:N",
51-
sort=alt.EncodingSortField(field="difference", order="ascending"),
52-
axis=alt.Axis(labelFontSize=18, titleFontSize=22, title=None),
53-
),
54-
x=alt.X("before:Q", scale=x_scale),
55-
x2=alt.X2("after:Q"),
56-
)
57+
.mark_rule(strokeWidth=3, color=INK_SOFT, opacity=0.55)
58+
.encode(y=alt.Y("category:N", sort=y_sort, title=None), x=alt.X("Before:Q", scale=x_scale), x2=alt.X2("After:Q"))
5759
)
5860

59-
# Create the dots with colors for before/after
61+
# Dots for Before / After values
6062
dots = (
6163
alt.Chart(dots_data)
62-
.mark_circle(size=350)
64+
.mark_circle(size=420, opacity=1.0, stroke=PAGE_BG, strokeWidth=2)
6365
.encode(
64-
y=alt.Y("category:N", sort=alt.EncodingSortField(field="difference", order="ascending")),
65-
x=alt.X(
66-
"score:Q", axis=alt.Axis(labelFontSize=18, titleFontSize=22), title="Satisfaction Score", scale=x_scale
67-
),
66+
y=alt.Y("category:N", sort=y_sort, title=None),
67+
x=alt.X("score:Q", scale=x_scale, title="Employee Satisfaction Score (%)"),
6868
color=alt.Color(
6969
"period:N",
70-
scale=alt.Scale(domain=["before", "after"], range=["#306998", "#FFD43B"]),
71-
legend=alt.Legend(title="Period", labelFontSize=16, titleFontSize=18),
70+
scale=alt.Scale(domain=["Before", "After"], range=[COLOR_BEFORE, COLOR_AFTER]),
71+
legend=alt.Legend(title="Policy Change", labelFontSize=16, titleFontSize=18),
7272
),
7373
tooltip=["category:N", "period:N", "score:Q"],
7474
)
7575
)
7676

77-
# Combine lines and dots
7877
chart = (
7978
(lines + dots)
8079
.properties(
8180
width=1600,
8281
height=900,
83-
title=alt.Title("Employee Satisfaction · dumbbell-basic · altair · pyplots.ai", fontSize=28),
82+
title=alt.Title(
83+
"Employee Satisfaction · dumbbell-basic · altair · anyplot.ai",
84+
fontSize=28,
85+
color=INK,
86+
anchor="start",
87+
offset=20,
88+
),
89+
background=PAGE_BG,
90+
)
91+
.configure_view(fill=PAGE_BG, stroke=None)
92+
.configure_axis(
93+
labelFontSize=18,
94+
titleFontSize=22,
95+
domainColor=INK_SOFT,
96+
tickColor=INK_SOFT,
97+
gridColor=INK,
98+
gridOpacity=0.10,
99+
labelColor=INK_SOFT,
100+
titleColor=INK,
84101
)
85-
.configure_view(strokeWidth=0)
86-
.configure_axis(grid=True, gridOpacity=0.3, gridDash=[4, 4])
102+
.configure_title(color=INK)
103+
.configure_legend(fillColor=ELEVATED_BG, strokeColor=INK_SOFT, labelColor=INK_SOFT, titleColor=INK, padding=12)
87104
)
88105

89-
# Save as PNG and HTML
90-
chart.save("plot.png", scale_factor=3.0)
91-
chart.save("plot.html")
106+
chart.save(f"plot-{THEME}.png", scale_factor=3.0)
107+
chart.save(f"plot-{THEME}.html")

0 commit comments

Comments
 (0)