讨厌的饼形图箭头

问题描述

让我们有以下代码:

pie_chart <- function(vec){
  
  df <- as.data.frame(table(vec))
  colnames(df)[1] <- 'group'
  df$label <- paste0(df$Freq,' (',percent(df$Freq / sum(df$Freq)),')')
  df$angle <- ((cumsum(df$Freq) - 0.5 * df$Freq) / sum(df$Freq) * 360) %% 180 - 90  
  ggplot(df,aes(x = "",y = Freq,fill = group)) +
    geom_col(width = 1,show.legend = TRUE) +
    geom_text(
      aes(label = label,angle = angle),position = position_stack(vjust = 0.5),size = 5
    ) +
    coord_polar("y",start = 0) +
    theme_void()
}

pie_chart(c(rep(2,20),rep(3,30),rep(4,4),rep(5,50),rep(6,30)))

enter image description here

如上所示,文本居中(相对于饼图的每个部分)居中并旋转到圆圈的中间。

我想做的是将所有小于所有饼图的5%的值添加到箭头。因此,在我们的示例中,值“ 4(3.0)%”不应出现在饼图中,而应远超过箭头。

现在让我们研究我对该问题的研究:

pie_chart <- function(vec){
  df <- as.data.frame(table(vec))
  colnames(df)[1] <- 'group'
  df$label <- paste0(df$Freq,angle = angle,x = ifelse(rev(Freq) / sum(Freq) < 0.05,1.7,1)),size = 5
    ) +  geom_segment(aes(x = 1.6,xend = 1.5,y = rev(Freq)/2 + c(0,cumsum(rev(Freq))[-length(Freq)]),yend = after_stat(y),colour = I(ifelse(rev(Freq) / sum(Freq) < 0.05,"black","transparent"))),arrow = arrow(length = unit(1,"mm"))) +
    coord_polar("y",30)))

enter image description here

正如您所看到的,我面临两个问题:

(1)布局崩溃(让我们看一下饼的红色部分)

(2)文本“ 4(3.0%)”在饼图上方,而不是与箭头连接(正确创建)

有什么办法可以解决问题(1)和(2)?

谢谢!

更新

按照SebSta的建议,我在他的代码中添加了箭头,它适用于这种特定情况。但是当我加上七个数字时,布局崩溃(我认为)

pie_chart <- function(vec){
  
  df <- as.data.frame(table(vec))
  colnames(df)[1] <- 'group'
  df$label <- paste0(df$Freq,round(df$Freq / sum(df$Freq),3)*100,'%)')
  df$angle <- ((cumsum(df$Freq) - 0.5 * df$Freq) / sum(df$Freq) * 360) %% 180 - 90
  
  ggplot(df,color = ifelse(rev(df$Freq)/(sum(df$Freq))<0.05,"transparent","black"),size = 5
    ) + geom_segment(aes(x = 1.6,"mm"))) +
    geom_text(aes(label =label,x =1.8),color = ifelse(rev(df$Freq)/(sum(df$Freq))>0.05,size = 5,) +
    coord_polar("y",rep(7,3)))

enter image description here

解决方法

您可以使用position_identity作为标签并计算出确切位置:

pie_chart <- function(vec){
  
  df <- as.data.frame(table(vec))
  colnames(df)[1] <- 'group'
  df$label <- paste0(df$Freq,' (',scales::percent(df$Freq / sum(df$Freq)),')')
  df$angle <- ((cumsum(df$Freq) - 0.5 * df$Freq) / sum(df$Freq) * 360) %% 180 - 90
  ggplot(df,aes(x = "",y = Freq,fill = group)) +
    geom_col(width = 1,show.legend = TRUE) +
    geom_text(
      aes(x = ifelse(Freq/sum(Freq) < 0.05,1.8,1),y = sum(Freq) - (cumsum(c(0,Freq[-length(Freq)])) + 0.5 * Freq),label = label,angle = angle),position = position_identity(),vjust = 0.25,size = 4
    ) +  geom_segment(aes(x = 1.6,xend = 1.5,y = rev(Freq)/2 + c(0,cumsum(rev(Freq))[-length(Freq)]),yend = after_stat(y),colour = I(ifelse(rev(Freq) / sum(Freq) < 0.05,"black","transparent"))),arrow = arrow(length = unit(1,"mm"))) +
    coord_polar("y",start = 0) +
    theme_void()
}

pie_chart(c(rep(2,20),rep(3,30),rep(4,4),rep(5,50),rep(6,30)))

enter image description here

,

在这里,我的第一个想法将是一种不明智的做法:两次编写标签,一次是普通标签,所有值 5%都是透明的。然后,您可以使用x坐标调整到饼图的距离:

pie_chart <- function(vec){
  
  df <- as.data.frame(table(vec))
  colnames(df)[1] <- 'group'
  df$label <- paste0(df$Freq,round(df$Freq / sum(df$Freq),3)*100,'%)')
  df$angle <- ((cumsum(df$Freq) - 0.5 * df$Freq) / sum(df$Freq) * 360) %% 180 - 90

  ggplot(df,show.legend = TRUE) +
    geom_text(
      aes(label = label,color = ifelse(rev(df$Freq)/(sum(df$Freq))<0.05,"transparent","black"),position = position_stack(vjust = 0.5),size = 5
    ) +
    geom_text(aes(label =label,angle = angle,x =1.8),color = ifelse(rev(df$Freq)/(sum(df$Freq))>0.05,size = 5,) +
    coord_polar("y",30)))

enter image description here

请注意,我无法复制您的箭头,因为我没有after_stat功能。我猜那是R 4.0.0的新版本,而我使用3.6.1。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...