【问题标题】:R: Pie chart with percentage as labels using ggplot2R:使用ggplot2以百分比作为标签的饼图
【发布时间】:2014-10-15 21:57:11
【问题描述】:

从一个数据框中,我想为五个类别绘制一个饼图,并将它们的百分比作为同一图表中的标签,按顺时针从高到低的顺序排列。

我的代码是:

League<-c("A","B","A","C","D","E","A","E","D","A","D")
data<-data.frame(League) # I have more variables 

p<-ggplot(data,aes(x="",fill=League))
p<-p+geom_bar(width=1)
p<-p+coord_polar(theta="y")
p<-p+geom_text(data,aes(y=cumsum(sort(table(data)))-0.5*sort(table(data)),label=paste(as.character(round(sort(table(data))/sum(table(data)),2)),rep("%",5),sep="")))
p

我用

cumsum(sort(table(data)))-0.5*sort(table(data))

将标签放置在相应的部分和

label=paste(as.character(round(sort(table(data))/sum(table(data)),2)),rep("%",5),sep="")

对于百分比的标签。

我得到以下输出:

Error: ggplot2 doesn't know how to deal with data of class uneval

【问题讨论】:

标签: r ggplot2 pie-chart labels


【解决方案1】:

我保留了您的大部分代码。我发现这很容易通过省略 coord_polar... 来调试。更容易以条形图的形式查看正在发生的事情。

主要是将因素从最高到最低重新排序,以使绘图顺序正确,然后只需使用标签位置即可使它们正确。我还简化了标签代码(您不需要as.characterreppaste0sep = "" 的快捷方式。)

League<-c("A","B","A","C","D","E","A","E","D","A","D")
data<-data.frame(League) # I have more variables 

data$League <- reorder(data$League, X = data$League, FUN = function(x) -length(x))

at <- nrow(data) - as.numeric(cumsum(sort(table(data)))-0.5*sort(table(data)))

label=paste0(round(sort(table(data))/sum(table(data)),2) * 100,"%")

p <- ggplot(data,aes(x="", fill = League,fill=League)) +
  geom_bar(width = 1) +
  coord_polar(theta="y") +
  annotate(geom = "text", y = at, x = 1, label = label)
p

at 计算是找到楔形的中心。 (更容易将它们视为堆叠条形图中的条形中心,只需运行上面没有coord_polar 线的图即可查看。)at 计算可以分解如下:

table(data) 是每组中的行数,sort(table(data)) 将它们按绘制顺序排列。取其中的cumsum(),我们可以得到每个条堆叠在一起时的边缘,乘以 0.5 可以得到堆栈中每个条的高度的一半(或馅饼楔形宽度的一半) .

as.numeric() 只是确保我们有一个数字向量而不是 table 类的对象。

从累积高度中减去半宽后,每个条在堆叠时得到中心。但是 ggplot 会将最大的条堆叠在底部,而我们所有的 sort()ing 都将最小的放在前面,所以我们需要做 nrow - 一切,因为我们实际计算的是相对于 顶部栏,而不是底部。 (并且,对于原始的分类数据,nrow() 是总行数,因此是条形的总高度。)

【讨论】:

  • 非常感谢!!我要疯了才能做到这一点。我不熟悉 ggplot2 库。
  • @Gregor 你能解释一下你的代码在计算at 时在做什么吗?非常感谢。
  • @info_seekeR 在底部添加了几段,看看是否有帮助。
  • @Gregor 非常清晰易懂 - 谢谢! :)
【解决方案2】:

前言:我没有自愿制作饼图。

下面是对包含百分比的ggpie 函数的修改:

library(ggplot2)
library(dplyr)

#
# df$main should contain observations of interest
# df$condition can optionally be used to facet wrap
#
# labels should be a character vector of same length as group_by(df, main) or
# group_by(df, condition, main) if facet wrapping
#

