6.7.9
Compress seasonal swings with a horizon chart When seasonality is large but space is limited, a horizon chart folds the bands to compact the view. Amplitude becomes color intensity, so up/down changes are intuitive.
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
import numpy as np
import matplotlib.pyplot as plt
x = np . arange ( 0 , 48 )
baseline = 120 + 30 * np . sin ( 2 * np . pi * x / 12 )
trend = 0.6 * x
rng = np . random . default_rng ( 7 )
series = baseline + trend + rng . normal ( 0 , 8 , size = x . size )
centered = series - series . mean ()
band = 20
levels = 3
palette_pos = [ "#bae6fd" , "#38bdf8" , "#0ea5e9" ]
palette_neg = [ "#fecaca" , "#f87171" , "#ef4444" ]
fig , ax = plt . subplots ( figsize = ( 6.2 , 3.6 ))
for level in range ( levels ):
upper = np . clip ( centered - level * band , 0 , band )
if np . any ( upper > 0 ):
ax . fill_between (
x ,
level * band ,
level * band + upper ,
color = palette_pos [ level ],
step = "mid" ,
)
lower = np . clip ( - centered - level * band , 0 , band )
if np . any ( lower > 0 ):
ax . fill_between (
x ,
- ( level * band + lower ),
- level * band ,
color = palette_neg [ level ],
step = "mid" ,
)
ax . axhline ( 0 , color = "#475569" , linewidth = 1 )
positions = range ( 0 , 48 , 6 )
ax . set_xticks ( positions , labels = [ f "Month { idx + 1 } " for idx , _ in enumerate ( positions )])
ax . set_yticks ([])
ax . set_title ( "Weekly sessions (deviation from baseline)" )
ax . set_xlabel ( "Week" )
ax . spines [[ "top" , "right" , "left" ]] . set_visible ( False )
fig . tight_layout ()
plt . show ()
Reading tips
# Darker bands indicate larger deviations, helping you spot peak periods quickly. Values below zero are negative deviations; warm colors emphasize declines. Lining up multiple series makes seasonal differences easy to compare in tight space.