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 |
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 |
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'
|
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 |
{}
|
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.