Create multiple donut plots in one plot

Viewed 94

Is it possible to plot multiple donut plots in one graph. I have a code, which plots one donut plot, however, is it possible to separate them by year(day) column. As a result, a total of 4 donut plots will be displayed?

library(ggplot2)
donut<-structure(list(`year(day)` = c(2018, 2018, 2018, 2018, 2018, 
                               2019, 2019, 2019, 2019, 2019, 2020, 2020, 2020, 2020, 2020, 2021, 
                               2021, 2021, 2021, 2021), kind = c("Audi", "BMW", "Skoda", "Ford", 
                                                                 "MB", "Audi", "BMW", "Skoda", "Ford", "MB", "Audi", "BMW", "Skoda", 
                                                                 "Ford", "MB", "Audi", "BMW", "Skoda", "Ford", "MB"), TOTL = c(82043.56, 
                                                                                                                              22908.66, 135925.42, 50448.36, 762679.18, 83680.1538461538, 35655.2115384615, 
                                                                                                                              95892.4807692308, 57961.5, 726726.423076923, 162654.5, 41344.6153846154, 
                                                                                                                              110685.038461538, 40149.4615384615, 664138.153846154, 355072.729926464, 
                                                                                                                              66555.3261904762, 102378.893809524, 55646.5438095238, 475979.351831226
                                                                 )), row.names = c(NA, -20L), groups = structure(list(`year(day)` = c(2018, 
                                                                                                                                      2019, 2020, 2021), .rows = structure(list(1:5, 6:10, 11:15, 16:20), ptype = integer(0), class = c("vctrs_list_of", 
                                                                                                                                                                                                                                        "vctrs_vctr", "list"))), row.names = c(NA, 4L), class = c("tbl_df", 
                                                                                                                                                                                                                                                                                                  "tbl", "data.frame"), .drop = TRUE), class = c("grouped_df", 
                                                                                                                                                                                                                                                                                                                                                 "tbl_df", "tbl", "data.frame"))


donut$fraction <- donut$NETP / sum(donut$NETP)
donut$ymax <- cumsum(donut$fraction)
donut$ymin <- c(0, head(donut$ymax, n=-1))
donut$labelPosition <- (donut$ymax + donut$ymin)/2
donut$label <- paste0(donut$kind, "\n NETP: ", donut$NETP)

ggplot(donut, aes(ymax=ymax, ymin=ymin, xmax=7, xmin=4, fill=kind)) +
  geom_rect() +
  geom_text( x=10, aes(y=labelPosition, label=label, color=kind), size=4.5, fontface="bold") + # x here controls label position (inner / outer)
  #scale_fill_brewer(palette=5) +
  #scale_color_brewer(palette=5) +
  coord_polar(theta="y") +
  xlim(c(-3, 10)) +
  theme_void()
2 Answers

This could be achieved via facetting. To make this work you have to compute the ymin and ymax per facet:

library(dplyr)
library(ggplot2)

donut1 <- donut %>%
  group_by(`year(day)`) %>%
  mutate(
    fraction = TOTL / sum(TOTL),
    ymax = cumsum(fraction),
    ymin = lag(ymax, default = 0),
    labelPosition = (ymax + ymin) / 2,
    label = paste0(kind, "\n TOTL: ", TOTL)
  )

ggplot(donut1, aes(ymax = ymax, ymin = ymin, xmax = 7, xmin = 4, fill = kind)) +
  geom_rect() +
  geom_text(x = 10, aes(y = labelPosition, label = label, color = kind), size = 2.5, fontface = "bold") +
  coord_polar(theta = "y") +
  xlim(c(-3, 10)) +
  facet_wrap(~`year(day)`) +
  theme_void() 

enter image description here

EDIT If you want to add an annotation to each of the facets I would suggest to do it via geom_text like so:

donut1_annotate <- donut1 %>% 
  group_by(`year(day)`) %>%
  summarise(totalsum = sum(TOTL))

ggplot(donut1) +
  geom_rect(aes(ymax = ymax, ymin = ymin, xmax = 7, xmin = 4, fill = kind)) +
  geom_text(x = 10, aes(y = labelPosition, label = label, color = kind), size = 2.5, fontface = "bold") +
  geom_text(data = donut1_annotate, aes(label = paste("Total: ",totalsum)), x = -2, y = 0, fontface = "bold") +
  coord_polar(theta = "y") +
  xlim(c(-3, 10)) +
  facet_wrap(~`year(day)`) +
  theme_void()

enter image description here

I couldn't find the column NETP in your dataframe, so I changed to plot TOTL.

donut$fraction <- donut$TOTL / sum(donut$TOTL)
donut$ymax <- cumsum(donut$fraction)
donut$ymin <- c(0, head(donut$ymax, n=-1))
donut$labelPosition <- (donut$ymax + donut$ymin)/2
donut$label <- paste0(donut$kind, "\n NETP: ", donut$TOTL)

p2018 <- ggplot(donut[donut$`year(day)` == 2018,], 
                aes(ymax=ymax, ymin=ymin, xmax=7, xmin=4, fill=kind)) +
    geom_rect() +
    geom_text( x=10, aes(y=labelPosition, label=label, color=kind), 
               size=4.5, fontface="bold")+
    coord_polar(theta="y") +
    xlim(c(-3, 10)) +
    theme_void()

p2019 <- ggplot(donut[donut$`year(day)` == 2019,], 
                aes(ymax=ymax, ymin=ymin, xmax=7, xmin=4, fill=kind)) +
    geom_rect() +
    geom_text( x=10, aes(y=labelPosition, label=label, color=kind), 
               size=4.5, fontface="bold")+
    coord_polar(theta="y") +
    xlim(c(-3, 10)) +
    theme_void()

p2020 <- ggplot(donut[donut$`year(day)` == 2020,], 
                aes(ymax=ymax, ymin=ymin, xmax=7, xmin=4, fill=kind)) +
    geom_rect() +
    geom_text( x=10, aes(y=labelPosition, label=label, color=kind), 
               size=4.5, fontface="bold")+
    coord_polar(theta="y") +
    xlim(c(-3, 10)) +
    theme_void()

p2021 <- ggplot(donut[donut$`year(day)` == 2021,], 
                aes(ymax=ymax, ymin=ymin, xmax=7, xmin=4, fill=kind)) +
    geom_rect() +
    geom_text( x=10, aes(y=labelPosition, label=label, color=kind), 
               size=4.5, fontface="bold")+
    coord_polar(theta="y") +
    xlim(c(-3, 10)) +
    theme_void()

g1 <- ggplotGrob(p2018)
g2 <- ggplotGrob(p2019)
g3 <- ggplotGrob(p2020)
g4 <- ggplotGrob(p2021)

grob1 <- gridExtra::arrangeGrob(grobs = list(g1, g2,g3,g4), nrow = 2)
plot1 <- gridExtra::grid.arrange(grob1)

Cheers

Related