Skip to content

Commit 9630a49

Browse files
feat(letsplot): implement bar-diverging (#6034)
## Implementation: `bar-diverging` - python/letsplot Implements the **python/letsplot** version of `bar-diverging`. **File:** `plots/bar-diverging/implementations/python/letsplot.py` **Parent Issue:** #2009 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25546837853)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
1 parent d368a92 commit 9630a49

2 files changed

Lines changed: 199 additions & 150 deletions

File tree

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
bar-diverging: Diverging Bar Chart
3-
Library: letsplot 4.8.2 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-25
3+
Library: letsplot 4.9.0 | Python 3.13.13
4+
Quality: 93/100 | Updated: 2026-05-08
55
"""
66

7+
import os
8+
79
import pandas as pd
810
from lets_plot import * # noqa: F403
911
from lets_plot.export import ggsave as export_ggsave
1012

1113

1214
LetsPlot.setup_html() # noqa: F405
1315

16+
# Theme tokens
17+
THEME = os.getenv("ANYPLOT_THEME", "light")
18+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
19+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
20+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
21+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
22+
23+
# Okabe-Ito brand colors for diverging bars
24+
POSITIVE_COLOR = "#009E73" # Brand green
25+
NEGATIVE_COLOR = "#D55E00" # Vermillion
26+
1427
# Data - Customer satisfaction survey (Net Promoter Score style)
1528
categories = [
1629
"Product Quality",
@@ -27,8 +40,8 @@
2740
"Loyalty Program",
2841
]
2942

30-
# Scores range from -100 (all detractors) to +100 (all promoters)
31-
scores = [72, 45, -28, 38, -12, 55, 21, 65, -35, 48, -8, 32]
43+
# More balanced scores: 6 negative, 6 positive
44+
scores = [62, 48, -22, 35, -15, 52, 28, 68, -38, 42, -8, 38]
3245

3346
df = pd.DataFrame(
3447
{"Category": categories, "Score": scores, "Sentiment": ["Positive" if s >= 0 else "Negative" for s in scores]}
@@ -40,31 +53,44 @@
4053
# Preserve category order after sorting
4154
df["Category"] = pd.Categorical(df["Category"], categories=df["Category"].tolist(), ordered=True)
4255

43-
# Create horizontal diverging bar chart
56+
# Create horizontal diverging bar chart with theme-adaptive styling
4457
plot = (
4558
ggplot(df, aes(x="Score", y="Category", fill="Sentiment")) # noqa: F405
46-
+ geom_bar(stat="identity", width=0.7, alpha=0.9) # noqa: F405
47-
+ geom_vline(xintercept=0, color="#333333", size=1.2) # noqa: F405
48-
+ scale_fill_manual(values=["#DC2626", "#306998"]) # noqa: F405
59+
+ geom_bar(stat="identity", width=0.75, alpha=0.95) # noqa: F405
60+
+ geom_vline(xintercept=0, color=INK_SOFT, size=1.5) # noqa: F405
61+
+ scale_fill_manual( # noqa: F405
62+
values={
63+
"Positive": POSITIVE_COLOR,
64+
"Negative": NEGATIVE_COLOR,
65+
}
66+
)
4967
+ labs( # noqa: F405
50-
x="Net Promoter Score", y="Category", title="bar-diverging · letsplot · pyplots.ai"
68+
x="Net Promoter Score (-100 to +100)", y="Category", title="bar-diverging · letsplot · anyplot.ai"
5169
)
5270
+ theme_minimal() # noqa: F405
5371
+ theme( # noqa: F405
54-
plot_title=element_text(size=28, face="bold", hjust=0.5), # noqa: F405
55-
axis_title_x=element_text(size=22), # noqa: F405
56-
axis_title_y=element_text(size=22), # noqa: F405
57-
axis_text_x=element_text(size=18), # noqa: F405
58-
axis_text_y=element_text(size=18), # noqa: F405
59-
legend_title=element_text(size=18), # noqa: F405
60-
legend_text=element_text(size=16), # noqa: F405
61-
legend_position="right",
72+
plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG), # noqa: F405
73+
panel_background=element_rect(fill=PAGE_BG), # noqa: F405
74+
panel_grid_major_x=element_line(color=INK, size=0.3), # noqa: F405
6275
panel_grid_major_y=element_blank(), # noqa: F405
6376
panel_grid_minor=element_blank(), # noqa: F405
77+
plot_title=element_text(size=28, face="bold", color=INK, hjust=0.5), # noqa: F405
78+
axis_title_x=element_text(size=22, color=INK), # noqa: F405
79+
axis_title_y=element_text(size=22, color=INK), # noqa: F405
80+
axis_text_x=element_text(size=18, color=INK_SOFT), # noqa: F405
81+
axis_text_y=element_text(size=18, color=INK_SOFT), # noqa: F405
82+
axis_line_x=element_line(color=INK_SOFT), # noqa: F405
83+
axis_line_y=element_line(color=INK_SOFT), # noqa: F405
84+
legend_title=element_text(size=18, color=INK), # noqa: F405
85+
legend_text=element_text(size=16, color=INK_SOFT), # noqa: F405
86+
legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT), # noqa: F405
87+
legend_position="right",
6488
)
6589
+ ggsize(1600, 900) # noqa: F405
6690
)
6791

68-
# Save
69-
export_ggsave(plot, filename="plot.png", path=".", scale=3)
70-
export_ggsave(plot, filename="plot.html", path=".")
92+
# Save PNG with scale 3x to get 4800 × 2700 px
93+
export_ggsave(plot, filename=f"plot-{THEME}.png", path=".", scale=3)
94+
95+
# Save HTML for interactive version
96+
export_ggsave(plot, filename=f"plot-{THEME}.html", path=".")

0 commit comments

Comments
 (0)