Donut#
Download this notebook from GitHub (right-click to download).
Title: Donut Element#
Dependencies: Matplotlib
Backends: Bokeh, Matplotlib
The Donut Element represents proportional data as wedges of an annular ring. The key dimension provides the category for each slice and the value dimension determines the slice size.
A Donut can be created from a list of tuples where each tuple contains a category and its corresponding value.
data = [('Rent', 1200), ('Food', 400), ('Transport', 200), ('Entertainment', 150)]
d = hv.Donut(data)
d
We can achieve the same plot using a Pandas DataFrame.
df = pd.DataFrame(
{
'Category': ['Rent', 'Food', 'Transport', 'Entertainment'],
'Amount': [1200, 400, 200, 150],
'Cumulative': [1200, 1600, 1800, 1950],
}
)
hv.Donut(df, kdims=['Category'], vdims=['Amount', 'Cumulative'])
Donut charts also support numeric categories, such as years.
yearly = pd.DataFrame(
{
'Year': [2021, 2022, 2023, 2024],
'Amount': [100, 140, 180, 220],
}
)
hv.Donut(yearly, kdims='Year', vdims='Amount')
Rows with a missing category or missing value are skipped when the donut is rendered.
missing = pd.DataFrame(
{
'Category': ['Rent', 'Food', 'Transport', None, 'Other'],
'Amount': [1200, 400, 200, 300, pd.NA],
}
)
hv.Donut(missing, kdims='Category', vdims='Amount')
Use start_angle to rotate the first wedge.
d.opts(start_angle=1.2)
Text labels can be placed next to each wedge with show_labels=True.
d = hv.Donut(df, kdims='Category', vdims='Amount')
d.opts(show_labels=True, show_legend=False, inner_radius=0.2)
Alternatively, show_labels can be a template string using dimension names and fraction. Zoom out using padding to prevent labels from being clipped.
(
d.clone().opts(show_labels='{Category}: {fraction:.1%}',).relabel('Category and share')
+ d.clone().opts(show_labels='${Amount:,.0f}').relabel('Value only')
).cols(3)
Label styling can be controlled with label_radius, label_text_align, label_text_baseline, label_font_size, and label_text_color.
d.opts(
show_labels="{Category}\n{fraction:.1%}",
label_radius=1.1,
label_text_align='right',
label_text_baseline='center',
label_font_size=8,
label_text_color='firebrick',
)
A center label can display the total or any custom text using center_label.
Set it to 'total' to compute and format the sum of all values.
d = d.opts(center_label='total', center_font_size=10, inner_radius=0.9)
d
center_label also accepts template strings. Available placeholders include {total}, {total_formatted}, and the value-dimension name.
(
d.clone().opts(center_label='Budget mix').relabel('Static label')
+ d.clone().opts(center_label='The total was\n{total:,.0f}').relabel('Template')
+ d.clone().opts(
center_label="Monthly total\n${total:,.0f}",
center_text_color='red',
).relabel('Styled center label')
).cols(3)
Datetime categories are also supported and can be formatted in label templates.
dated = pd.DataFrame(
{
'date': pd.to_datetime(['2024-01-01', '2024-02-01', '2024-03-01', '2024-04-01']),
'Amount': [1200, 900, 600, 300],
}
)
hv.Donut(dated, kdims='date', vdims='Amount').opts(
show_labels="{date:%b %Y} {fraction:.1%}",
show_legend=False,
)
The inner_radius option controls the size of the hole. Setting it to 0 produces a pie chart while a larger inner_radius creates a thinner ring. outer_radius can be used to scale the donut itself.
d = d.opts(show_legend=False, center_label=None, label_text_color="black")
(
d.clone().opts(inner_radius=0).relabel('Pie') +
d.clone().opts(inner_radius=0.2).relabel('Default')
+ d.clone().opts(inner_radius=0.4).relabel('Thin ring')
+ d.clone().opts(inner_radius=0.7, outer_radius=1.2).relabel('Thin ring, larger radius')
).cols(4)
The color palette can be changed using the cmap style option.
(
d.clone().opts(cmap='Set2').relabel('Named palette')
+ d.clone().opts(cmap=['black', 'brown', 'tan', 'gray']).relabel('Custom list')
+ d.clone().opts(
cmap={
'Rent': '#1d4ed8',
'Food': '#16a34a',
'Transport': '#f59e0b',
'Entertainment': '#ef4444',
}
).relabel('Category map')
).cols(3)
Border styling uses the normal Bokeh line properties.
To make borders visible, set alpha=1 in addition to edgecolor and linewidth.
d.opts(
edgecolor='white',
linewidth=4,
alpha=1,
)
For full documentation and the available style and plot options, use hv.help(hv.Donut).
Download this notebook from GitHub (right-click to download).