Skip to content

Commit 5aacada

Browse files
feat(letsplot): implement polar-bar (#6511)
## Implementation: `polar-bar` - python/letsplot Implements the **python/letsplot** version of `polar-bar`. **File:** `plots/polar-bar/implementations/python/letsplot.py` **Parent Issue:** #2693 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25772046568)* --------- 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 df1fbba commit 5aacada

2 files changed

Lines changed: 201 additions & 145 deletions

File tree

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,75 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
polar-bar: Polar Bar Chart (Wind Rose)
3-
Library: letsplot 4.8.2 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-30
3+
Library: letsplot 4.9.0 | Python 3.13.13
4+
Quality: 92/100 | Updated: 2026-05-13
55
"""
66

7+
import os
8+
79
import numpy as np
810
import pandas as pd
911
from lets_plot import (
1012
LetsPlot,
1113
aes,
1214
coord_polar,
1315
element_line,
16+
element_rect,
1417
element_text,
1518
geom_bar,
1619
ggplot,
20+
ggsave,
1721
ggsize,
1822
labs,
1923
scale_fill_manual,
2024
scale_y_continuous,
2125
theme,
2226
theme_minimal,
2327
)
24-
from lets_plot.export import ggsave
2528

2629

2730
LetsPlot.setup_html()
2831

29-
# Data - Wind direction frequency data (8 compass directions)
30-
np.random.seed(42)
31-
directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
32+
# Theme-adaptive colors
33+
THEME = os.getenv("ANYPLOT_THEME", "light")
34+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
35+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
36+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
3237

33-
# Generate realistic wind frequency data
34-
frequencies = np.array([15, 8, 12, 5, 10, 18, 22, 14])
38+
# Okabe-Ito palette + adaptive neutral for 8 compass directions
39+
OKABE_ITO = ["#009E73", "#D55E00", "#0072B2", "#CC79A7", "#E69F00", "#56B4E9", "#F0E442"]
40+
NEUTRAL = "#1A1A1A" if THEME == "light" else "#E8E8E0"
41+
DIRECTION_COLORS = OKABE_ITO + [NEUTRAL]
3542

36-
# Create DataFrame - direction as categorical factor
43+
# Data - Monsoon wind pattern (SW-dominant, distinct from westerlies)
44+
directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
45+
frequencies = np.array([3, 5, 6, 12, 28, 35, 6, 5])
46+
47+
# Create DataFrame
3748
df = pd.DataFrame(
3849
{"direction": pd.Categorical(directions, categories=directions, ordered=True), "frequency": frequencies}
3950
)
4051

4152
# Create polar bar chart (wind rose)
42-
# Use coord_polar to wrap bars in a circle
4353
plot = (
4454
ggplot(df, aes(x="direction", y="frequency", fill="direction"))
45-
+ geom_bar(stat="identity", color="white", size=0.8, alpha=0.85, width=0.95)
46-
+ coord_polar(start=-np.pi / 8) # Rotate so N is at top
47-
+ scale_fill_manual(values=["#306998", "#4A90C2", "#FFD43B", "#F5A623", "#7B68EE", "#9B59B6", "#2ECC71", "#27AE60"])
55+
+ geom_bar(stat="identity", color="white", size=0.5, alpha=0.85, width=0.95)
56+
+ coord_polar(start=-np.pi / 8)
57+
+ scale_fill_manual(values=DIRECTION_COLORS)
4858
+ scale_y_continuous(limits=[0, None], expand=[0, 0.5])
49-
+ labs(title="polar-bar · letsplot · pyplots.ai", x="", y="Frequency (%)")
59+
+ labs(title="polar-bar · letsplot · anyplot.ai", x="", y="Frequency (%)")
5060
+ theme_minimal()
5161
+ theme(
52-
plot_title=element_text(size=24, face="bold"),
53-
axis_title_y=element_text(size=18),
54-
axis_text=element_text(size=14),
55-
legend_position="none", # Hide legend (labels shown around chart)
56-
panel_grid_major=element_line(color="#CCCCCC", size=0.3),
62+
plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
63+
panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
64+
panel_grid_major=element_line(color=INK_SOFT, size=0.3),
65+
plot_title=element_text(size=24, color=INK, face="bold"),
66+
axis_title_y=element_text(size=20, color=INK),
67+
axis_text=element_text(size=16, color=INK_SOFT),
68+
legend_position="none",
5769
)
58-
+ ggsize(1200, 1200) # Square for polar chart
70+
+ ggsize(1200, 1200)
5971
)
6072

61-
# Save as PNG (scale 3x for high resolution: 3600x3600 for square polar)
62-
ggsave(plot, "plot.png", scale=3, path=".")
63-
64-
# Save interactive HTML
65-
ggsave(plot, "plot.html", path=".")
73+
# Save as PNG and HTML (theme-suffixed)
74+
ggsave(plot, f"plot-{THEME}.png", scale=3, path=".")
75+
ggsave(plot, f"plot-{THEME}.html", path=".")

0 commit comments

Comments
 (0)