ChaRtBot / assets /example_polar_scatter.txt
Deepa Shalini
support for dumbbell, choropleth and polar charts
d04a737
import pandas as pd
import numpy as np
import plotly.express as px
# Sample data for demonstration (full year 2024)
data = {
'date': pd.date_range('2024-01-01', periods=365, freq='D'),
'value': np.random.randint(50, 200, 365)
}
df = pd.DataFrame(data)
# Extract calendar components
df['month'] = df['date'].dt.month # 1..12
# Convert pandas weekday (Monday=0..Sunday=6) to Sun=0..Sat=6
df['weekday_sun0'] = (df['date'].dt.dayofweek + 1) % 7
# Aggregate values by month x weekday
agg = (
df.groupby(['month', 'weekday_sun0'], as_index=False)['value']
.sum()
.rename(columns={'value': 'total_value'})
)
# Ensure all 12x7 cells exist (fill missing with 0)
full = pd.MultiIndex.from_product(
[range(1, 13), range(0, 7)],
names=['month', 'weekday_sun0']
).to_frame(index=False)
agg = full.merge(agg, on=['month', 'weekday_sun0'], how='left').fillna({'total_value': 0.0})
# Labels for months and weekdays
month_labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
weekday_labels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
agg['month_name'] = agg['month'].map(lambda m: month_labels[m-1])
agg['weekday_name'] = agg['weekday_sun0'].map(lambda w: weekday_labels[w])
# Rings: 1..7 (Sun=1 inner → Sat=7 outer)
agg['r'] = agg['weekday_sun0'] + 1
# Bubble size normalization (log1p compresses large values; then scale to pixel range)
max_marker_px = 42
min_marker_px = 6
s = agg['total_value'].to_numpy(dtype=float)
s_log = np.log1p(s)
if np.allclose(s_log.max(), s_log.min()):
agg['size_px'] = min_marker_px
else:
# Scale log values to [min_marker_px, max_marker_px]
scaled = (s_log - s_log.min()) / (s_log.max() - s_log.min())
agg['size_px'] = min_marker_px + scaled * (max_marker_px - min_marker_px)
# Sizeref for area sizing
sizeref = 2.0 * agg['size_px'].max() / (max_marker_px ** 2)
# Build polar scatter chart
fig = px.scatter_polar(
agg,
r='r',
theta='month_name',
size='size_px',
size_max=max_marker_px,
color='total_value',
color_continuous_scale='Viridis',
hover_data={
'month_name': True,
'weekday_name': True,
'total_value': ':,.2f',
'r': False,
'size_px': False,
'month': False,
'weekday_sun0': False,
},
title='Circular Calendar View - Monthly Values by Weekday (2024)',
)
# Force area sizing behavior
fig.update_traces(marker=dict(sizemode='area', sizeref=sizeref, line=dict(width=0.6)))
# Clockwise months, start Jan at top
fig.update_layout(
polar=dict(
angularaxis=dict(
direction='clockwise',
rotation=90, # puts Jan at the top
),
radialaxis=dict(
tickmode='array',
tickvals=list(range(1, 8)),
ticktext=weekday_labels, # Sun..Sat
range=[0.5, 7.5],
showline=False,
gridcolor='rgba(0,0,0,0.12)',
),
),
coloraxis_colorbar=dict(title='Value'),
template='plotly_white',
margin=dict(l=40, r=40, t=70, b=40),
height=800,
)
fig.show()