The ggplot2 package allows to build donut chart with R. This post describes how, providing explanation and reproducible code.
ggplot2
      
            The ggplot2 package allows to build
            donut charts. Note however that
            this is possible thanks a hack, since no specific function has been
            created for this kind of chart. (This is voluntary, to avoid donut
            charts that are dataviz
            bad practice)
          
            Here is the process: - input data provides a numeric variable for a
            set of entities - absolute numeric values must be translated to
            proportion - group positions must be stacked: we’re gonna display
            them one after the other - geom_rect() is used to plot
            each group as a rectangle - coord_polar() is used to
            switch from stacked rectangles to a ring -
            xlim() allows to switch from pie to donut: it adds the
            empty circle in the middle
          
            
          
# load library
library(ggplot2)
 
# Create test data.
data <- data.frame(
  category=c("A", "B", "C"),
  count=c(10, 60, 30)
)
 
# Compute percentages
data$fraction = data$count / sum(data$count)
# Compute the cumulative percentages (top of each rectangle)
data$ymax = cumsum(data$fraction)
# Compute the bottom of each rectangle
data$ymin = c(0, head(data$ymax, n=-1))
 
# Make the plot
ggplot(data, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=category)) +
     geom_rect() +
     coord_polar(theta="y") + # Try to remove that to understand how the chart is built initially
     xlim(c(2, 4)) # Try to remove that to see how to make a pie chart
      Here are a couple of things you can do improve your donut chart style:
theme_void() to get rid of the unnecessary
              background, axis, labels and so on.
            
            
          
# load library
library(ggplot2)
# Create test data.
data <- data.frame(
  category=c("A", "B", "C"),
  count=c(10, 60, 30)
)
 
# Compute percentages
data$fraction <- data$count / sum(data$count)
# Compute the cumulative percentages (top of each rectangle)
data$ymax <- cumsum(data$fraction)
# Compute the bottom of each rectangle
data$ymin <- c(0, head(data$ymax, n=-1))
# Compute label position
data$labelPosition <- (data$ymax + data$ymin) / 2
# Compute a good label
data$label <- paste0(data$category, "\n value: ", data$count)
# Make the plot
ggplot(data, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=category)) +
  geom_rect() +
  geom_label( x=3.5, aes(y=labelPosition, label=label), size=6) +
  scale_fill_brewer(palette=4) +
  coord_polar(theta="y") +
  xlim(c(2, 4)) +
  theme_void() +
  theme(legend.position = "none")
      
            It is important to understand that donut chart are just stacked
            rectangles that are made circular thanks to
            coord_polar.
          
Thus, the empty circle that makes it a donut chart is just the space between the initial Y axis and the left part of the rectangle.
xlim left boundary is big, no empty circle. You
              get a pie chart
            xlim is low, the ring becomes thinner.
            If you don’t get it, just plot the chart without
            coord_polar()
          
            
          
# load library
library(ggplot2)
# Create test data.
data <- data.frame(
  category=c("A", "B", "C"),
  count=c(10, 60, 30)
)
 
# Compute percentages
data$fraction <- data$count / sum(data$count)
# Compute the cumulative percentages (top of each rectangle)
data$ymax <- cumsum(data$fraction)
# Compute the bottom of each rectangle
data$ymin <- c(0, head(data$ymax, n=-1))
# Compute label position
data$labelPosition <- (data$ymax + data$ymin) / 2
# Compute a good label
data$label <- paste0(data$category, "\n value: ", data$count)
# Make the plot
ggplot(data, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=category)) +
  geom_rect() +
  geom_text( x=2, aes(y=labelPosition, label=label, color=category), size=6) + # x here controls label position (inner / outer)
  scale_fill_brewer(palette=3) +
  scale_color_brewer(palette=3) +
  coord_polar(theta="y") +
  xlim(c(-1, 4)) +
  theme_void() +
  theme(legend.position = "none")
      👋 After crafting hundreds of R charts over 12 years, I've distilled my top 10 tips and tricks. Receive them via email! One insight per day for the next 10 days! 🔥