-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaltair.py
More file actions
130 lines (109 loc) · 4.17 KB
/
altair.py
File metadata and controls
130 lines (109 loc) · 4.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
""" anyplot.ai
rose-basic: Basic Rose Chart
Library: altair 6.1.0 | Python 3.13.13
Quality: 87/100 | Updated: 2026-04-30
"""
import os
import altair as alt
import numpy as np
import pandas as pd
# Theme
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
# Data - Monthly rainfall in mm (12-month cyclical pattern)
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
rainfall = [78, 52, 68, 45, 35, 28, 22, 30, 55, 85, 92, 88]
n = len(months)
angle_step = 360 / n
start_angles = [-90 + i * angle_step for i in range(n)]
end_angles = [-90 + (i + 1) * angle_step for i in range(n)]
df = pd.DataFrame(
{"month": months, "value": rainfall, "startAngle": np.radians(start_angles), "endAngle": np.radians(end_angles)}
)
max_val = 100
chart_radius = 460
# Radial gridlines at 25, 50, 75, 100 mm
grid_values = [25, 50, 75, 100]
grid_data = pd.DataFrame({"value": grid_values})
gridlines = (
alt.Chart(grid_data)
.mark_arc(filled=False, stroke=INK_SOFT, strokeWidth=1.0, strokeOpacity=0.35, strokeDash=[6, 4])
.encode(
theta=alt.value(2 * np.pi),
radius=alt.Radius("value:Q", scale=alt.Scale(type="linear", domain=[0, max_val], range=[0, chart_radius])),
)
)
# Grid labels at 3 o'clock position
grid_label_data = pd.DataFrame(
{"value": grid_values, "label": [f"{v} mm" for v in grid_values], "theta": [0.0] * len(grid_values)}
)
grid_labels = (
alt.Chart(grid_label_data)
.mark_text(fontSize=18, dx=10, align="left", baseline="middle")
.encode(
theta=alt.Theta("theta:Q"),
radius=alt.Radius("value:Q", scale=alt.Scale(type="linear", domain=[0, max_val], range=[0, chart_radius])),
text="label:N",
color=alt.value(INK_SOFT),
)
)
# Rose chart segments — viridis colormap for value-based color encoding (12 categories)
rose = (
alt.Chart(df)
.mark_arc(stroke=PAGE_BG, strokeWidth=2, innerRadius=0)
.encode(
theta=alt.Theta("startAngle:Q", stack=None),
theta2=alt.Theta2("endAngle:Q"),
radius=alt.Radius("value:Q", scale=alt.Scale(type="linear", domain=[0, max_val], range=[0, chart_radius])),
color=alt.Color("value:Q", scale=alt.Scale(scheme="viridis"), legend=None),
tooltip=[alt.Tooltip("month:N", title="Month"), alt.Tooltip("value:Q", title="Rainfall (mm)")],
)
)
# Value labels near segment tips
mid_angles = [-90 + (i + 0.5) * angle_step for i in range(n)]
mid_angles_rad = np.radians(mid_angles)
label_radii = [max(v * 1.35, 45) if v < 35 else v * 1.15 for v in rainfall]
label_data = pd.DataFrame({"month": months, "value": rainfall, "theta": mid_angles_rad, "labelRadius": label_radii})
value_labels = (
alt.Chart(label_data)
.mark_text(fontSize=20, fontWeight="bold")
.encode(
theta=alt.Theta("theta:Q"),
radius=alt.Radius(
"labelRadius:Q", scale=alt.Scale(type="linear", domain=[0, max_val], range=[0, chart_radius])
),
text=alt.Text("value:Q"),
color=alt.value(INK),
)
)
# Month labels at outer edge — just beyond the 100 mm gridline
month_label_data = pd.DataFrame({"month": months, "theta": mid_angles_rad, "labelRadius": [115.0] * n})
month_labels = (
alt.Chart(month_label_data)
.mark_text(fontSize=22, fontWeight="bold")
.encode(
theta=alt.Theta("theta:Q"),
radius=alt.Radius(
"labelRadius:Q", scale=alt.Scale(type="linear", domain=[0, max_val], range=[0, chart_radius])
),
text=alt.Text("month:N"),
color=alt.value(INK),
)
)
# Combine all layers
chart = (
alt.layer(gridlines, grid_labels, rose, value_labels, month_labels)
.properties(
width=1200,
height=1200,
background=PAGE_BG,
title=alt.Title(text="rose-basic · altair · anyplot.ai", fontSize=32, anchor="middle", offset=20, color=INK),
)
.configure_view(strokeWidth=0, fill=PAGE_BG)
.configure_axis(grid=False, domain=False, ticks=False, labels=False, title=None)
)
# Save
chart.save(f"plot-{THEME}.png", scale_factor=3.0)
chart.save(f"plot-{THEME}.html")