I have spent years building data visualizations and dashboards using Python. Over time, I have found that the standard pie chart often feels cluttered and outdated.
When I want to create a cleaner, more modern look for my reports, I always reach for the Python Matplotlib donut chart. It is essentially a pie chart with a hole in the middle, but it offers much better readability.
In this tutorial, I will show you exactly how I build these charts from scratch. I will share the methods I use daily to turn boring data into professional-grade visuals.
Donut Chart in Python
I often get asked why someone should bother with a donut chart instead of a standard pie chart. In my experience, the empty center of a donut chart is prime real estate for a title or a summary statistic.
It reduces the “visual heaviness” of the chart. By focusing on the length of the arcs rather than the area of the slices, your audience can interpret the data much faster.
Method 1: Create a Python Matplotlib Donut Chart Using Wedgeprops
This is my favorite method because it is clean and requires the least amount of code. We use the wedgeprops parameter within the standard plt.pie() function.
I will use a USA-centric example here. Let’s look at the market share of the top coffee chains in the United States.
import matplotlib.pyplot as plt
# Data: USA Top Coffee Chains Market Share (Hypothetical)
brands = ['Starbucks', 'Dunkin', 'Tim Hortons', 'Dutch Bros', 'Others']
market_share = [40, 25, 15, 10, 10]
colors = ['#00704A', '#E03E96', '#FF0000', '#0061A8', '#A9A9A9']
# Create the figure
plt.figure(figsize=(8, 6))
# Plotting the pie chart with a 'hole' using wedgeprops
plt.pie(market_share, labels=brands, autopct='%1.1f%%', startangle=140,
colors=colors, pctdistance=0.85,
wedgeprops={'width': 0.4, 'edgecolor': 'w'})
# Adding a title in the center
plt.title('USA Coffee Chain Market Share', fontsize=15, pad=20)
# Display the plot
plt.axis('equal')
plt.tight_layout()
plt.show()I executed the above example code and added the screenshot below.

When I use wedgeprops={‘width’: 0.4}, I am telling Matplotlib only to draw the outer 40% of the radius. This automatically creates that “donut” look without needing extra shapes.
I also like to set edgecolor=’w’ to create white borders between the slices. It makes the Python Matplotlib donut chart look much sharper on digital screens.
Method 2: Create a Donut Chart by Adding a Center Circle
If you are using an older version of Matplotlib or prefer a more manual approach, this method is for you. I used this technique for years before wedgeprops became popular.
First, I create a standard pie chart. Then, I draw a white circle at the center to “mask” the middle part of the pie.
import matplotlib.pyplot as plt
# Data: Popular Sports in the USA
sports = ['American Football', 'Basketball', 'Baseball', 'Soccer', 'Ice Hockey']
viewership = [37, 11, 9, 7, 4]
colors = ['#013369', '#FF671F', '#002D72', '#00FF00', '#C8102E']
# Create the pie chart
fig, ax = plt.subplots(figsize=(8, 6))
ax.pie(viewership, labels=sports, autopct='%1.1f%%', startangle=90, colors=colors)
# Create a circle for the center of the plot
center_circle = plt.Circle((0,0), 0.70, fc='white')
fig = plt.gcf()
fig.gca().add_artist(center_circle)
# Adjusting the aspect ratio
ax.axis('equal')
plt.title('Top Sports in the USA by Viewership', fontsize=16)
plt.tight_layout()
plt.show()I executed the above example code and added the screenshot below.

In this code, plt.Circle((0,0), 0.70, fc=’white’) creates a white circle at the origin with a radius of 0.7. I find that a radius between 0.7 and 0.8 usually gives the best visual balance.
This method is great because you can change the fc (face color) of the center circle to match your dashboard’s background color.
Customize Your Python Matplotlib Donut Chart
I believe that customization is what separates a beginner from an experienced Python developer. You want your chart to be informative, not just pretty.
One trick I always use is placing a central text label. This is very common in financial reports in the US to show the total value.
import matplotlib.pyplot as plt
# Data: US Household Spending Categories
categories = ['Housing', 'Transportation', 'Food', 'Healthcare', 'Insurance', 'Others']
spending = [33, 16, 13, 8, 11, 19]
# Define the figure
fig, ax = plt.subplots(figsize=(8, 8))
# Create the donut
ax.pie(spending, labels=categories, autopct='%1.1f%%', startangle=140,
colors=plt.cm.Paired.colors, wedgeprops={'width': 0.5})
# Add central text
plt.text(0, 0, 'Total Spending\n$63,000', ha='center', va='center', fontsize=14, fontweight='bold')
plt.title('Average Annual US Household Spending', fontsize=16)
plt.axis('equal')
plt.show()I executed the above example code and added the screenshot below.

I use plt.text() with ha=’center’ and va=’center’ to ensure the text is perfectly aligned in the middle of the hole. This immediately tells the viewer what the “whole” represents.
Method 3: Handle Hierarchical Data with Nested Donut Charts
Sometimes, I need to show sub-categories within a larger group. For instance, I might want to show the US Tech Giant’s revenue split by product category.
This is called a nested donut chart. It looks complex, but I can break it down into two simple pie() calls.
import matplotlib.pyplot as plt
import numpy as np
# Data
group_names = ['Apple', 'Google', 'Microsoft']
group_size = [50, 30, 20]
subgroup_names = ['iPhone', 'Services', 'Mac', 'Ads', 'Cloud', 'Windows', 'Office']
subgroup_size = [30, 10, 10, 25, 5, 10, 10]
# Colors
a, b, c = [plt.cm.Blues, plt.cm.Reds, plt.cm.Greens]
# Outer Ring
fig, ax = plt.subplots()
ax.axis('equal')
mypie, _ = ax.pie(group_size, radius=1.3, labels=group_names, colors=[a(0.6), b(0.6), c(0.6)])
plt.setp(mypie, width=0.3, edgecolor='white')
# Inner Ring
mypie2, _ = ax.pie(subgroup_size, radius=1.3-0.3, labels=subgroup_names,
labeldistance=0.7, colors=[a(0.5), a(0.4), a(0.3), b(0.5), b(0.4), c(0.5), c(0.4)])
plt.setp(mypie2, width=0.4, edgecolor='white')
plt.margins(0,0)
plt.title('USA Tech Giant Revenue Breakdown', pad=40)
plt.show()I executed the above example code and added the screenshot below.

When I build these, I play with the radius and width parameters. The outer ring has a larger radius, while the inner ring is slightly smaller.
This is a very powerful way to visualize complex US market data. It keeps related information together without needing multiple separate charts.
Common Issues to Avoid
I have made plenty of mistakes while learning Matplotlib, and I want to help you avoid them. One common issue is the chart looking like an oval instead of a circle.
I always include plt.axis(‘equal’) or ax.axis(‘equal’). This ensures that the aspect ratio is 1:1, keeping your donut perfectly round.
Another tip is to avoid too many slices. If you have more than 7 or 8 categories, the labels will overlap, and the chart will become unreadable. In those cases, I usually group the smaller categories into an “Others” slice.
Conclusion
I find that using a Python Matplotlib donut chart is one of the easiest ways to upgrade the look of your data projects. It is clean, modern, and highly customizable.
Whether you use the wedgeprops method or the Circle patch method, the result is much more engaging than a standard pie chart.
Python is a versatile tool, and mastering these small design details will make your work stand out. Happy coding!
You may also like to read:
- Matplotlib Pie Chart Autopct to Format Percentages
- Python Matplotlib Pie Chart Hatch
- Python Matplotlib Pie Chart Explode and Shadow Effects
- Python Matplotlib Multiple Pie Charts

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.