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', legend=False, legend_bins=4, legend_labels=None, legend_labels_precision=None, legend_labels_kws=None, 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
|
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 |
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 |
None
|
edgecolor
|
str
|
Color of the edges for each day's rectangle. |
'black'
|
edgewidth
|
float
|
Line width for the edges of each day's rectangle. |
0.0
|
cmap
|
Union[str, LinearSegmentedColormap]
|
A valid Matplotlib colormap name or a LinearSegmentedColormap instance. The |
'Greens'
|
week_starts_on
|
str
|
The starting day of the week, which can be specified as a string ("Sunday", "Monday", ..., "Saturday"). |
'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 |
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 |
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, |
None
|
boxstyle
|
Union[str, BoxStyle]
|
The style of each box. This will be passed to |
'square'
|
legend
|
bool
|
Whether to display a legend for the color scale. |
False
|
legend_bins
|
int
|
Number of boxes/steps to display in the legend. |
4
|
legend_labels
|
Optional[Union[List, Literal['auto']]]
|
Labels for the legend boxes. Can be a list of strings or "auto" to generate labels from the data values. |
None
|
legend_labels_precision
|
Optional[int]
|
Number of decimal places to round legend labels when
|
None
|
legend_labels_kws
|
Optional[Dict]
|
Additional keyword arguments passed to the matplotlib text function when rendering legend labels. |
None
|
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
|
Any additional arguments that will be passed to |
{}
|
Returns:
| Type | Description |
|---|---|
List[Rectangle]
|
A list of |
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.