【问题标题】:How can a line be overlaid on a bar plot using ggplot2?如何使用 ggplot2 在条形图上叠加一条线?
【发布时间】:2010-12-02 06:22:41
【问题描述】:

我正在寻找一种方法来绘制包含两个不同系列的条形图,隐藏其中一个系列的条形,而是让一条线(如果可能的话平滑)穿过隐藏系列的条形的顶部已经(类似于人们如何在直方图上叠加频率多项式)。我已经尝试了下面的示例,但似乎遇到了两个问题。

首先,我需要按组汇总(总计)数据,其次,我想将其中一个系列(df2)转换为一行。

df <- data.frame(grp=c("A","A","B","B","C","C"),val=c(1,1,2,2,3,3))  
df2 <- data.frame(grp=c("A","A","B","B","C","C"),val=c(1,4,3,5,1,2))  
ggplot(df, aes(x=grp, y=val)) +   
    geom_bar(stat="identity", alpha=0.75) +  
    geom_bar(data=df2, aes(x=grp, y=val), stat="identity", position="dodge")

【问题讨论】:

    标签: r ggplot2


    【解决方案1】:

    您可以通过多种方式获取组总数。其中之一是

    with(df, tapply(val, grp, sum))
    

    为简单起见,您可以将条形和线形数据组合成一个数据集。

    df_all <- data.frame(grp = factor(levels(df$grp)))
    df_all$bar_heights <- with(df, tapply(val, grp, sum))
    df_all$line_y <- with(df2, tapply(val, grp, sum))
    

    条形图使用分类 x 轴。要覆盖一条线,您需要将轴转换为数字。

    ggplot(df_all) +
       geom_bar(aes(x = grp, weight = bar_heights)) +
       geom_line(aes(x = as.numeric(grp), y = line_y))
    

    【讨论】:

    • 不错的答案(+1)!我喜欢这种方法。我想这取决于原始源数据来自哪里,哪些需要更少的编码。
    【解决方案2】:

    也许您的样本数据不能代表您正在使用的真实数据,但没有为df2 画线。每个 x 和 y 值只有一个值。这是您的 df2 的修改版本,其中包含足够的数据点来构建线条:

    df <- data.frame(grp=c("A","A","B","B","C","C"),val=c(1,2,3,1,2,3))
    df2 <- data.frame(grp=c("A","A","B","B","C","C"),val=c(1,4,3,5,0,2))
    
    p <- ggplot(df, aes(x=grp, y=val)) 
    p <- p + geom_bar(stat="identity", alpha=0.75) 
    
    p + geom_line(data=df2, aes(x=grp, y=val), colour="blue")
    

    或者,如果您上面的示例数据是正确的,您可以将此信息绘制为带有geom_point(data = df2, aes(x = grp, y = val), colour = "red", size = 6) 的点。您显然可以根据自己的喜好更改颜色和大小。

    编辑:回应评论

    我不完全确定直方图上的频率多项式的视觉效果应该是什么样子。 x值是否应该相互连接?其次,您一直提到想要的行,但您的代码显示 geom_bar() 我认为这不是您想要的?如果你想要线条,请使用geom_lines()。如果上面的两个假设是正确的,那么这里有一个方法来做到这一点:

     #First let's summarise df2 by group
     df3 <- ddply(df2, .(grp), summarise, total = sum(val))
    >  df3
      grp total
    1   A     5
    2   B     8
    3   C     3
    
    #Second, let's plot df3 as a line while treating the grp variable as numeric
    
    p <- ggplot(df, aes(x=grp, y=val))
    p <- p + geom_bar(alpha=0.75, stat = "identity") 
    p + geom_line(data=df3, aes(x=as.numeric(grp), y=total), colour = "red")
    

    【讨论】:

    • 实际上,我正在寻找一种方法来绘制包含两个不同系列的条形图,隐藏其中一个条形图,而是让一条线(如果可能的话平滑)穿过条形图的顶部因为隐藏的系列本来是(类似于在直方图上叠加频率多项式的方式)。
    • 我澄清了最初的问题。到目前为止,感谢您的帮助 - 看来我错过了首先汇总数据的步骤。
    • @user338714 - 更新的回复,我还是有点不清楚你到底想要什么。如果你想要的不是上面的,你能找到一个你想要的最终图像的例子吗?
    • 这正是我想要的!谢谢。