# Set up plotting context, style, and fig/ax
sns.set_context('poster', font_scale=2)
with plt.xkcd(scale=0.9, length=100, randomness=200):
# Fig/axis
fig, ax = plt.subplots(1, 1, figsize=(50, 20))
sns.despine(fig) # Turn off up/right axis
# Plot both raw and rolling lines separatey for easier control
sns.lineplot(data=hr, ax=ax,
x='date', y='heart_rate',
alpha=.2, color='black',
label='Raw Heart Rate')
sns.lineplot(data=hr, ax=ax,
x='date', y='rolling_30',
color='black', linestyle='--',
linewidth=8,
label='Rolling 30 minute average')
# Add a horizontal line at 100bpm, shift legend, add a shaded block for the 23rd and annotate the 23rd/24th
ax.axhline(100, color='black', alpha=.5)
ax.legend(loc='upper left')
ax.axvspan('2021-04-23 00:00:00', '2021-04-24 00:00:00', color='silver', alpha=.05)
ax.text(.27, .80, '23rd', transform=ax.transAxes, fontsize=80)
ax.text(.85, .80, '24th', transform=ax.transAxes, fontsize=80)
# Add the annotations - the X coord needs converting to datetime
for event, time in events.items():
# Converts the first element - cleanest way I could think of
time_ = [(pd.to_datetime(t[0]), t[1]) for t in time]
# Add annotation
ax.annotate(event, *time_, arrowprops={'width': 1}, fontsize=30)
# Clean up axes, setting an x tick every four hours in date-time format, then relabelling
ax.set(ylabel='Heart Rate\nbpm', xlabel='Time', ylim=(50, 160),
xticks=[f'2021-04-{d} {h:02}:00:00' for d in [23, 24] for h in [0, 4, 8, 12, 16, 20]],
xticklabels=[f'{x:02}:00' for x in [0, 4, 8, 12, 16, 20]]*2)