同一张图中同时使用交错和堆叠的geom_bar?

6

我有以下图表,它实际上是两个分布的直方图并排绘制在一起:

my.barplot <- function( df, title="", ... ) {
  df.count <- aggregate( df$outcome, by=list(df$category1,df$outcome), FUN=length )
  colnames( df.count ) <- c("category1","outcome","n")
  df.total <- aggregate( df.count$n, by=list(df.count$category1), FUN=sum )
  colnames( df.total ) <- c("category1","total")
  df.dens <- merge(df.count, df.total)
  df.dens$dens <- with( df.dens, n/total )
  p <- ggplot( df.dens, aes( x=outcome, fill=category1 ), ... )
  p <- p + geom_bar( aes( y=dens ), position="dodge" )
  p <- p + opts( axis.text.x=theme_text(angle=-90,hjust=0), title=title )
  p
}

N <- 50*(2*8*2)
outcome <- sample(ordered(seq(8)),N,replace=TRUE,prob=c(seq(4)/20,rev(seq(4)/20)) )
category2 <- ifelse( outcome==1, sample(c("yes","not"), prob=c(.95,.05)), sample(c("yes","not"), prob=c(.35,.65)) )
dat <- data.frame(
  category1=rep(c("in","out"),each=N/2),
  category2=category2,
  outcome=outcome
  )

my.barplot(dat)

现有的条形图

我想在每个条形图中绘制属于某个第二类别的比例。如果没有按照第一类别进行组织的需要,我就会叠放这些柱形图。但是,我无法弄清楚如何按第二类别叠加。基本上,在每个结果-类别1条中,我希望类别2中的比例被阴影较深地涂色。

下面是我想要创建的GIMP图片:

堆积类别2比例的条形图


我在邮件列表中找到了这个相当古老的帖子。不确定这个功能是否被整合到后来的版本中。 - joran
4
抱歉我现在没有更多的时间,但我想放个链接给你,希望能给你一些想法:http://learnr.wordpress.com/2009/04/02/ggplot2-marimekko-replacement-overlapping-bars/ 简而言之:绘制两个分离的条形图层。你可以使用不同的颜色方案来区分条形图,或者使用相同的颜色方案,并使用“alpha()”函数使它们半透明 - 非堆叠的是浅色,堆叠的是全彩。 - Matt Parker
谢谢Joran和Matt。我会尝试使用图层和透明度技巧,希望今天晚些时候能成功。 - Ari B. Friedman
3个回答

7

图形基础?!永远不用

这是我想到的。我承认我很难理解你所有的聚合和准备工作,所以我只聚合到计数,可能搞错了一切 - 但似乎你处于一个更容易从一个可用绘图开始然后正确获取输入的位置。这个做到了吗?

# Aggregate
dat.agg <- ddply(dat, .var = c("category1", "outcome"), .fun = summarise,
                 cat1.n = length(outcome),
                 yes = sum(category2 %in% "yes"),
                 not = sum(category2 %in% "not")
)


# Plot - outcome will be x for both layers
ggplot(dat.agg, aes(x = outcome)) +

    # First layer of bars - for category1 totals by outcome
    geom_bar(aes(weight = cat1.n, fill = category1), position = "dodge") +

    # Second layer of bars - number of "yes" by outcome and category1
    geom_bar(aes(weight = yes, fill = category1), position = "dodge") +

    # Transparency to make total lighter than "yes" - I am bad at colors
    scale_fill_manual(value = c(alpha("#1F78B4", 0.5), alpha("#33A02C", 0.5))) +

    # Title
    opts(title = "A pretty plot <3")

Plot with bars that are simultaneously dodged, overlaid, and transparent


