Search code examples
rggplot2donut-chart

Why my Donut chart with facet_grid doesn't run?


I have the data frame below, called 'subdata.frame'. It's a data from a rent bike company. There are users called 'member' who paid an annual subscription, and the casual riders. Further, we have three types of bikes. The 'n' counts the total of rides in a certain period.

member_casual rideable_type n
casual classic_bike 68941
casual docked_bike 14503
casual electric_bike 20990
member classic_bike 75455
member electric_bike 17008

So, I'm trying to create two donut charts to show the proportion of each type of bike used within the member and casual groups. I'm using the 'facet_grid' (~member_casual) function. But first, it's necessary to create new columns for the percentage and cumulative sums.

subdata.frame <- data.frame(subdata) %>%
                  group_by(member_casual) %>%
                    count(rideable_type) %>%
                      mutate(prop = n/sum(n)) %>%
                        mutate(ymax = cumsum(prop))

Resulting in the next table:

member_casual rideable_type n prop ymax
casual classic_bike 68941 0.660 0.660
casual docked_bike 14503 0.139 0.799
casual electric_bike 20990 0.201 1
member classic_bike 75455 0.816 0.816
member electric_bike 17008 0.184 1

Using the geom_rect function, 'ymax' will set the top of each rectangle.

So, i assign the 'ymin', to set the bottom of each rectangle:

subdata.frame$ymin <- c(0, head(subdata.frame$ymax, n=-1))

So, I run the ggplot function:

ggplot(subdata.frame, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=rideable_type)) +
  geom_rect() +
  scale_fill_brewer(palette=4) +
  facet_grid(~member_casual) +
  coord_polar(theta="y") +
  xlim(c(2, 4)) +
  theme_void() 

Finally, I have the plot below. Note that the member donut chart is incomplete: plot error


Solution

  • The issue is that using subdata.frame$ymin <- c(0, head(subdata.frame$ymax, n=-1)) to compute the ymin you did not take the grouping by member type into account.

    First, to reproduce your issue:

    library(ggplot2)
    
    subdata.frame$ymin <- c(0, head(subdata.frame$ymax, n=-1))
    
    ggplot(subdata.frame, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=rideable_type)) +
      geom_rect() +
      scale_fill_brewer(palette=4) +
      facet_grid(~member_casual) +
      coord_polar(theta="y") +
      xlim(c(2, 4)) +
      theme_void() 
    

    To fix that you could use dplyr::lag as already suggested by @RuiBarradas and to group your data by member_casual when doing so:

    library(dplyr)
    
    subdata.frame <- subdata.frame %>%
      group_by(member_casual) %>%
      mutate(ymin = lag(ymax, default = 0))
    
    ggplot(subdata.frame, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=rideable_type)) +
      geom_rect() +
      scale_fill_brewer(palette=4) +
      facet_grid(~member_casual) +
      coord_polar(theta="y") +
      xlim(c(2, 4)) +
      theme_void() 
    

    DATA

    subdata.frame <- data.frame(
      stringsAsFactors = FALSE,
         member_casual = c("casual", "casual", "casual", "member", "member"),
         rideable_type = c("classic_bike","docked_bike",
                           "electric_bike","classic_bike","electric_bike"),
                     n = c(68941L, 14503L, 20990L, 75455L, 17008L),
                  prop = c(0.66, 0.139, 0.201, 0.816, 0.184),
                  ymax = c(0.66, 0.799, 1, 0.816, 1)
    )