Skip to content

Calendar Heatmap

The Calendar Heatmap component works with timeseries data to visualise counts over a calendar year.

import altair as alt
import datapane as dp
import pandas as pd 
from vega_datasets import data

Wrangling and visualisation functions

def wrangle_df(df, year=None):
    df = df.set_index("Date")
    df.index = pd.DatetimeIndex(df.index)

    # If not after a specific year, use year from last sample date
    last_sample_date = df.index.max()
    if not year:
        year = last_sample_date.year

    # Subsample to samples from the same year
    df = df[df.index.year == year]

    # Fill our DataFrame so there's a sample for every day of the year
    idx = pd.date_range(f"01-01-{year}", f"12-31-{year}")
    df = df.reindex(idx, fill_value=0)
    df["Date"] = df.index

    return df, year, last_sample_date
def plot_calendar_heatmap(
    metric,
    df_yt_analytics,
    labels=True,
    legend=True,
    color_scheme="viridis",
    height=120,
):
    chart = (
        alt.Chart(df_yt_analytics)
        .mark_rect(stroke="white", strokeWidth=2)
        .encode(
            alt.X(
                "week(Date):T",
                title=None,
                axis=alt.Axis(
                    grid=False,
                    labels=labels,
                    ticks=False,
                    domain=False,
                    tickCount="month",
                    format="%b",
                ),
            ),
            alt.Y(
                "day(Date):T",
                sort="descending",
                title=None,
                axis=alt.Axis(
                    labelBaseline="top",
                    grid=False,
                    labels=labels,
                    ticks=False,
                    domain=False,
                    tickCount={"interval": "day", "step": 3},
                ),
            ),
            alt.Color(
                f"{metric}:Q",
                legend=alt.Legend() if legend else None,
                title=None,
                scale=alt.Scale(scheme=color_scheme),
            ),
            tooltip=["Date", f"{metric}"],
        )
        .configure_view(strokeWidth=0)
        .configure_axis(labelFontSize=12)
        .properties(width="container", height=height)
    )

    return chart

Load and wrangle data

The wrangling and visualisation functions expect a pandas DataFrame with two columns: - Date: Unique dates corresponding to some measure. - Incidents: containing the value counts, e.g. number of incidents on a particular day.

df_birdstrikes = data.birdstrikes()

df_daily_incidents = pd.DataFrame(
    df_birdstrikes["Flight_Date"].value_counts()
).reset_index()
df_daily_incidents.columns = ["Date", "Incidents"]

The name of the value counts column, e.g. Incidents, can be anything. If you change the column name, be sure to update the corresponding argument to plot_calendar_heatmap.

The samples will look something like the following.

Date Incidents
0 10/19/99 0:00 16
1 10/24/90 0:00 14
2 8/13/98 0:00 13
3 10/25/95 0:00 11
4 9/13/00 0:00 11

Now we can pass this DataFrame to the provided function for wrangling. Specify the year to be visualised below, or omit it to visualise the latest year available.

df, year, last_sample_date = wrangle_df(df_daily_incidents, year=2000)

Build app

plot_heatmap = dp.Plot(
    plot_calendar_heatmap("Incidents", df, legend=True, color_scheme="viridis")
)

app = dp.App(plot_heatmap)

app.save(path="calendar-heatmap-component.html", open=True)