Adding percentage labels on pie chart in R

前端 未结 5 1348
渐次进展
渐次进展 2020-12-03 19:23

My data frame looks like

df
   Group   value
1 Positive    52
2 Negative   239
3 Neutral     9

I would like to make a pie chart of the dat

相关标签:
5条回答
  • 2020-12-03 19:57

    I agree with @hrbrmstr a waffle chart would be better. But to answer the original question... your problem comes from the order in which the wedges are drawn, which will default to alphabetical. As you calculate where to place the labels based on the ordering in your data frame, this works out wrong.

    As a general principle of readability, do all the fancy calculations of labels and positions they go before the actual code drawing the graphic.

    library(dplyr)
    library(ggplot2)
    library(ggmap) # for theme_nothing
    df <- data.frame(value = c(52, 239, 9),
                     Group = c("Positive", "Negative", "Neutral")) %>%
       # factor levels need to be the opposite order of the cumulative sum of the values
       mutate(Group = factor(Group, levels = c("Neutral", "Negative", "Positive")),
              cumulative = cumsum(value),
              midpoint = cumulative - value / 2,
              label = paste0(Group, " ", round(value / sum(value) * 100, 1), "%"))
    
    ggplot(df, aes(x = 1, weight = value, fill = Group)) +
       geom_bar(width = 1, position = "stack") +
       coord_polar(theta = "y") +
       geom_text(aes(x = 1.3, y = midpoint, label = label)) +
       theme_nothing()               
    

    0 讨论(0)
  • 2020-12-03 20:01

    For example, I create a dataframe e3 with 400 vehicles:

    e3 <- data.frame(400)
    e3 <- rep( c("car", "truck", "other", "bike", "suv"), c(60, 120, 20, 50, 150))
    

    Since pie charts are especially useful for proportions, let's have a look on the proportions of our vehicles, than we will report on the graph in this case:

    paste(prop.table(table(e3))*100, "%", sep = "")
    [1] "15%"   "5%"    "30%"   "12.5%" "37.5%"
    

    Then you can draw your pie chart,

    pie(table(e3), labels = paste(round(prop.table(table(e3))*100), "%", sep = ""), 
    col = heat.colors(5), main = "Vehicles proportions - n: 400")
    

    0 讨论(0)
  • 2020-12-03 20:11

    This is my example, using only the basic R code. Hope it help.

    Take iris for example
    attach(iris)
    
    check the the ratio of iris$Species
    a<- table(iris$Species)
    class(a)  
    
    then convert table format into matrix in order to use rowname code
    a_mat<- as.matrix(a)
    a_mat
    
    calculate the ratio of each Species
    a_ratio<- a_mat[,1]/sum(a_mat[,1])*100
    a_ratio
    
    since each Species accounts for 0.33333 (i.e. 33.33333%), I just want 2 decimal places by using signif()
    a_ratio<- signif(a_ratio,3)
    a_ratio
    
    basic pie chart code of R base
    pie(a_ratio,labels=rownames(a_mat))
    
    further add ratio values to labels by using paste()
    pie(a_ratio,labels=paste(rownames(a_mat),c("33%","33%","34%")))
    

    final pie chart, please click this link

    0 讨论(0)
  • 2020-12-03 20:14

    Here is an idea matching the order of groups in the pie chart and the order of labels. I sorted the data in descending order by value. I also calculated the percentage in advance. When I drew the ggplot figure, I specified the order of Group in the order in mydf (i.e., Negative, Positive, and Neutral) using fct_inorder(). When geom_label_repel() added labels to the pie, the order of label was identical to that of the pie.

    library(dplyr)
    library(ggplot2)
    library(ggrepel)
    library(forcats)
    library(scales)
    
    mydf %>%
    arrange(desc(value)) %>%
    mutate(prop = percent(value / sum(value))) -> mydf 
    
    pie <- ggplot(mydf, aes(x = "", y = value, fill = fct_inorder(Group))) +
           geom_bar(width = 1, stat = "identity") +
           coord_polar("y", start = 0) +
           geom_label_repel(aes(label = prop), size=5, show.legend = F, nudge_x = 1) +
           guides(fill = guide_legend(title = "Group"))
    

    DATA

    mydf <- structure(list(Group = structure(c(3L, 1L, 2L), .Label = c("Negative", 
    "Neutral", "Positive"), class = "factor"), value = c(52L, 239L, 
    9L)), .Names = c("Group", "value"), class = "data.frame", row.names = c("1", 
    "2", "3"))
    
    0 讨论(0)
  • 2020-12-03 20:15

    How about:

    vals <- c(239, 52, 9)
    val_names <- sprintf("%s (%s)", c("Negative", "Positive", "Neutral"), scales::percent(round(vals/sum(vals), 2)))
    names(vals) <- val_names
    
    waffle::waffle(vals) +
      ggthemes::scale_fill_tableau(name=NULL)
    

    instead?

    It's "fresher" than a pie chart and you aren't really gaining anything with the level of precision you have/want on those pie labels now.

    0 讨论(0)
提交回复
热议问题