我喜欢这个!太完美了。你堆叠了闪避而不是试图躲避堆叠,如果这有任何意义的话 :-) - Ari B. Friedman
你有没有什么提示可以帮助我为category2添加图例呢?因为category1是两者的填充,所以6.4.5 ggplot2手册的建议是使用identity_scale,但是进一步阅读后发现这样做会导致图例消失,所以我很无助。 - Ari B. Friedman
@gsk3 是的,这种方法的一个主要缺陷就是没有办法得到图例,因为在ggplot看来,这里只有两种颜色。我认为你需要以一种相当基本的方式重新构造数据,但我现在想不出来。不过我注意到你熟悉GIMP... - Matt Parker
事实上,经过深思熟虑,那正是我会做的事情。按照上面的绘图方法进行操作,复制/粘贴类别1的图例,然后使用吸管工具+填充功能将颜色从条形图中设置。只要你不需要制作无数个这样的图表,这个方法还是相当可行的。 - Matt Parker

1

我喜欢@MattP的评论;我只想补充一点,除了使用alpha()之外,还可以直接指定透明度。例如,#FF0000是纯色,而#FF000033是淡色/部分透明色。 像往常一样,搜索http://addictedtor.free.fr/graphiques/可能会帮助您找到创建所需图形风格的代码。


有趣的是,您如何评估您所提供的透明度级别?只是玩弄一下,似乎“#1F78B499”与alpha(“#1F78B4”,0.5)大致相当 - 如果要做到75%的不透明度,您会怎么做呢? - Matt Parker
1
@Matt:最后两位数字,就像两位数的颜色值一样,从00到FF。你来算吧 :-) - Carl Witthoft

0

好的,我尝试了一下,但除了将适当的密度放在同一个数据框中之外,没有取得太多进展:

my.barplot <- function( df, title="", legend.title="",... ) {
  df.count12 <- aggregate( df$outcome, by=list(df$category1,df$category2,df$outcome), FUN=length )
  colnames( df.count12 ) <- c("category1","category2","outcome","n")
  df.total <- aggregate( df.count12$n, by=list(df.count12$category1), FUN=sum )
  colnames( df.total ) <- c("category1","total")
  # Densities within a bar - Categories 1 & 2
  df.dens12 <- merge(df.count12, df.total)
  df.dens12$dens12 <- with( df.dens12, n/total )
  # Total bar height - Category 1 density
  df.count1 <- aggregate( df.dens12$n, by=list(df.dens12$category1,df.dens12$outcome), FUN=sum )
  colnames( df.count1 ) <- c("category1","outcome","n")
  df.dens1 <- merge(df.count1,df.total)
  df.dens1$dens1 <- with(df.dens1, n/total)
  # Merge both into the final dataset
  df.dens <- merge(df.dens12,df.dens1,all.x=TRUE,by=c("category1","outcome"))
  df.dens <- subset(df.dens, select=c(-total.x) )
  colnames( df.dens ) <- sub("\\.x","12",colnames(df.dens))
  colnames( df.dens ) <- sub("\\.y","1",colnames(df.dens))
  # Plot 
  ymax <- max(df.dens$dens1)
  # Plot 1: category1
  p <- ggplot( df.dens, aes( x=outcome, fill=category1 ), ... )
  p1 <- p + geom_bar( aes( y=dens1 ), position="dodge" )
  p1 <- p1 + opts( axis.text.x=theme_text(angle=-90,hjust=0), title=title )
  if(legend.title!="") { p1 <- p1 + scale_colour_discrete(name=legend.title) }
  # Plot 2: category2
  p2 <- p1 + geom_bar( aes( y=dens12, fill=category2 ), position="stack", stat="identity" )
  p2
}

N <- 50*(2*8*2)
outcome <- sample(ordered(seq(8)),N,replace=TRUE,prob=c(seq(4)/20,rev(seq(4)/20)) )
category2 <- ifelse( outcome==1, sample(c("yes","not"), prob=c(.95,.05)), sample(c("yes","not"), prob=c(.35,.65)) )
dat <- data.frame(
  category1=rep(c("in","out"),each=N/2),
  category2=category2,
  outcome=outcome
  )

my.barplot(dat, title="Test title", legend.title="Medical system")

与链接中的尝试相比,很明显他是将第三个维度(x=结果,dodge=类别1,stack=类别2)与网格布局一起使用,而我真正需要的是将第三个维度堆叠在第二个维度内。我想我可能已经到了折磨ggplot2的地步,应该只是编写一个使用基本图形的函数。唉。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接