Skip to content

Commit 06a0cfe

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

2 files changed

Lines changed: 230 additions & 155 deletions

File tree

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
dumbbell-basic: Basic Dumbbell Chart
3-
Library: plotnine 0.15.2 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: plotnine 0.15.3 | Python 3.14.4
4+
Quality: 89/100 | Updated: 2026-04-26
55
"""
66

7+
import os
8+
79
import pandas as pd
810
from plotnine import (
911
aes,
1012
element_blank,
13+
element_line,
14+
element_rect,
1115
element_text,
1216
geom_point,
1317
geom_segment,
@@ -20,24 +24,27 @@
2024
)
2125

2226

27+
THEME = os.getenv("ANYPLOT_THEME", "light")
28+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
29+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
30+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
31+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
32+
33+
OKABE_ITO = ["#009E73", "#D55E00", "#0072B2", "#CC79A7", "#E69F00", "#56B4E9", "#F0E442"]
34+
2335
# Data: Employee satisfaction scores before and after workplace policy changes
2436
categories = ["Engineering", "Marketing", "Sales", "HR", "Finance", "Operations", "Customer Support", "Product"]
2537
before_scores = [65, 58, 72, 45, 68, 52, 40, 75]
2638
after_scores = [82, 71, 78, 73, 75, 68, 62, 88]
2739

28-
# Calculate differences and sort by largest improvement first
2940
differences = [a - b for a, b in zip(after_scores, before_scores, strict=True)]
30-
sorted_data = sorted(
31-
zip(categories, before_scores, after_scores, differences, strict=True), key=lambda x: x[3], reverse=True
32-
)
41+
sorted_data = sorted(zip(categories, before_scores, after_scores, differences, strict=True), key=lambda x: x[3])
3342
categories = [d[0] for d in sorted_data]
3443
before_scores = [d[1] for d in sorted_data]
3544
after_scores = [d[2] for d in sorted_data]
45+
differences = [d[3] for d in sorted_data]
3646

37-
# Create DataFrame for segments (connecting lines)
38-
df_segments = pd.DataFrame({"category": categories, "start": before_scores, "end": after_scores})
39-
40-
# Create DataFrame for points (long format for legend)
47+
df_segments = pd.DataFrame({"category": categories, "start": before_scores, "end": after_scores, "diff": differences})
4148
df_points = pd.DataFrame(
4249
{
4350
"category": categories * 2,
@@ -46,32 +53,40 @@
4653
}
4754
)
4855

49-
# Create ordered categorical for proper y-axis ordering
5056
df_segments["category"] = pd.Categorical(df_segments["category"], categories=categories, ordered=True)
5157
df_points["category"] = pd.Categorical(df_points["category"], categories=categories, ordered=True)
58+
df_points["period"] = pd.Categorical(df_points["period"], categories=["Before", "After"], ordered=True)
5259

53-
# Plot
5460
plot = (
5561
ggplot()
56-
# Connecting lines (thin and subtle)
5762
+ geom_segment(
58-
aes(x="start", xend="end", y="category", yend="category"), data=df_segments, color="#888888", size=1.5
63+
aes(x="start", xend="end", y="category", yend="category"), data=df_segments, color=INK_SOFT, size=1.5, alpha=0.6
64+
)
65+
+ geom_point(aes(x="value", y="category", color="period"), data=df_points, size=7)
66+
+ scale_color_manual(values={"Before": OKABE_ITO[0], "After": OKABE_ITO[1]})
67+
+ scale_x_continuous(limits=(30, 100), breaks=[30, 40, 50, 60, 70, 80, 90, 100])
68+
+ labs(
69+
x="Satisfaction Score",
70+
y="Department",
71+
title="Employee Satisfaction · dumbbell-basic · plotnine · anyplot.ai",
72+
color="",
5973
)
60-
# Dots with distinct colors for before/after
61-
+ geom_point(aes(x="value", y="category", color="period"), data=df_points, size=6, stroke=0.5)
62-
+ scale_color_manual(values={"Before": "#306998", "After": "#FFD43B"})
63-
+ scale_x_continuous(limits=(30, 100))
64-
+ labs(x="Satisfaction Score", y="Department", title="dumbbell-basic · plotnine · pyplots.ai", color="")
6574
+ theme_minimal()
6675
+ theme(
6776
figure_size=(16, 9),
68-
plot_title=element_text(size=24),
69-
axis_title=element_text(size=20),
70-
axis_text=element_text(size=16),
71-
legend_text=element_text(size=16),
77+
plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
78+
panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
79+
plot_title=element_text(size=24, color=INK, weight="bold"),
80+
axis_title=element_text(size=20, color=INK),
81+
axis_text=element_text(size=16, color=INK_SOFT),
82+
legend_text=element_text(size=16, color=INK_SOFT),
83+
legend_title=element_text(color=INK),
84+
legend_background=element_rect(fill=ELEVATED_BG, color=ELEVATED_BG),
7285
legend_position="right",
86+
panel_grid_major_x=element_line(color=INK, size=0.3, alpha=0.10),
87+
panel_grid_minor=element_blank(),
7388
panel_grid_major_y=element_blank(),
7489
)
7590
)
7691

77-
plot.save("plot.png", dpi=300, verbose=False)
92+
plot.save(f"plot-{THEME}.png", dpi=300, verbose=False)

0 commit comments

Comments
 (0)