Annotated Heatmap

heatmap
text
Author

Hassan Kibirige

import pandas as pd
import numpy as np

from plotnine import (
    ggplot,
    aes,
    geom_tile,
    geom_text,
    scale_y_reverse,
    scale_y_discrete,
    scale_fill_brewer,
    scale_color_manual,
    coord_equal,
    theme,
    theme_void,
    element_blank,
    element_rect,
    element_text,
)

Conditinous data recorded at discrete time intervals over many cycles

Read data

flights = pd.read_csv("data/flights.csv")
months = flights["month"].unique()  # Months ordered January, ..., December
flights["month"] = pd.Categorical(flights["month"], categories=months)
flights.head()
year month passengers
0 1949 January 112
1 1949 February 118
2 1949 March 132
3 1949 April 129
4 1949 May 121
# We use 'factor(year)' -- a discrete -- instead of 'year' so that all the years
# are displayed along the x-axis.
# The .95s create spacing between the tiles.

(
    ggplot(flights, aes("factor(year)", "month", fill="passengers"))
    + geom_tile(aes(width=0.95, height=0.95))
    + geom_text(aes(label="passengers"), size=9)
)

That looks like what we want, but it could do with a few tweaks. First the contrast between the tiles and the text is not good for the lower passenger numbers. We use pd.cut to partition the number of passengers into two discrete groups.

flights["p_group"] = pd.cut(
    flights["passengers"], (0, 300, 1000), labels=("low", "high")
)
flights.head()
year month passengers p_group
0 1949 January 112 low
1 1949 February 118 low
2 1949 March 132 low
3 1949 April 129 low
4 1949 May 121 low
(
    ggplot(flights, aes("factor(year)", "month", fill="passengers"))
    + geom_tile(aes(width=0.95, height=0.95))
    + geom_text(aes(label="passengers", color="p_group"), size=9, show_legend=False)  # modified
    + scale_color_manual(["white", "black"])  # new
)

Last tweaks, put January at the top and remove the axis ticks and plot background.

(
    ggplot(flights, aes("factor(year)", "month", fill="passengers"))
    + geom_tile(aes(width=0.95, height=0.95))
    + geom_text(aes(label="passengers", color="p_group"), size=9, show_legend=False)
    + scale_color_manual(["white", "black"])  # new
    + scale_y_discrete(limits=months[::-1])  # new
    + theme(  # new
        axis_ticks=element_blank(),
        panel_background=element_rect(fill="white"),
    )
)

You can get similar results if you replace

 + geom_tile(aes(width=.95, height=.95))
 + geom_text(aes(label='passengers', color='p_group'), size=9, show_legend=False)

with

+ geom_label(aes(label='passengers', color='p_group'), size=9, show_legend=False)

Credit: This example is a recreation of this seaborn example.