How to Create a Donut Chart in Plotly
Donut charts are essentially pie charts with a blank center, creating a ring-shaped visualization. While they serve the same purpose as pie charts—showing part-to-whole relationships—the center hole...
Key Insights
- Donut charts are created in Plotly by adding a
holeparameter to pie charts—use Plotly Express for quick implementations and Graph Objects for granular control over styling and interactivity. - The center hole in donut charts reduces visual distortion compared to pie charts and provides space for displaying summary metrics like totals or percentages using annotations.
- Limit donut charts to 5-7 categories maximum, use sequential color schemes for ordered data, and always include hover templates with exact values since humans struggle to compare angles accurately.
Understanding Donut Charts and When to Use Them
Donut charts are essentially pie charts with a blank center, creating a ring-shaped visualization. While they serve the same purpose as pie charts—showing part-to-whole relationships—the center hole offers distinct advantages. The blank space reduces the emphasis on area comparison (which humans are notoriously bad at) and provides a natural location for displaying summary statistics.
Use donut charts when you need to show proportions of a categorical dataset with fewer than seven segments. They work particularly well for dashboard KPIs, budget breakdowns, or market share analysis. Avoid them for precise comparisons—bar charts handle that better—and never use them for time series data.
Plotly gives you two approaches: Plotly Express for rapid prototyping and Plotly Graph Objects for pixel-perfect control. Both produce interactive, publication-ready visualizations with hover effects, zooming, and export capabilities built in.
Creating Your First Donut Chart with Plotly Express
Plotly Express provides the fastest path to a functional donut chart. The px.pie() function handles most of the heavy lifting, and you only need to add the hole parameter to transform a pie chart into a donut.
import plotly.express as px
import pandas as pd
# Sample market share data
data = {
'Company': ['TechCorp', 'DataSystems', 'CloudNet', 'SecureIT', 'Others'],
'Market_Share': [35, 25, 20, 12, 8]
}
df = pd.DataFrame(data)
# Create basic donut chart
fig = px.pie(
df,
values='Market_Share',
names='Company',
title='Cloud Storage Market Share 2024',
hole=0.4 # This parameter creates the donut effect
)
fig.show()
The hole parameter accepts values between 0 and 1, representing the proportion of the radius. A value of 0.3-0.5 typically works best—too small and it looks like a pie chart, too large and the segments become difficult to read.
Plotly Express automatically generates a color scheme, creates hover labels, and adds a legend. For many use cases, this three-line implementation is sufficient.
Fine-Tuning with Plotly Graph Objects
When you need precise control over every visual element, Plotly Graph Objects (go.Pie()) gives you access to the full configuration API. This approach requires more code but unlocks advanced customization.
import plotly.graph_objects as go
companies = ['TechCorp', 'DataSystems', 'CloudNet', 'SecureIT', 'Others']
market_share = [35, 25, 20, 12, 8]
# Custom color palette
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8']
fig = go.Figure(data=[go.Pie(
labels=companies,
values=market_share,
hole=0.45,
marker=dict(
colors=colors,
line=dict(color='white', width=2)
),
textinfo='label+percent',
textposition='outside',
hovertemplate='<b>%{label}</b><br>' +
'Market Share: %{value}%<br>' +
'Percentage: %{percent}<br>' +
'<extra></extra>'
)])
fig.update_layout(
title_text='Cloud Storage Market Share 2024',
title_x=0.5,
showlegend=True,
font=dict(size=14)
)
fig.show()
This example demonstrates several key customizations:
- Custom colors: Define your brand palette instead of using defaults
- Border lines: White borders separate segments clearly
- Text information: Control what appears on the chart (
label+percent,value, etc.) - Hover templates: Format the tooltip that appears on mouseover
- Layout options: Center the title and adjust typography
The <extra></extra> tag in the hover template removes the default trace information that Plotly adds, creating cleaner tooltips.
Adding Central Annotations
The donut’s center is prime real estate for displaying summary metrics. Use annotations to add totals, percentages, or contextual labels that enhance the visualization’s message.
import plotly.graph_objects as go
companies = ['TechCorp', 'DataSystems', 'CloudNet', 'SecureIT', 'Others']
market_share = [35, 25, 20, 12, 8]
total_market = sum(market_share)
fig = go.Figure(data=[go.Pie(
labels=companies,
values=market_share,
hole=0.5,
marker=dict(colors=['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8'])
)])
# Add annotation in the center
fig.add_annotation(
text=f'<b>{total_market}%</b><br>Total Market',
x=0.5, y=0.5,
font=dict(size=20, color='#333333'),
showarrow=False,
align='center'
)
fig.update_layout(
title_text='Cloud Storage Market Share 2024',
showlegend=True,
height=500,
width=600
)
fig.show()
Annotations use normalized coordinates where (0.5, 0.5) represents the chart center. HTML formatting in the text parameter allows for multi-line displays with different styles. This technique works particularly well for financial dashboards showing budget totals or conversion funnels displaying overall conversion rates.
Advanced Styling and Interactive Features
Professional visualizations require attention to interaction design and visual hierarchy. Plotly’s interactivity features transform static charts into exploration tools.
import plotly.graph_objects as go
companies = ['TechCorp', 'DataSystems', 'CloudNet', 'SecureIT', 'Others']
market_share = [35, 25, 20, 12, 8]
# Pull out the largest segment for emphasis
pull_values = [0.1, 0, 0, 0, 0]
fig = go.Figure(data=[go.Pie(
labels=companies,
values=market_share,
hole=0.45,
pull=pull_values, # Pull out specific slices
marker=dict(
colors=['#2E86AB', '#A23B72', '#F18F01', '#C73E1D', '#6A994E'],
line=dict(color='white', width=3)
),
textfont=dict(size=16, color='white'),
hovertemplate='<b>%{label}</b><br>' +
'<b>Market Share:</b> %{value}%<br>' +
'<b>Proportion:</b> %{percent:.1%}<br>' +
'<extra></extra>',
rotation=90 # Rotate starting position
)])
fig.update_layout(
title={
'text': 'Cloud Storage Market Share 2024',
'x': 0.5,
'xanchor': 'center',
'font': {'size': 24, 'color': '#2E86AB'}
},
showlegend=True,
legend=dict(
orientation='v',
x=1.1,
y=0.5,
font=dict(size=14)
),
paper_bgcolor='#F5F5F5',
plot_bgcolor='#F5F5F5',
height=600,
width=800
)
fig.show()
The pull parameter accepts a list of values (0-1) corresponding to each segment, where higher values pull slices further from the center. Use this sparingly to highlight the most important category.
Custom hover templates should always include both absolute values and percentages. Users need context—35% means something different when the total is 100 units versus 1 million units.
Best Practices and Common Pitfalls
Limit your categories. Seven segments is the absolute maximum for donut charts. Beyond that, segments become too small to distinguish. If you have more categories, group smaller ones into “Others” or use a different chart type.
Choose colors intentionally. Use sequential color schemes (light to dark) for ordered data like age ranges or satisfaction levels. Use qualitative schemes (distinct hues) for categorical data like product lines or regions. Avoid red-green combinations due to colorblindness.
Make it accessible. Always include a legend and ensure sufficient color contrast. Test your charts in grayscale to verify that segments remain distinguishable without color.
# Good practice: Limited categories with clear labels
good_data = {
'Category': ['Product A', 'Product B', 'Product C', 'Product D'],
'Sales': [45, 30, 15, 10]
}
# Poor practice: Too many categories
poor_data = {
'Category': ['Cat1', 'Cat2', 'Cat3', 'Cat4', 'Cat5', 'Cat6', 'Cat7', 'Cat8', 'Cat9', 'Cat10'],
'Sales': [15, 12, 11, 10, 9, 8, 7, 6, 5, 17]
}
# The good example creates readable segments
# The poor example creates a confusing rainbow
Consider the alternative. Before defaulting to a donut chart, ask whether a horizontal bar chart would communicate the data more effectively. Bar charts excel at precise comparisons and work better when exact values matter more than proportions.
Optimize for responsiveness. Set explicit height and width values in your layout configuration, or use Plotly’s responsive sizing with config={'responsive': True}. Test your charts on mobile devices—small screens make donut charts particularly challenging.
Donut charts serve a specific purpose in the visualization toolkit. Use them to show high-level proportions in dashboards and reports, but reach for bar charts when precision matters. With Plotly’s flexible API, you can create polished, interactive donut charts that communicate clearly and look professional across any platform.