Skip to content

Commit 4fdf648

Browse files
feat(letsplot): implement waterfall-basic (#5747)
## Implementation: `waterfall-basic` - python/letsplot Implements the **python/letsplot** version of `waterfall-basic`. **File:** `plots/waterfall-basic/implementations/python/letsplot.py` **Parent Issue:** #777 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25411013945)* --------- 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 781d3fe commit 4fdf648

2 files changed

Lines changed: 204 additions & 157 deletions

File tree

plots/waterfall-basic/implementations/python/letsplot.py

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
waterfall-basic: Basic Waterfall Chart
3-
Library: letsplot 4.8.2 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-24
3+
Library: letsplot 4.9.0 | Python 3.13.13
4+
Quality: 94/100 | Updated: 2026-05-06
55
"""
66

7+
import os
8+
79
import pandas as pd
810
from lets_plot import (
911
LetsPlot,
1012
aes,
1113
element_blank,
14+
element_rect,
1215
element_text,
1316
geom_rect,
1417
geom_segment,
@@ -27,6 +30,18 @@
2730

2831
LetsPlot.setup_html()
2932

33+
# Theme tokens
34+
THEME = os.getenv("ANYPLOT_THEME", "light")
35+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
36+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
37+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
38+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
39+
40+
# Okabe-Ito palette
41+
BRAND = "#009E73" # Position 1 - green
42+
ACCENT_1 = "#D55E00" # Position 2 - orange
43+
ACCENT_2 = "#0072B2" # Position 3 - blue
44+
3045
# Data - Quarterly financial breakdown from revenue to net income
3146
categories = [
3247
"Starting Balance",
@@ -37,7 +52,7 @@
3752
"Taxes",
3853
"Net Profit",
3954
]
40-
values = [50000, 35000, 18000, -22000, -8000, -12000, 0] # Last is placeholder for total
55+
values = [50000, 35000, 18000, -22000, -8000, -12000, 0]
4156

4257
# Calculate waterfall positions
4358
running_total = 0
@@ -109,22 +124,22 @@
109124
+ geom_rect(
110125
data=df,
111126
mapping=aes(xmin="xmin", xmax="xmax", ymin="ymin", ymax="ymax", fill="color_type"),
112-
color="white",
113-
size=1,
127+
color=INK_SOFT,
128+
size=0.8,
114129
)
115130
# Connector lines between bars
116131
+ geom_segment(
117132
data=connector_df,
118133
mapping=aes(x="x_start", xend="x_end", y="y", yend="y"),
119-
color="#555555",
120-
size=1,
134+
color=INK_SOFT,
135+
size=0.6,
121136
linetype="dashed",
122137
)
123138
# Value labels on bars
124-
+ geom_text(data=df, mapping=aes(x="x_pos", y="label_y", label="label"), color="white", size=12, fontface="bold")
125-
# Custom colors: green for positive, red for negative, Python Blue for totals
139+
+ geom_text(data=df, mapping=aes(x="x_pos", y="label_y", label="label"), color=INK, size=12, fontface="bold")
140+
# Colors: Okabe-Ito palette
126141
+ scale_fill_manual(
127-
values={"positive": "#22C55E", "negative": "#EF4444", "total": "#306998"},
142+
values={"positive": BRAND, "negative": ACCENT_1, "total": ACCENT_2},
128143
name="Change Type",
129144
labels={"positive": "Increase", "negative": "Decrease", "total": "Total"},
130145
)
@@ -133,24 +148,29 @@
133148
# Y axis
134149
+ scale_y_continuous(format="${,.0f}")
135150
# Labels
136-
+ labs(title="waterfall-basic · letsplot · pyplots.ai", x="", y="Amount ($)")
151+
+ labs(title="waterfall-basic · letsplot · anyplot.ai", x="", y="Amount ($)")
137152
# Theme
138153
+ theme_minimal()
139154
+ theme(
140-
plot_title=element_text(size=24, hjust=0.5),
141-
axis_title=element_text(size=20),
142-
axis_text_x=element_text(size=14, angle=30),
143-
axis_text_y=element_text(size=16),
144-
legend_title=element_text(size=18),
145-
legend_text=element_text(size=16),
146-
legend_position="right",
155+
plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
156+
panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
157+
panel_grid_major_y=element_rect(color=INK_SOFT, size=0.4, linetype="solid"),
147158
panel_grid_major_x=element_blank(),
159+
panel_grid_minor=element_blank(),
160+
plot_title=element_text(size=24, color=INK),
161+
axis_title=element_text(size=20, color=INK),
162+
axis_text_x=element_text(size=14, color=INK_SOFT, angle=30),
163+
axis_text_y=element_text(size=16, color=INK_SOFT),
164+
legend_title=element_text(size=18, color=INK),
165+
legend_text=element_text(size=16, color=INK_SOFT),
166+
legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),
167+
legend_position="right",
148168
)
149169
+ ggsize(1600, 900)
150170
)
151171

152172
# Save as PNG (scale 3x for 4800x2700)
153-
ggsave(plot, "plot.png", path=".", scale=3)
173+
ggsave(plot, f"plot-{THEME}.png", path=".", scale=3)
154174

155175
# Save as HTML for interactivity
156-
ggsave(plot, "plot.html", path=".")
176+
ggsave(plot, f"plot-{THEME}.html", path=".")

0 commit comments

Comments
 (0)