首页 文章

在堆叠的ggplot条形图中标记单个条形图

提问于
浏览
4

有没有一种简单的方法可以在"stacked"条形图中标记单个"blocks",如下所示 . 我希望标签位于每个区块的顶部附近,但我的最新方法导致以某种方式交换美国和墨西哥的文本,如下所示 .

example bar graph

寻找解决方案,我只找到了必须在外部预先计算文本的 y 值的方法,除了额外的逻辑之外,还带来了控制块堆叠顺序的问题 . .
我也发现了这个stackoverflow question我在 stat_bin 中使用 geom="text" 的想法(见下面的代码)
这是一个精简的代码片段,用于说明我当前的方法 . 我不一定试图修复这个片段,标签堆栈条形图区域的任何通用成语都可以!
编辑:(鉴于到目前为止这个问题的两个答案)
我想强调 I'd rather solutions which don't imply pre-computing the y position of the text .

# sample data source
df.StackData <- data.frame(
    QType = c("A4-1", "A4-1", "A4-1",  "B3", "B3", "B3"),
    Country = c("Canada", "USA", "Mexico", "Canada", "USA", "Mexico"),
    NbOfCases = c(1000, 1320, 380, 400, 1000, 812),
    AvgRate = c(17.2, 11.4, 44.21, 17.3, 15.3, 39.7),
    Comment = c("Can", "US", "Mex", "Can", "US", "Mex")
)

和ggplot调用 . 它生成上面显示的图形,标签交换奇怪(也是一个额外的图例,'虽然这个传奇问题很容易处理;我只是在准备这个问题时注意到它) .

ggplot(data=df.StackData,
       aes(x=QType, y=NbOfCases, fill=Country))+
  geom_bar(stat="identity", width=1) +
  stat_bin(geom="text", aes(label=paste("R coef =",
                                        formatC(AvgRate, format="f", digits=3),
                                        "(", Comment, ")" ),
                            vjust=1.5, size=3 
                        )
  )

我最初尝试将geom_text()添加到图形中,如下所示,但当然y值是错误的(相对于图形的底部而不是单个块底部的文本)...

... +
  geom_text(mapping=aes(x=QType, y=NbOfCases, 
                        label=paste("R coef =",
                                    formatC(AvgRate, format="f", digits=3),
                                    "(", Comment, ")" ),
                         vjust=1.5),
            size=3)

4 回答

  • 1

    这是一个解决方案 . 这里有两件事 . 首先,您应该 data.framedata.frame 的级别设置为与数据 df.StackData 中相同的顺序 . 其次,创建另一个 data.frame 以通过计算数据的累积总和来计算 y-position .

    # reorder levels of factor to the same order as found in data
    df.StackData$Country <- factor(df.StackData$Country, 
              levels=c("Canada", "USA", "Mexico"), ordered=TRUE)
    p <- ggplot(data=df.StackData, aes(x=QType, fill=Country))
    p <- p + geom_bar(aes(weights=NbOfCases))
    
    # compute corresponding y-axis positions by cumulative sum
    require(plyr)
    df <- ddply(df.StackData, .(QType), function(x) {
        x$NbOfCases <- cumsum(x$NbOfCases)
        x
    })
    
    # then use geom_text with data = df (the newly created data)
    p + geom_text(data = df,  aes(x=QType, y=NbOfCases, 
            label=paste("R coef =", 
            formatC(AvgRate, format="f", digits=3), 
            "(", Comment, ")" ), vjust=1.5), size=3)
    

    enter image description here

    Edit: 如果你不't want to calculate the y-pos yourself, then you'将不得不使用 stat_bin . 只需重新排序列 Country 的级别,它的工作原理如下:

    # data
    df.StackData <- data.frame(
        QType = c("A4-1", "A4-1", "A4-1",  "B3", "B3", "B3"),
        Country = c("Canada", "USA", "Mexico", "Canada", "USA", "Mexico"),
        NbOfCases = c(1000, 1320, 380, 400, 1000, 812),
        AvgRate = c(17.2, 11.4, 44.21, 17.3, 15.3, 39.7),
        Comment = c("Can", "US", "Mex", "Can", "US", "Mex")
    )
    
    # just add this: reorder the level 
    df.StackData$Country <- factor(df.StackData$Country, 
              levels=c("Canada", "USA", "Mexico"), ordered=TRUE)
    
    # your code again using stat_bin (just changed the width to 0.75)
    ggplot(data=df.StackData,
           aes(x=QType, y=NbOfCases, fill=Country))+
      geom_bar(stat="identity", width=.75) +
      stat_bin(geom="text", size=4, aes(label=paste("R coef =",
                                            formatC(AvgRate, format="f", digits=3),
                                            "(", Comment, ")" ),
                                vjust=1.5))
    

    enter image description here

  • 1

    这是一个解决方案

    df2 = ddply(df.StackData, .(QType), transform, 
     pos = cumsum(NbOfCases) - 0.5 * NbOfCases)
    
    ggplot(data = df2, aes(x = QType, y = NbOfCases, fill = Country)) +
      geom_bar(stat = "identity") +
      geom_text(aes(y = pos, label = paste("R coef =", 
       formatC(AvgRate, format="f", digits=3), "(", Comment, ")" ))
      )
    

    Imgur

  • 2

    这里's an alternative - because your factor will be ordered alphabetically by default, I suggest reordering your dataframe to match this instead of reordering the factor to match the order of the dataframe. To my mind, this would allow a more general solution. The only reason you were getting a legend you didn' t想要的是你在 aes 里面的大小 - 我已经修复了下面的内容 .

    使用您的数据:

    df.StackData <- with(df.StackData, df.StackData[order(Country),])
    

    然后你可以使用 stat_bin 的原始解决方案 . 我用一些更复杂的数据集测试它只是为了检查它是否有效:

    df.StackData <- data.frame(
      QType = rep(c("A4-1","B3"), each = 6),
      Country = rep(c("Canada", "USA", "Mexico", "UK", "Sweden", "Australia"), times = 2),
      NbOfCases = c(1000, 1320, 380, 400, 1000, 812, 542, 531, 674, 328, 795, 721),
      AvgRate = c(17.2, 11.4, 44.21, 17.3, 15.3, 39.7, 21.1, 25.3, 24.1, 31.3, 38.4, 36.1),
      Comment = rep(c("Can", "US", "Mex", "UK", "Aus", "Swe"), times = 2)
    )
    

    没有排序:

    ggplot(data=df.StackData,
           aes(x=QType, y=NbOfCases, fill=Country))+
      geom_bar(stat="identity", width=1) +
      stat_bin(geom="text", aes(label=paste("R coef =", formatC(AvgRate, format="f", digits=3),
    "(", Comment, ")" ),  vjust = 1),size=3)
    geom_text(aes(label = Comment), stat="identity")
    

    enter image description here

    排序后:

    df.StackData < - with(df.StackData,df.StackData [order(Country),])

    enter image description here

  • 2

    为了删除额外的图例,您可以使用 show_guide=FALSE . 在你的例子中:

    ggplot(data=df.StackData,
           aes(x=QType, y=NbOfCases, fill=Country))+
      geom_bar(stat="identity", width=.75) +
      stat_bin(geom="text", size=4, aes(label=paste("R coef =",
                                            formatC(AvgRate, format="f", digits=3),
                                            "(", Comment, ")" ),
                                vjust=1.5), show_guide=FALSE)
    

相关问题