Megan Critchley
Megan Critchley

Reputation: 103

Creating donut charts with ggplot2 and grouping variables

apologies if this has already been answered but I've tried code from many posts to no avail. I am trying to make a donut chart in ggplot 2, which is new for me. It seems to be working for the most part, but isnt grouping the countries together, so instead each row gets its own chunk in the pie chart, instead of all UK rows being put together (sorry if thats a bit rambly).

Heres the code with some example data (i actually have 14 countries and 1200 rows):

  country <- c("Australia", "Australia", "China", "UK", "UK", "UK", "Australia", "New Zealand", "Hong Kong", "India", "India", "Korea", "Malaysia", "UK")
  GAV <- c(32626614, 611751827, 1070038943.77, 1070038990, 611751347, 567751827, 444751827, 611751444, 999751827, 111751827, 222751827, 331751827, 611751844, 611777827)

panel_donut <- data.frame(country, GAV)

remove rows with NA GAV

panel_donut <- panel_donut[!is.na(panel_donut$GAV),]

calculate percentage

panel_donut$percentage <-  panel_donut$GAV / sum(panel_donut$GAV)* 100

panel_donut <-  panel_donut[rev(order(panel_donut$percentage)), ]

panel_donut$ymax <-  cumsum(panel_donut$percentage)

panel_donut$ymin <-  c(0, head(panel_donut$ymax, n = -1))

panel_donut

reorder colour levels

panel_donut <-  panel_donut[order(panel_donut$country), ]

plot the chart

library(ggplot2)
library(ggrepel)

donut <-  ggplot(panel_donut, aes(fill = country, ymax = ymax, ymin = ymin, xmax = 100, xmin = 80)) +

  geom_rect(colour = "black") +

  coord_polar(theta = "y") + 

  xlim(c(0, 100)) +

  theme(legend.title = element_text(colour = "black", size = 16, face = "bold"), 
    legend.text = element_text(colour = "black", size = 15), 
    panel.grid = element_blank(),
    axis.text = element_blank(),
    axis.title = element_blank(),
    axis.ticks = element_blank())

donut

Currently, I get a donut chart but all of the levels have separate chunks, i.e UK has 4 chunks of the donut instead of it being grouped into 1. I'm wondering where I have gone wrong in my code that has resulted in this happening.

Thanks in advance for any help!

Upvotes: 1

Views: 400

Answers (1)

Stephan
Stephan

Reputation: 2246

yes, your main dataframe has several entries of your countries. you need to summarise them. try this approach:

library(ggplot2)
library(ggrepel)
library(dplyr)

panel_donut %>% 
  group_by(country) %>% 
  summarise(percentage = sum(percentage)) %>% 
  mutate(ymax = cumsum(percentage), 
         ymin = c(0, head(ymax, n = -1))) %>% 
  ggplot(aes(fill = country, ymax = ymax, ymin = ymin, xmax = 100, xmin = 80)) +
  geom_rect(colour = "black") +
  coord_polar(theta = "y") +
  xlim(c(0, 100)) +
  scale_fill_brewer(palette = "Set1") +
  theme(legend.title = element_text(colour = "black", size = 16, face = "bold"), 
        legend.text = element_text(colour = "black", size = 15), 
        panel.grid = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank())

output is:

enter image description here

although I suggest an easier approach with the same libraries:

data.frame(country, GAV) %>% 
  filter(!is.na(GAV)) %>% 
  mutate(percentage = GAV / sum(GAV) * 100) %>% 
  group_by(country) %>% 
  summarise(percentage = sum(percentage)) %>% 
  mutate(ymax = cumsum(percentage), 
         ymin = c(0, head(ymax, n = -1))) %>% 
  ggplot(aes(fill = country, ymax = ymax, ymin = ymin, xmax = 100, xmin = 80)) +
  geom_rect(colour = "black") +
  coord_polar(theta = "y") +
  xlim(c(0, 100)) +
  scale_fill_brewer(palette = "Set1", guide = "none") +
  theme(legend.title = element_text(colour = "black", size = 16, face = "bold"), 
        legend.text = element_text(colour = "black", size = 15), 
        panel.grid = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank()) +
  geom_label_repel(aes(label = paste(country, "\n", round(percentage, 1),"%"), 
                       x = 100, 
                       y = (ymin + ymax)/2),
                   inherit.aes = F, 
                   show.legend = F, size = 3) +
  annotate("text", x = 0, y = 0, size = 15, label = "Donut Chart")

output:

enter image description here

Upvotes: 2

Related Questions