Matplotlib Pie Charts

Build clear pie, donut, and nested donut charts with Matplotlib — labels, percentages, explode, rotation, legends, and best practices.

Quiz progress
0 / 10 answered
Contents

Basics #

Minimal pie:
import matplotlib.pyplot as plt
sizes = [30, 45, 25]
labels = ["A", "B", "C"]

fig, ax = plt.subplots()
ax.pie(sizes, labels=labels)   # values need not sum to 100
ax.axis("equal")               # circle instead of ellipse
plt.show()
  • Values are normalized internally: [30,45,25] → 30%, 45%, 25%.
  • Use ax.axis("equal") to keep the pie circular.
“Pies are for parts of a whole. If you have many slices or the ranking matters, consider a bar chart.”
— Visualization wisdom

Quiz: Basics

1. In ax.pie([30,70]), the wedges represent:
2. To start the first wedge at the top (12 o’clock), use:

Labels & Percentages #

Show percentages with autopct
fig, ax = plt.subplots()
sizes = [40, 35, 25]
labels = ["North", "East", "West"]
wedges, texts, autotexts = ax.pie(
    sizes, labels=labels,
    autopct="%1.1f%%",               # format string
    pctdistance=0.8,                 # position of % labels
    textprops={"fontsize":10}
)
ax.axis("equal")
plt.show()
Custom percentage formatting
def fmt_pct(pct, allvals):
    absolute = pct/100 * sum(allvals)
    return f"{pct:.1f}%\n({absolute:.0f})"

fig, ax = plt.subplots()
sizes = [5, 15, 30, 50]
wedges, *_ = ax.pie(
    sizes,
    autopct=lambda pct: fmt_pct(pct, sizes),  # pct is 0..100
    startangle=90
)
ax.axis("equal"); plt.show()

Quiz: Labels & Percentages

3. Which autopct string shows percentages with one decimal?
4. In an autopct callable, the argument pct is:

Explode & Rotation #

Explode a slice; rotate and direction
fig, ax = plt.subplots()
sizes  = [50, 25, 25]
labels = ["Core", "A", "B"]
explode = [0.05, 0.15, 0.0]         # highlight the 2nd slice

ax.pie(
    sizes, labels=labels, explode=explode,
    startangle=90,                    # start at 12 o'clock
    counterclock=False,               # clockwise
    autopct="%1.0f%%", shadow=True
)
ax.axis("equal"); plt.show()

Quiz: Explode & Rotation

5. To draw the wedges clockwise, use:
6. Explode only the second slice by 0.1:

Donut & Nested Donut #

Donut chart (ring) via wedgeprops
fig, ax = plt.subplots()
sizes = [40, 35, 25]
wedges, _ = ax.pie(
    sizes, startangle=90,
    wedgeprops={"width":0.4, "edgecolor":"white"}  # width < 1 → hole
)
ax.axis("equal")
plt.show()
Nested donut (two rings)
fig, ax = plt.subplots()
outer = [50, 30, 20]
inner = [30, 20, 10, 25, 10, 5]  # e.g., sub-categories

ax.pie(outer, radius=1.0,  wedgeprops={"width":0.3, "edgecolor":"white"}, labels=["A","B","C"])
ax.pie(inner, radius=0.7,  wedgeprops={"width":0.3, "edgecolor":"white"})
ax.axis("equal"); plt.show()

Quiz: Donut & Nested

7. Easiest way to create a donut hole is to:
8. To make a nested donut, you typically… (choose all that apply)

Styling & Legends #

Colors, edges, legends
fig, ax = plt.subplots()
sizes  = [25, 35, 40]
labels = ["Red", "Green", "Blue"]
colors = ["#ef476f", "#06d6a0", "#118ab2"]

wedges, texts, autotexts = ax.pie(
    sizes, labels=labels, colors=colors,
    autopct="%1.0f%%",
    wedgeprops={"linewidth":1, "edgecolor":"#fff"},
    textprops={"color":"#222"}
)
ax.axis("equal")
ax.legend(wedges, labels, title="Segments", loc="center left", bbox_to_anchor=(1,0.5))
plt.show()

Quiz: Styling & Legends

9. To ensure your pie is a circle (not an ellipse), use:

Pitfalls & Best Practices #

  • Too many slices: group small categories into “Other”.
  • Invalid data: negative values are not allowed; all zeros yields nothing to plot.
  • Legibility: prefer few slices; use labels, legend, and contrasting edges.
  • Accessibility: avoid using color alone; add labels/legend and consider patterns/annotations.

Quiz: Pitfalls

10. Which inputs are invalid or will fail for ax.pie? (choose all that apply)

Final Quiz & Summary #

Review your performance and revisit questions you missed.

Category: viz · Lesson: matplotlib-pie-charts
Learning by Examples
Runs three demos: basic pie, donut, and nested donut. If Matplotlib is available, images render below the console; otherwise, you’ll see a text fallback.
# Pie Charts Playground
# If Matplotlib is available, this script will print lines like
# "IMG64:<base64_png>" that the page will render as images.

def basic_pie():
    import matplotlib
    matplotlib.use("AGG")
    import matplotlib.pyplot as plt
    from io import BytesIO
    import base64

    sizes = [30, 45, 25]
    labels = ["A", "B", "C"]

    fig, ax = plt.subplots(figsize=(4,4), dpi=144)
    ax.pie(sizes, labels=labels, autopct="%1.1f%%", startangle=90)
    ax.axis("equal")
    buf = BytesIO()
    fig.savefig(buf, format="png", bbox_inches="tight")
    plt.close(fig)
    data = base64.b64encode(buf.getvalue()).decode("ascii")
    print("Basic pie (A,B,C):")
    print("IMG64:" + data)

def donut_pie():
    import matplotlib
    matplotlib.use("AGG")
    import matplotlib.pyplot as plt
    from io import BytesIO
    import base64

    sizes = [40, 35, 25]
    fig, ax = plt.subplots(figsize=(4,4), dpi=144)
    ax.pie(sizes, startangle=90, wedgeprops={"width":0.4, "edgecolor":"white"}, autopct="%1.0f%%")
    ax.axis("equal")
    buf = BytesIO()
    fig.savefig(buf, format="png", bbox_inches="tight")
    plt.close(fig)
    data = base64.b64encode(buf.getvalue()).decode("ascii")
    print("Donut chart:")
    print("IMG64:" + data)

def nested_donut():
    import matplotlib
    matplotlib.use("AGG")
    import matplotlib.pyplot as plt
    from io import BytesIO
    import base64

    outer = [50, 30, 20]
    inner = [30, 20, 10, 25, 10, 5]

    fig, ax = plt.subplots(figsize=(4.8,4.8), dpi=144)
    ax.pie(outer, radius=1.0, wedgeprops={"width":0.3, "edgecolor":"white"}, labels=["A","B","C"], startangle=90)
    ax.pie(inner, radius=0.7, wedgeprops={"width":0.3, "edgecolor":"white"}, startangle=90)
    ax.axis("equal")
    buf = BytesIO()
    fig.savefig(buf, format="png", bbox_inches="tight")
    plt.close(fig)
    data = base64.b64encode(buf.getvalue()).decode("ascii")
    print("Nested donut:")
    print("IMG64:" + data)

def text_fallback():
    print("Matplotlib not available. Showing a small text demo:")
    sizes = [12, 18, 30, 40]
    total = sum(sizes)
    pct = [round(s/total*100, 1) for s in sizes]
    print("Sizes:", sizes)
    print("Percentages:", pct)

try:
    import matplotlib  # noqa
    basic_pie()
    donut_pie()
    nested_donut()
except Exception as e:
    text_fallback()
    print("(Install matplotlib locally or run in an environment with plotting support.)")