Pie Chart
ggplot2: geom_col() + coord_polar("y") · Package: ggplot2 · Variables: 1 categorical + 1 numerical
WHAT IS A PIE CHART?
A pie chart divides a circle into slices where each slice represents a proportion of the whole. Despite controversy in the data visualization community, pie charts remain effective for simple part-to-whole relationships with 2-5 categories — especially when one category clearly dominates. They answer "what fraction of the total does each category represent?" Avoid pie charts with more than 6 slices or when comparing similarly-sized segments (humans are poor at comparing angles). For many categories, use a treemap or bar chart instead. In ggplot2, pie charts use coord_polar("y") applied to geom_col().
HOW TO READ A PIE CHART
A pie chart encodes proportion as angle, and angle is among the least accurate visual channels people judge — which is why the format attracts so much criticism. It survives because it communicates one thing exceptionally well: that a set of parts constitutes a whole. Read it for rough shares and dominance, never for precise comparison. Two slices within a few percentage points of each other are genuinely indistinguishable, so if the reader needs to know which is larger, the chart cannot answer the question they came with. The format works when there are two to four slices, when one clearly dominates, and when the categories genuinely sum to a meaningful total. It fails as soon as the answer depends on ranking several similar segments — a sorted bar chart handles that case, and handles it accurately.
BEST FOR
- · Simple part-to-whole (2-5 slices)
- · Highlighting a dominant category
- · Rough proportions
AVOID WHEN
- · More than 6 categories
- · Comparing similar-sized slices
- · Values not summing to a whole
- · Precise comparison needed
R + GGPLOT2 CODE EXAMPLE
df <- data.frame(cyl = c("4", "6", "8"), n = c(11, 7, 14))
ggplot(df, aes(x = "", y = n, fill = cyl)) +
geom_col(width = 1) +
coord_polar(theta = "y") +
theme_void() +
labs(title = "Cars by Cylinder", fill = "Cylinders")PIE CHART WITH PERCENTAGE LABELS AND LUMPED CATEGORIES
Sorted slices, an explicit Other bucket, and percentages printed on the chart so the reader never has to estimate an angle.
library(ggplot2)
library(dplyr)
library(forcats)
df <- data.frame(
segment = c("Enterprise", "Mid-market", "SMB", "Education", "Public"),
revenue = c(412000, 268000, 154000, 39000, 27000)
) |>
mutate(
segment = fct_lump_n(fct_reorder(segment, -revenue), n = 3, w = revenue),
) |>
count(segment, wt = revenue, name = "revenue") |>
arrange(desc(revenue)) |>
mutate(
share = revenue / sum(revenue),
label = scales::percent(share, accuracy = 1),
pos = cumsum(share) - share / 2
)
ggplot(df, aes(x = "", y = share, fill = fct_rev(segment))) +
geom_col(width = 1, colour = "white") +
coord_polar(theta = "y", direction = -1) +
geom_text(aes(y = 1 - pos, label = label), size = 3.8) +
scale_fill_manual(
values = c("#ff6a00", "#3d9970", "#7d5fff", "#b8b8a8"),
name = NULL
) +
labs(title = "Revenue share by segment") +
theme_void(base_size = 12)COMMON MISTAKES WITH THIS CHART
Using more than about five slices
Thin wedges are unreadable and the legend becomes a lookup table. Keep the top few categories and lump the rest into an explicit "Other".
Plotting values that do not sum to a whole
A pie asserts part-to-whole. Overlapping categories or a filtered subset make the geometry lie. Use a bar chart when the parts are not exhaustive.
Adding a 3D effect or explosion
Perspective changes the apparent area of slices by position, so the same value looks larger at the front. It introduces distortion for no informational gain.
Leaving slices in arbitrary order
Order by size starting at twelve o’clock. It gives the eye a consistent reference and makes the ranking as readable as the format allows.
Run this code now
Paste the code above into RChat and see the pie chart rendered instantly in your browser.