Skip to content

Commit 8e5f1cb

Browse files
feat(plotly): implement polar-bar (#6505)
## Implementation: `polar-bar` - python/plotly Implements the **python/plotly** version of `polar-bar`. **File:** `plots/polar-bar/implementations/python/plotly.py` **Parent Issue:** #2693 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25771631680)* --------- 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 0bb321e commit 8e5f1cb

2 files changed

Lines changed: 205 additions & 192 deletions

File tree

Lines changed: 44 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,78 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
polar-bar: Polar Bar Chart (Wind Rose)
3-
Library: plotly 6.5.0 | Python 3.13.11
4-
Quality: 91/100 | Created: 2025-12-30
3+
Library: plotly 6.7.0 | Python 3.13.13
4+
Quality: 88/100 | Updated: 2026-05-13
55
"""
66

7+
import os
8+
79
import numpy as np
810
import plotly.graph_objects as go
911

1012

13+
# Theme tokens
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+
GRID = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)"
20+
21+
# Okabe-Ito palette (first series always #009E73)
22+
OKABE_ITO = ["#009E73", "#D55E00", "#0072B2"]
23+
wind_speed_labels = ["Light (0-10 km/h)", "Moderate (10-20 km/h)", "Strong (20+ km/h)"]
24+
1125
# Data: Wind speed distribution by direction (8 compass points)
12-
# Each direction has 3 speed ranges (stacked bars)
1326
np.random.seed(42)
14-
1527
directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
1628

17-
# Wind speed frequencies by direction (simulating typical coastal wind patterns)
18-
# Light breeze (0-10 km/h)
29+
# Wind speed frequencies by direction (coastal wind pattern)
1930
light = np.array([8, 5, 4, 3, 6, 12, 15, 10])
20-
# Moderate breeze (10-20 km/h)
2131
moderate = np.array([6, 4, 3, 2, 4, 10, 12, 8])
22-
# Strong breeze (20+ km/h)
2332
strong = np.array([3, 2, 1, 1, 2, 5, 6, 4])
2433

2534
# Create figure with polar subplot
2635
fig = go.Figure()
2736

28-
# Add stacked bars for each wind speed category (base is cumulative)
29-
fig.add_trace(
30-
go.Barpolar(
31-
r=light,
32-
theta=directions,
33-
name="Light (0-10 km/h)",
34-
marker=dict(color="#306998", line=dict(color="white", width=2)),
35-
opacity=0.9,
36-
)
37-
)
38-
39-
fig.add_trace(
40-
go.Barpolar(
41-
r=moderate,
42-
theta=directions,
43-
name="Moderate (10-20 km/h)",
44-
marker=dict(color="#FFD43B", line=dict(color="white", width=2)),
45-
opacity=0.9,
46-
)
47-
)
48-
49-
fig.add_trace(
50-
go.Barpolar(
51-
r=strong,
52-
theta=directions,
53-
name="Strong (20+ km/h)",
54-
marker=dict(color="#4ECDC4", line=dict(color="white", width=2)),
55-
opacity=0.9,
37+
# Add stacked bars for each wind speed category
38+
for data, label, color in zip([light, moderate, strong], wind_speed_labels, OKABE_ITO, strict=True):
39+
fig.add_trace(
40+
go.Barpolar(
41+
r=data,
42+
theta=directions,
43+
name=label,
44+
marker=dict(color=color, line=dict(color=PAGE_BG, width=2)),
45+
hovertemplate="<b>%{theta}</b><br>%{customdata}<br>Frequency: %{r}<extra></extra>",
46+
customdata=[label] * len(directions),
47+
opacity=0.9,
48+
)
5649
)
57-
)
5850

59-
# Update layout for polar chart
51+
# Update layout for polar chart with theme-adaptive styling
6052
fig.update_layout(
61-
title=dict(text="polar-bar · plotly · pyplots.ai", font=dict(size=32, color="#333"), x=0.5, y=0.95),
53+
title=dict(text="polar-bar · plotly · anyplot.ai", font=dict(size=28, color=INK), x=0.5, xanchor="center"),
54+
paper_bgcolor=PAGE_BG,
55+
plot_bgcolor=PAGE_BG,
6256
polar=dict(
6357
barmode="stack",
6458
radialaxis=dict(
6559
visible=True,
6660
range=[0, max(light + moderate + strong) + 3],
67-
tickfont=dict(size=18),
68-
tickangle=45,
69-
gridcolor="rgba(0,0,0,0.2)",
70-
linecolor="rgba(0,0,0,0.3)",
71-
title=dict(text="Frequency (%)", font=dict(size=18)),
61+
tickfont=dict(size=18, color=INK_SOFT),
62+
gridcolor=GRID,
63+
linecolor=INK_SOFT,
64+
title=dict(text="Frequency", font=dict(size=20, color=INK)),
7265
),
7366
angularaxis=dict(
74-
tickfont=dict(size=22, color="#333"),
75-
direction="clockwise",
76-
rotation=90, # N at top
77-
gridcolor="rgba(0,0,0,0.15)",
78-
linecolor="rgba(0,0,0,0.3)",
67+
tickfont=dict(size=22, color=INK), direction="clockwise", rotation=90, gridcolor=GRID, linecolor=INK_SOFT
7968
),
80-
bgcolor="rgba(255,255,255,0.95)",
8169
),
8270
legend=dict(
83-
font=dict(size=20),
84-
x=0.85,
85-
y=0.95,
86-
bgcolor="rgba(255,255,255,0.9)",
87-
bordercolor="rgba(0,0,0,0.2)",
88-
borderwidth=1,
71+
font=dict(size=18, color=INK_SOFT), x=0.85, y=0.95, bgcolor=ELEVATED_BG, bordercolor=INK_SOFT, borderwidth=1
8972
),
90-
template="plotly_white",
91-
margin=dict(l=80, r=180, t=120, b=80),
73+
margin=dict(l=100, r=200, t=120, b=100),
9274
)
9375

94-
# Save as PNG (4800 x 2700 px)
95-
fig.write_image("plot.png", width=1600, height=900, scale=3)
96-
97-
# Save interactive HTML
98-
fig.write_html("plot.html", include_plotlyjs=True, full_html=True)
76+
# Save as PNG (4800 x 2700 px) and interactive HTML
77+
fig.write_image(f"plot-{THEME}.png", width=1600, height=900, scale=3)
78+
fig.write_html(f"plot-{THEME}.html", include_plotlyjs="cdn")

0 commit comments

Comments
 (0)