About

This plot is a waffle chart, with small mutliples. It shows the recycling rates per London borough. The size of each square is proportional to the recycling rate. The chart is made with the pywaffle library.

The chart was made by Lisa Hornung. Thanks to her for accepting sharing her work here!

Let's see what the final picture will look like:

small multiple waffle chart

Libraries

First, you need to install the following librairies:

  • matplotlib is used for creating the chart and add customization features
  • pandas is used to read the data
  • pywaffle is used to create the waffle chart
  • flexitext: to add beautiful annotations to the chart

And that's it!

import pandas as pd
import matplotlib.pyplot as plt
from pywaffle import Waffle
from flexitext import flexitext
from matplotlib import font_manager

Dataset

For this reproduction, we're going to retrieve the data directly from the gallery's Github repo. This means we just need to give the right url as an argument to pandas' read_csv() function to retrieve the data.

url = "https://raw.githubusercontent.com/holtzy/the-python-graph-gallery/master/static/data/london_recycling.csv"

df = pd.read_csv(url)
df.head()
household_waste_recycled_dry_perc household_waste_recycled_green_perc household_waste_not_recycled_perc_est Display_name
0 21.0 12.0 67.0 BAR
1 19.0 9.0 72.0 BRN
2 21.0 13.0 66.0 BRT
3 19.0 8.0 73.0 CMD
4 34.0 14.0 52.0 ELG

Initialize parameters

Before creating the plot, we first need to define different elements:

  • the layout of the small multiples
layout = [
    ["___","___","___","___","ENF","___","___","___"],
    ["___","___","HRW","BRN","HGY","WTH","___","___"],
    ["HDN","ELG","BRT","CMD","ISL","HCK","RDB","HVG"],
    ["HNS","HMS","KNS","WST","CTY","TOW","NWM","BAR"],
    ["___","RCH","WNS","LAM","SWR","LSH","GRN","BXL"],
    ["___","___","KNG","MRT","CRD","BRM","___","___"],
    ["___","___","___","STN","___","___","___","___"],
]
  • the font: remember to change my_path value to the path of the font on your computer. You can learn more about font management in this post
# load fonts
my_path = '/Users/josephbarbier/Library/Fonts'
label_font = font_manager.FontProperties(fname=f'{my_path}/Roboto-Medium.ttf')
title_font = font_manager.FontProperties(fname=f'{my_path}/LilitaOne-Regular.ttf')
  • a color mapping
colors = {
   "dry": "#22A2AA",
   "green": "#81CE9C",
   "none": "#fbfaf9",
   "value": "#0B4465",
   "bg": "#fbfaf9"
}

We can now develop the plot! The main step is to generate a figure with a grid of subplots. After that, we iterate through each axis to construct a waffle chart.

# layout
scale_factor = 1.8
fig, axs = plt.subplot_mosaic(layout, figsize=(8*scale_factor,7*scale_factor), empty_sentinel="___")
plt.subplots_adjust(wspace=0.25, hspace=0.25, left=0.05, right=0.95, bottom=0.05)
fig.set_facecolor(colors["bg"])

plt.show()

We easily recognize the shape of the layout defined above!

Fill the grid

Once the grid is created, we can fill it with the waffle charts. We iterate through each axis to create a waffle chart. We use the pywaffle library to create the waffle chart. We also add a title to each subplot.

# setup
columns =  [
    'household_waste_recycled_dry_perc',
    'household_waste_recycled_green_perc',
    'household_waste_not_recycled_perc_est'
]

# layout
scale_factor = 1.8
fig, axs = plt.subplot_mosaic(layout, figsize=(8*scale_factor,7*scale_factor), empty_sentinel="___")
plt.subplots_adjust(wspace=0.25, hspace=0.25, left=0.1, right=0.9, top=0.9, bottom=0.1)
fig.set_facecolor(colors["bg"])


# plot data
for ax in axs:
    data_filtered = df[df["Display_name"]==ax]
    y_values = data_filtered[columns].values.tolist()[0]
    Waffle.make_waffle(
        ax=axs[ax],
        rows=10,
        values=y_values,
        colors=[colors["dry"],
        colors["green"],
        colors["none"]],
        interval_ratio_x=0.35,
        interval_ratio_y=0.35,
        vertical=True,
        zorder=1
    )

    #display % value and borough
    axs[ax].text(
        0.95,
        0.8,
        str(int(y_values[0] + y_values[1]))+"%",
        ha="right",
        va='top',
        fontsize=20,
        color=colors["value"],
        fontproperties=title_font
    )
    axs[ax].text(
        0.95,
        0.95,
        ax,
        fontsize=10,
        ha="right",
        va='top',
        color=colors["value"],
        zorder=3,
        fontproperties=label_font
    )

# title and footer
fig.text(
    0.5,
    1,
    "Recycling rates by London borough",
    fontsize=38,
    ha='center',
    va="top",
    fontweight="bold",
    fontproperties=title_font,
    color=colors["value"]
)
fig.text(
    0.7,
    0.055,
    "Source: Defra",
    fontsize=11,
    ha='right',
    va="center",
    fontweight="normal",
    fontproperties=label_font,
    linespacing=1.5, color="black"
)
subtitle = (
    "<size:20>% of household waste sent for "
    "<color:#22A2AA, weight:bold>DRY</> or <color:#81CE9C, weight:bold>GREEN</> recycling, 2022/23</>"
)
flexitext(0.5, 1-0.075, subtitle, va="bottom", ha="center", xycoords="figure fraction")

plt.savefig("../../static/graph/web-waffle-with-small-multiples.png", dpi=300)
plt.show()

Going further

This article explains how to reproduce a small multiple waffle chart with annotations, colormap and nice other features.

You might be interested in:

Contact & Edit


👋 This document is a work by Yan Holtz. You can contribute on github, send me a feedback on twitter or subscribe to the newsletter to know when new examples are published! 🔥

This page is just a jupyter notebook, you can edit it here. Please help me making this website better 🙏!