pie_chart <- function(df, main, labels = NULL, condition = NULL) {

  # convert the data into percentages. group by conditional variable if needed
  df <- group_by_(df, .dots = c(condition, main)) %>%
    summarize(counts = n()) %>%
    mutate(perc = counts / sum(counts)) %>%
    arrange(desc(perc)) %>%
    mutate(label_pos = cumsum(perc) - perc / 2,
           perc_text = paste0(round(perc * 100), "%"))

  # reorder the category factor levels to order the legend
  df[[main]] <- factor(df[[main]], levels = unique(df[[main]]))

  # if labels haven't been specified, use what's already there
  if (is.null(labels)) labels <- as.character(df[[main]])

  p <- ggplot(data = df, aes_string(x = factor(1), y = "perc", fill = main)) +

    # make stacked bar chart with black border
    geom_bar(stat = "identity", color = "black", width = 1) +

    # add the percents to the interior of the chart
    geom_text(aes(x = 1.25, y = label_pos, label = perc_text), size = 4) +

    # add the category labels to the chart
    # increase x / play with label strings if labels aren't pretty
    geom_text(aes(x = 1.82, y = label_pos, label = labels), size = 4) +

    # convert to polar coordinates
    coord_polar(theta = "y") +

    # formatting
    scale_y_continuous(breaks = NULL) +
    scale_fill_discrete(name = "", labels = unique(labels)) +
    theme(text = element_text(size = 22),
          axis.ticks = element_blank(),
          axis.text = element_blank(),
          axis.title = element_blank())

  # facet wrap if that's happening
  if (!is.null(condition)) p <- p + facet_wrap(condition)

  return(p)
}

例子:

# sample data
resps <- c("A", "A", "A", "F", "C", "C", "D", "D", "E")
cond <- c(rep("cat A", 5), rep("cat B", 4))
example <- data.frame(resps, cond)

就像一个典型的 ggplot 调用:

ex_labs <- c("alpha", "charlie", "delta", "echo", "foxtrot")

pie_chart(example, main = "resps", labels = ex_labs) +
  labs(title = "unfacetted example")

ex_labs2 <- c("alpha", "charlie", "foxtrot", "delta", "charlie", "echo")

pie_chart(example, main = "resps", labels = ex_labs2, condition = "cond") +
  labs(title = "facetted example")

【讨论】:

  • 这是一些很棒的编码。我的所有解决方案都有问题,我的图表似乎是逆时针构建的,但我的标签是顺时针的?谢谢
  • 我尝试用direction=-1 改变极地的方向,但它似乎同时翻转了百分比和方向,所以我遇到了同样的问题
  • 解决了@Reno。我更改了以下行label_pos = sum(perc) - cumsum(perc) + perc / 2
  • 使用1-(cumsum(perc)-perc/2). 为我工作theme_void() 也很有用
【解决方案3】:

它适用于所有包含的功能,灵感来自here

 ggpie <- function (data) 
{
  # prepare name
  deparse( substitute(data) ) -> name ;

  # prepare percents for legend
  table( factor(data) ) -> tmp.count1
  prop.table( tmp.count1 ) * 100 -> tmp.percent1 ;
  paste( tmp.percent1, " %", sep = "" ) -> tmp.percent2 ;
  as.vector(tmp.count1) -> tmp.count1 ;

  # find breaks for legend
  rev( tmp.count1 ) -> tmp.count2 ;
  rev( cumsum( tmp.count2 ) - (tmp.count2 / 2) ) -> tmp.breaks1 ;

  # prepare data
  data.frame( vector1 = tmp.count1, names1 = names(tmp.percent1) ) -> tmp.df1 ;


  # plot data
  tmp.graph1 <- ggplot(tmp.df1, aes(x = 1, y = vector1, fill = names1 ) ) +
    geom_bar(stat = "identity", color = "black" ) +
    guides( fill = guide_legend(override.aes = list( colour = NA ) ) ) +
    coord_polar( theta = "y" ) +
    theme(axis.ticks = element_blank(),
          axis.text.y = element_blank(),
          axis.text.x = element_text( colour = "black"),
          axis.title = element_blank(),
          plot.title = element_text( hjust = 0.5, vjust = 0.5) ) +
    scale_y_continuous( breaks = tmp.breaks1, labels = tmp.percent2 ) +   
    ggtitle( name ) + 
    scale_fill_grey( name = "") ;

  return( tmp.graph1 )
} ;

一个例子:

sample( LETTERS[1:6], 200, replace = TRUE) -> vector1 ;
ggpie(vector1)

Output

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多