Skip to content

Instantly share code, notes, and snippets.

@barrysmyth
Last active April 11, 2020 21:42
Show Gist options
  • Save barrysmyth/c51a8aec88d77c02f5f1e7de3fcbbf66 to your computer and use it in GitHub Desktop.
Save barrysmyth/c51a8aec88d77c02f5f1e7de3fcbbf66 to your computer and use it in GitHub Desktop.
A short snippet of code to reproduce the BBC's COVID-19 lockdown chart.
fig, ax = plt.subplots(figsize=(30, len(use_countries)*1.25))
# ----------------------------
# The Stringency Index Heatmap
# ----------------------------
# For maximum flexibility we use a separate axis to plot the heatmap's
# colour bar (horizontally) as the SI legend.
cbar_ax = fig.add_axes([.15, .17, .38, 3/len(stringency_for_country_by_date)])
# The heatmap itself is straightfoward with one caveat: after much fiddling I had to
# set its xticklabels parameter to the date interval we are using.
sns.heatmap(stringency_for_country_by_date.loc[use_countries], ax=ax,
linewidths=1, cmap=stringency_cmap, cbar=True, xticklabels=date_interval, zorder=10,
cbar_ax=cbar_ax, cbar_kws=dict(orientation='horizontal', ticks=[])
)
# ----------------------------
# The First Cases Heatmap
# ----------------------------
# The first cases plot doesn't look like a heatmap. It looks like a variation of a
# line graph, but this doesn't work. Notice that the first case markers for each country
# are not regular matplotlib markers, they are vertical lines that align and match with the
# the SI cells.
bx = ax.twinx() # We need a duplicate axis
# The first cases heatmap
sns.heatmap(first_cases_for_country_by_date.loc[use_countries], ax=ax,
linewidths=.15, cmap=['k'], cbar=False, xticklabels=14, zorder=10)
# ----------------------------
# Axes, labels & grid-lines
# ----------------------------
ax.set_xticklabels(date_labels)
# We want a duplicate x axis on the top too.
ax2 = ax.twiny()
ax2.set_xticks(ax.get_xticks())
ax2.set_xticklabels(ax.get_xticklabels())
# Remove axes ticks
ax.tick_params(axis='both', length = 0)
ax2.tick_params(axis='both', length = 0)
# Draw the vertical gridlines
ax.grid(axis='x', lw=2)
# We dont need labels for the x axes.
ax.set_xlabel('')
ax.set_ylabel('')
# Shift the y axis labels to the right-hand side.
ax.set_yticklabels(ax.get_yticklabels(), rotation=0, fontweight='bold')
ax.yaxis.tick_right()
# We don't need the y-axis ticks/labels for teh second y-axis.
bx.set_yticks([])
bx.set_yticklabels([])
ax.set_xlim(14)
bx.set_xlim(14)
# Remove the frame around the plot
sns.despine(left=True, bottom=True, right=True)
# A title and key for the SI legend.
bx.annotate('Stringency Index', xy=(.04, .1), xycoords='axes fraction', fontweight='bold')
cbar_ax.annotate(' Low Medium High Very High', xy=(.04, .3), xycoords='axes fraction', fontsize=40, fontweight='bold', color='white')
# A title for the graph.
ax.set_title('Countries in Lockdown (2020)\n', fontweight='bold', loc='left')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment