Skip to content

Calendar heatmaps


dayplot.calendar

calendar(dates, values, start_date=None, end_date=None, color_for_none=None, edgecolor='black', edgewidth=0.0, cmap='Greens', week_starts_on='Sunday', month_kws=None, day_kws=None, day_x_margin=0.02, month_y_margin=0.4, vmin=None, vmax=None, vcenter=None, boxstyle='square', clip_on=False, ax=None, **kwargs)

Create a calendar heatmap (GitHub-style) from input dates and values, supporting both positive and negative values via a suitable colormap scale.

This function generates a calendar heatmap similar to GitHub's contribution graph, where each cell represents a day colored according to the corresponding value. The chart is organized by weeks (columns) and days of the week (rows), starting from a specified start date to an end date.

When vmin, vmax, and vcenter are not specified, they default to the data's minimum, maximum, and zero (if data spans negative and positive values), respectively. Providing any of vmin, vmax, or vcenter manually will override the automatic calculation for that parameter.

Parameters:

Name Type Description Default
dates List[Union[date, datetime, str]]

A list of date-like objects (e.g., datetime.date, datetime.datetime, or strings in "YYYY-MM-DD" format). Must have the same length as values.

required
values List[Union[int, float]]

A list of numeric values corresponding to each date in dates. These values represent contributions or counts for each day and must have the same length as dates.

required
start_date Optional[Union[date, datetime, str]]

The earliest date to display on the chart. Can be a date, datetime, or a string in "YYYY-MM-DD" format. If not provided, the minimum date found in dates will be used.

None
end_date Optional[Union[date, datetime, str]]

The latest date to display on the chart. Can be a date, datetime, or a string in "YYYY-MM-DD" format. If not provided, the maximum date found in dates will be used.

None
color_for_none Optional[str]

Color to use for days with no contributions (i.e., count zero). Defaults to "#e8e8e8", a light gray color. This parameter is ignored when values has negative values.

None
edgecolor str

Color of the edges for each day's rectangle. Defaults to "black".

'black'
edgewidth float

Line width for the edges of each day's rectangle. Defaults to 0.5.

0.0
cmap Union[str, LinearSegmentedColormap]

A valid Matplotlib colormap name or a LinearSegmentedColormap instance. Defaults to "Greens". The colormap is used to determine the fill color intensity of each day's cell based on its value.

'Greens'
week_starts_on str

The starting day of the week, which can be specified as a string ("Sunday", "Monday", ..., "Saturday"). Defaults to "Sunday".

'Sunday'
month_kws Optional[Dict]

Additional keyword arguments passed to the matplotlib.axes.Axes.text function when labeling month names (outside of x, y and s).

None
day_kws Optional[Dict]

Additional keyword arguments passed to the matplotlib.axes.Axes.text function when labeling weekday names on the y-axis (outside of x, y and s).

None
day_x_margin float

Distance between the day labels (Monday, Tuesday, etc.) and the graph. The greater the distance, the further to the left the text will be.

0.02
month_y_margin float

Distance between the month labels (January, February, etc.) and the graph. The greater the distance, the more text will appear at the top.

0.4
vmin Optional[float]

The lower bound for the color scale. If None, it is determined automatically from the data. If data contains both positive and negative values and vcenter is not provided, vmin will default to the data's minimum. Providing vmin overrides the automatic calculation.

None
vmax Optional[float]

The upper bound for the color scale. If None, it is determined automatically from the data. If data contains both positive and negative values and vcenter is not provided, vmax will default to the data's maximum. Providing vmax overrides the automatic calculation.

None
vcenter Optional[float]

The midpoint for the color scale, typically used with diverging colormaps (e.g., "RdBu") to position a central reference (e.g., zero). If None and the data spans negative and positive values, vcenter will default to 0. Providing vcenter overrides this automatic setting.

None
boxstyle Union[str, BoxStyle]

The style of each box. This will be passed to matplotlib.patches.FancyBboxPatch. Available values are: "square", "circle", "ellipse", "larrow"

'square'
clip_on bool

Whether the artist (e.g., squares) is clipped to the axes boundaries (True) or allowed to extend beyond them (False).

False
ax Optional[Axes]

A matplotlib axes. If None, plt.gca() will be used. It is advisable to make this explicit to avoid unexpected behaviour, particularly when manipulating a figure with several axes.

None
kwargs

Any additional arguments that will be passed to matplotlib.patches.FancyBboxPatch. For example, you can set alpha, hatch, linestyle, etc. You can find them all here.

{}

Returns:

Type Description
List[Rectangle]

A list of matplotlib.patches.FancyBboxPatch (one for each cell).

Notes

The function aggregates multiple entries for the same date by summing their values.


Examples

Basic usage

# mkdocs: render
import matplotlib.pyplot as plt
import dayplot as dp

df = dp.load_dataset()

fig, ax = plt.subplots(figsize=(15, 5))
dp.calendar(
   df["dates"],
   df["values"],
   start_date="2024-01-01",
   end_date="2024-12-31"
)

Change colormap

# mkdocs: render
import matplotlib.pyplot as plt
import dayplot as dp

df = dp.load_dataset()

fig, ax = plt.subplots(figsize=(15, 5))
dp.calendar(
   df["dates"],
   df["values"],
   cmap="Reds",
   start_date="2024-01-01",
   end_date="2024-12-31"
)

Change other colors

# mkdocs: render
import matplotlib.pyplot as plt
import dayplot as dp

df = dp.load_dataset()

fig, ax = plt.subplots(figsize=(15, 5))
dp.calendar(
   df["dates"],
   df["values"],
   start_date="2024-01-01",
   end_date="2024-12-31",
   color_for_none="pink",
   edgecolor="white",
   edgewidth=0.4,
   day_kws={"color": "skyblue"},
   month_kws={"color": "red"},
   ax=ax,
)
fig.set_facecolor("black")
ax.set_facecolor("black")

Boxstyle

# mkdocs: render
import matplotlib.pyplot as plt
import dayplot as dp

df = dp.load_dataset()

fig, ax = plt.subplots(figsize=(15, 5))
dp.calendar(
   dates=df["dates"],
   values=df["values"],
   start_date="2024-01-01",
   end_date="2024-12-31",
   boxstyle="circle",
   ax=ax,
)

Fill the gap

# mkdocs: render
import matplotlib.pyplot as plt
import dayplot as dp

df = dp.load_dataset()

fig, ax = plt.subplots(figsize=(15, 5))
dp.calendar(
   dates=df["dates"],
   values=df["values"],
   start_date="2024-01-01",
   end_date="2024-12-31",
   mutation_scale=1.22, # 22% bigger boxes
   ax=ax,
)

Label style

# mkdocs: render
import matplotlib.pyplot as plt
import dayplot as dp

df = dp.load_dataset()

fig, ax = plt.subplots(figsize=(15, 5))
dp.calendar(
   dates=df["dates"],
   values=df["values"],
   start_date="2024-01-01",
   end_date="2024-12-31",
   day_kws={"weight": "bold", "size": 12},
   month_kws={"size": 20, "color": "red"},
   day_x_margin=0.05,  # default = 0.02
   month_y_margin=0.8,  # default = 0.4
   ax=ax,
)

Combine calendars

# mkdocs: render
import matplotlib.pyplot as plt
import dayplot as dp

df = dp.load_dataset()

fig, (ax1, ax2) = plt.subplots(
   nrows=2,
   figsize=(16, 4)
)

dp.calendar(
    dates=df["dates"],
    values=df["values"],
    start_date="2025-01-01",
    end_date="2025-12-31",
    ax=ax1, # top axes
)

dp.calendar(
    dates=df["dates"],
    values=df["values"],
    start_date="2024-01-01",
    end_date="2024-12-31",
    ax=ax2, # bottom axes
)

text_args = dict(x=-4, y=3.5, size=30, rotation=90, color="#aaa", va="center")
ax1.text(s="2024", **text_args)
ax2.text(s="2025", **text_args)

Advanced

See advanced usage here.