将两个图例独立定位在ggplot2图中 [英] Positioning two legends independently in a faceted ggplot2 plot

查看:1172
本文介绍了将两个图例独立定位在ggplot2图中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个由ggplot2生成的图,其中包含两个图例。传说中的
放置并不理想,所以我想调整它们的
。我一直在试图模仿
中显示的方法我如何在ggplot中独立定位两个图例
该答案中显示的示例有效。
然而,我无法得到所描述的方法适用于我的情况。



我使用R 2.15.3(2013-03-01) ,ggplot2_0.9.3.1,lattice_0.20-13,gtable_0.1.2,gridExtra_0.9.1
在Debian squeeze上。



考虑由 minimal.R 。这与我实际情节中的
类似。

  ############## ########## 
minimal.R
########################

get_stat < - function()
{
n = 20
q1 = qnorm(seq(3,17)/ 20,14,5)
q2 = qnorm seq(1,19)/ 20,65,10)
Stat = data.frame(value = c(q1,q2),
pvalue = c(dnorm(q1,14,5)/ max (dnorm(q1,14,5)),d = dnorm(q2,65,10)/ max(dnorm(q2,65,10))),
variable = c(rep('true',length ()),rep('data',length(q2))))
return(Stat)
}

stat_all< - function()
{
library(ggplot2)
library(gridExtra)
stathuman = get_stat()
stathuman $ dataset =human
statmouse = get_stat()
statmouse $ dataset =mouse
stat = merge(stathuman,statmouse,all = TRUE)
return(stat)
}

simplot< - function()
{
Stat = stat_all()
Pvalue = subset(Stat,variable ==true)
pdf(file =CDF
stat = ggplot()+ stat_ecdf(data = Stat,n = 1000,aes(x = value,color = variable))+
theme( legend.key = element_blank(),legend.background = element_blank(),legend.position = c(.9,.25),legend.title = element_text(face =bold))+
scale_x_continuous(负数对数似然性)+
scale_y_continuous(比例$ <$ x)+
facet_grid(〜dataset,scales ='free')+
scale_colour_manual(values = c(blue ,red),name =数据类型,
labels = c(Gene segments,Model),guide = guide_legend(override.aes = list(size = 2)))+
geom_area(data = Pvalue,aes(x = value,y = pvalue,fill = variable),position =identity,alpha = 0.5)+
scale_fill_manual(values = c(gray), name =Pvalue,labels = c())
print(stat)
dev.off()
}

simplot()

这导致i在下面的图中。可以看出,数据类型
Pvalue 图例定位不准确。我将此代码修改为
minimal2.R





在版本1中,应该将图例置于顶端,代码运行
没有错误,但没有显示图例。

编辑:有两个框显示,一个在另一个之上。最高的
是空白的。如果我没有在> grid.arrange()中设置高度,如@ bptiste,
所示,则图例和图都放在底部框中。
如果我如图所示设置高度,那么我看不到图例。



编辑2:看起来额外的空白框被<$ c调用$ c> grid.newpage ,
我从前面的问题中复制过来的。我不知道为什么它在那里。
如果我不使用该行,那么我只会得到一个框/页。



在版本2中,我收到此错误。

  UseMethod(grid.draw)中的错误:
没有应用于类的对象的'grid.draw'的适用方法c('gg','ggplot')
呼叫:simplot - > grid.draw

编辑:如果我使用 print(plotNew)按照@baptiste的建议,那么我得到以下错误:

pre $ if(empty(data)){ :缺少TRUE / FALSE所需的值
调用:simplot ... facet_map_layout - > facet_map_layout.grid - > locate_grid。

我试图弄清楚这里发生了什么,但我找不到多少
相关信息。



注意:


  1. 我不确定为什么我得到
    经验CDF的阶梯效应。我确信有一个明显的解释。如果您知道,请
    启发我。

  2. 我愿意考虑替代此代码,甚至ggplot2为
    产生此图,如果任何人都可以提出替代方案,例如
    matplotlib,我从来没有认真尝试过。
  3. 添加

      print(ggplot_gtable(ggplot_build(stat2)))

    minimal2 .R 给我

      TableGrob(7 x 7)layout:12 grobs 
    z单元格名称grob
    1 0(1-7,1-7)背景矩形[plot.background.rect.186]
    2 1(3-3,4-4)strip-top absoluteGrob [ strip.absoluteGrob.135]
    3 2(3-3,6-6)strip-top absoluteGrob [strip.absoluteGrob.141]
    4 5(4-4,3-3)axis-l绝对Grob [GRID.absoluteGrob.129]
    5 3(4-4,4-4)panel gTree [GRID.gTree.155]
    6 4(4-4,6-6)panel gTree [ GRID.g [169]]
    7 6(5-5,4-4)axis -b absoluteGrob [GRID.absoluteGrob.117]
    8 7(5-5,6-6)axis-b absoluteGrob [GRID.absoluteGrob.123]
    9 8(6-6,4-6)xlab text [axis.title.x.text.171]
    10 9(4-4,2-2 )ylab text [axis.title.y.text.173]
    11 10(4-4,4-6)guide box gtable [guide-box]
    12 11(2-2,4 -6)title text [plot.title.text.184]

    我不明白这个细目。谁能解释一下?
    guide-box 是否与图例相符,以及如何知道这一点?


以下是我的代码的修改版本, minimal2.R

  ######################## 
minimal2.R
##### ###################

get_stat< - function()
{
n = 20
q1 = qnorm(seq(3,17)/ 20,14,5)
q2 = qnorm(seq(1,19)/ 20,65,10)
Stat = data.frame(value = c (q1,q2),
pvalue = c(dnorm(q1,14,5)/ max(dnorm(q1,14,5)),d = dnorm(q2,65,10)/ max(dnorm ($)
变量= c(rep('true',length(q1)),rep('data',length(q2))))
return(Stat)

$ b $ stat_all< - function()
{
library(ggplot2)
library(gridExtra)
library(gtable)
stathuman = get_stat()
stathuman $ dataset =human
statmouse = get_stat()
statmouse $ dataset =mouse
stat = merge(stathuman,statmouse,所有= TRUE)
return(stat)
}

simplot< - function()
{
Stat = stat_all()
Pvalue = subset(Stat ,变量==真)
pdf(文件=CDF.pdf,宽度= 5.5,高度= 2.7)

##只包括数据类型图例
stat1 = ggplot()+ stat_ecdf(data = Stat,n = 1000,aes(x = value,color = variable))+
主题(legend.key = element_blank(),legend.background = element_blank() .position = c(.9,.25),legend.title = element_text(face =bold))+
scale_x_continuous(负对数似然)+
scale_y_continuous(比例$< $ x $)+
facet_grid(〜dataset,scales ='free')+
scale_colour_manual(values = c(blue,red),name =Data type,labels = c (数据= P值,aes(x =值,y = p值,填充=数值)变量),position =identity,alpha = 0.5)+
scal e_fill_manual(values = c(gray),name =Pvalue,labels = c(),guide = FALSE)

##提取数据类型图例
dataleg< - gtable_filter(ggplot_gtable(ggplot_build(stat1)),guide-box)

##只包括pvalue图例
stat2 = ggplot()+ stat_ecdf(data = Stat,n = 1000 ,aes(x = value,color = variable))+
theme(legend.key = element_blank(),legend.background = element_blank(),legend.position = c(.9,.25),legend。 title = element_text(face =bold))+
scale_x_continuous(负对数似然)+
scale_y_continuous(比例$ <$ x)+
facet_grid(〜dataset, scale ='free')+
scale_colour_manual(values = c(blue,red),name =Data type,labels = c(Gene segments,Model),guide = FALSE )+
geom_area(data = Pvalue,aes(x = value,y = pvalue,fill = variable),position =identity,alpha = 0.5)+
scale_fill_manual(values = c(gray ),name =P (ggplot_gtable(ggplot_build(stat2)),guide-box)
$ b $ ##没有传说
stat = ggplot()+ stat_ecdf(data = Stat,n = 1000,aes(x = value,color = variable))+
theme(legend。 key = element_blank(),legend.background = element_blank(),legend.position = c(.9,.25),legend.title = element_text(face =bold))+
scale_x_continuous(Negative log可能性)+
scale_y_continuous(比例$ <$ x)+
facet_grid(〜dataset,scales ='free')+
scale_colour_manual(values = c(blue, red),name =Data type,labels = c(Gene segments,Model),guide = FALSE)+
geom_area(data = Pvalue,aes(x = value,y = pvalue ,fill = variable),position =identity,alpha = 0.5)+
scale_fill_manual(values = c(gray),name =Pvalue,labels = c(),guide = FALSE)

##添加数据类型图例: (dataleg $ height,unit(1,npc) - dataleg $ height) ,ncol = 1)

##添加数据类型图例:版本2(数据类型图例应位于内部某处)
## plotNew< - stat + annotation_custom(grob = dataleg ,xmin = 7,xmax = 10,ymin = 0,ymax = 4)

grid.newpage()
grid.draw(plotNew)
dev.off()


simplot()


解决方案

它可以通过grid.arrange和arrangeGrob完成,但正确调整高度和宽度是一件很痛苦的事情。

  grid.arrange(arrangeGrob(dataleg,pvalleg,nrow = 1,ncol = 2,widths = c(unit(1,npc),unit(5,cm)))stat,nrow = 2,height = c(单位(.2,npc),单位(.8,npc)))

我通常更喜欢用适当的图例创建新图并使用这个新图例:


$ b $ (10),b = rnorm(10),c =因子(rbinom(10,1,.5)),其中b

  h < -  ggplot ,标签= c(基因片段,模型)),d =因子()),
aes(x = a,y = b))+
geom_line(aes = c),size = 1.3)+ geom_polygon(aes(fill = d))+
scale_color_manual(values = c(blue,red),name =Data type)+
scale_fill_manual(values =gray,name =P-value)
g_legend <-function(a.gplot){
tmp< - ggplot_gtable(ggplot_build(a.gplot))
$ leg< - which(sapply(tmp $ grobs,function(x)x $ name)==guide-box)
legend< - tmp $ grobs [[leg]]
return (图例)
}
图例< - g_legend(h)

grid.arrange(stat,legend,nrow = 1,ncol = 2,widths = c(unit (单元(.2,npc),单元(.2,npc)))
grid.arrange(legend,stat,nrow = 2,ncol = 1,heights = c ),单位(.8,npc)))


I have a plot generated by ggplot2, which contains two legends. The placing of the legends is not ideal, so I would like to adjust them. I've been trying to imitate the method shown in the answer to "How do I position two legends independently in ggplot". The example shown in that answer works. However, I can't get the method described to work for my situation.

I'm using R 2.15.3 (2013-03-01), ggplot2_0.9.3.1, lattice_0.20-13, gtable_0.1.2, gridExtra_0.9.1 on Debian squeeze.

Consider the plot generated by minimal.R. This is similar to my actual plot.

########################
minimal.R
########################

get_stat <- function()
  {
    n = 20
    q1 = qnorm(seq(3, 17)/20, 14, 5)
    q2 = qnorm(seq(1, 19)/20, 65, 10)
    Stat = data.frame(value = c(q1, q2),
      pvalue = c(dnorm(q1, 14, 5)/max(dnorm(q1, 14, 5)), d = dnorm(q2, 65, 10)/max(dnorm(q2, 65, 10))),
      variable = c(rep('true', length(q1)), rep('data', length(q2))))
    return(Stat)
  }

stat_all<- function()
{
  library(ggplot2)
  library(gridExtra)
  stathuman = get_stat()
  stathuman$dataset = "human"
  statmouse = get_stat()
  statmouse$dataset = "mouse"
  stat = merge(stathuman, statmouse, all=TRUE)
  return(stat)
}

simplot <- function()
  {
    Stat = stat_all()
    Pvalue = subset(Stat, variable=="true")
    pdf(file = "CDF.pdf", width = 5.5, height = 2.7)
    stat = ggplot() + stat_ecdf(data=Stat, n=1000, aes(x=value, colour = variable)) +
      theme(legend.key = element_blank(), legend.background = element_blank(), legend.position=c(.9, .25), legend.title = element_text(face = "bold")) +
        scale_x_continuous("Negative log likelihood") +
          scale_y_continuous("Proportion $<$ x") +
            facet_grid(~ dataset, scales='free') +
              scale_colour_manual(values = c("blue", "red"), name="Data type",
                                  labels=c("Gene segments", "Model"), guide=guide_legend(override.aes = list(size = 2))) +
                geom_area(data=Pvalue, aes(x=value, y=pvalue, fill=variable), position="identity", alpha=0.5) +
                  scale_fill_manual(values = c("gray"), name="Pvalue", labels=c(""))
    print(stat)
    dev.off()
  }

simplot()

This results in the following plot. As can be seen, the Data type and Pvalue legends are not well positioned. I modified this code to minimal2.R.

With Version 1, which should put the legend on the top, the code runs without error, but no legend is shown.

EDIT: There are two boxes displayed, one on top of the other. The top one is blank. If I do not set the heights in grid.arrange(), as suggeted by @baptiste, then the legend and the plot are both placed in the bottom box. If I set the height as shown, then I don't see the legend.

EDIT2: It seems the extra blank box was called by grid.newpage, which I copied from the earlier question. I'm not sure why it was there. If I don't use that line, then I just get one box/page.

With Version 2, I get this error.

Error in UseMethod("grid.draw") :
  no applicable method for 'grid.draw' applied to an object of class "c('gg', 'ggplot')"
Calls: simplot -> grid.draw

EDIT: If I use print(plotNew) as suggested by @baptiste, then I get the following error

Error in if (empty(data)) { : missing value where TRUE/FALSE needed 
Calls: simplot ... facet_map_layout -> facet_map_layout.grid -> locate_grid.

I tried to figure out what is going on here, but I could not find much relevant information.

NOTES:

  1. I'm not sure why I'm getting the staircase effect for the empirical CDF. I'm sure there is an obvious explanation. Please enlighten me if you know.

  2. I'm willing to consider alternatives to this code and even ggplot2 for producing this graph, if anyone can suggest alternatives, e.g. matplotlib, which I have never seriously experimented with.

  3. Adding

    print(ggplot_gtable(ggplot_build(stat2)))
    

    to minimal2.R gives me

    TableGrob (7 x 7) "layout": 12 grobs
        z     cells       name                                 grob
    1   0 (1-7,1-7) background       rect[plot.background.rect.186]
    2   1 (3-3,4-4)  strip-top absoluteGrob[strip.absoluteGrob.135]
    3   2 (3-3,6-6)  strip-top absoluteGrob[strip.absoluteGrob.141]
    4   5 (4-4,3-3)     axis-l  absoluteGrob[GRID.absoluteGrob.129]
    5   3 (4-4,4-4)      panel                gTree[GRID.gTree.155]
    6   4 (4-4,6-6)      panel                gTree[GRID.gTree.169]
    7   6 (5-5,4-4)     axis-b  absoluteGrob[GRID.absoluteGrob.117]
    8   7 (5-5,6-6)     axis-b  absoluteGrob[GRID.absoluteGrob.123]
    9   8 (6-6,4-6)       xlab          text[axis.title.x.text.171]
    10  9 (4-4,2-2)       ylab          text[axis.title.y.text.173]
    11 10 (4-4,4-6)  guide-box                    gtable[guide-box]
    12 11 (2-2,4-6)      title            text[plot.title.text.184]
    

    I don't understand this breakdown. Can anyone explain? Does guide-box correspond to the legend, and how does one know this?

Here is the modified version of my code, minimal2.R.

########################
minimal2.R
########################

get_stat <- function()
  {
    n = 20
    q1 = qnorm(seq(3, 17)/20, 14, 5)
    q2 = qnorm(seq(1, 19)/20, 65, 10)
    Stat = data.frame(value = c(q1, q2),
      pvalue = c(dnorm(q1, 14, 5)/max(dnorm(q1, 14, 5)), d = dnorm(q2, 65, 10)/max(dnorm(q2, 65, 10))),
      variable = c(rep('true', length(q1)), rep('data', length(q2))))
    return(Stat)
  }

stat_all<- function()
{
  library(ggplot2)
  library(gridExtra)
  library(gtable)
  stathuman = get_stat()
  stathuman$dataset = "human"
  statmouse = get_stat()
  statmouse$dataset = "mouse"
  stat = merge(stathuman, statmouse, all=TRUE)
  return(stat)
}

simplot <- function()
  {
    Stat = stat_all()
    Pvalue = subset(Stat, variable=="true")
    pdf(file = "CDF.pdf", width = 5.5, height = 2.7)

    ## only include data type legend
    stat1 = ggplot() + stat_ecdf(data=Stat, n=1000, aes(x=value, colour = variable)) +
      theme(legend.key = element_blank(), legend.background = element_blank(), legend.position=c(.9, .25), legend.title = element_text(face = "bold")) +
        scale_x_continuous("Negative log likelihood") +
          scale_y_continuous("Proportion $<$ x") +
            facet_grid(~ dataset, scales='free') +
              scale_colour_manual(values = c("blue", "red"), name="Data type", labels=c("Gene segments", "Model"), guide=guide_legend(override.aes = list(size = 2))) +
                geom_area(data=Pvalue, aes(x=value, y=pvalue, fill=variable), position="identity", alpha=0.5) +
                  scale_fill_manual(values = c("gray"), name="Pvalue", labels=c(""), guide=FALSE)

    ## Extract data type legend
    dataleg <- gtable_filter(ggplot_gtable(ggplot_build(stat1)), "guide-box")

    ## only include pvalue legend
    stat2 = ggplot() + stat_ecdf(data=Stat, n=1000, aes(x=value, colour = variable)) +
      theme(legend.key = element_blank(), legend.background = element_blank(), legend.position=c(.9, .25), legend.title = element_text(face = "bold")) +
        scale_x_continuous("Negative log likelihood") +
          scale_y_continuous("Proportion $<$ x") +
            facet_grid(~ dataset, scales='free') +
              scale_colour_manual(values = c("blue", "red"), name="Data type", labels=c("Gene segments", "Model"), guide=FALSE) +
                geom_area(data=Pvalue, aes(x=value, y=pvalue, fill=variable), position="identity", alpha=0.5) +
                  scale_fill_manual(values = c("gray"), name="Pvalue", labels=c(""))

    ## Extract pvalue legend
    pvalleg <- gtable_filter(ggplot_gtable(ggplot_build(stat2)), "guide-box")

    ## no legends
    stat = ggplot() + stat_ecdf(data=Stat, n=1000, aes(x=value, colour = variable)) +
      theme(legend.key = element_blank(), legend.background = element_blank(), legend.position=c(.9, .25), legend.title = element_text(face = "bold")) +
        scale_x_continuous("Negative log likelihood") +
          scale_y_continuous("Proportion $<$ x") +
            facet_grid(~ dataset, scales='free') +
              scale_colour_manual(values = c("blue", "red"), name="Data type", labels=c("Gene segments", "Model"), guide=FALSE) +
                geom_area(data=Pvalue, aes(x=value, y=pvalue, fill=variable), position="identity", alpha=0.5) +
                  scale_fill_manual(values = c("gray"), name="Pvalue", labels=c(""), guide=FALSE)

    ## Add data type legend: version 1 (data type legend should be on top)
    ## plotNew <- arrangeGrob(dataleg, stat, heights = unit.c(dataleg$height, unit(1, "npc") - dataleg$height), ncol = 1)

    ## Add data type legend: version 2 (data type legend should be somewhere in the interior)
    ## plotNew <- stat + annotation_custom(grob = dataleg, xmin = 7, xmax = 10, ymin = 0, ymax = 4)

    grid.newpage()
    grid.draw(plotNew)
    dev.off()
  }

simplot()

解决方案

It can be done with grid.arrange and arrangeGrob, but it's a pain to adjust the heights and widths correctly.

grid.arrange(arrangeGrob(dataleg, pvalleg, nrow=1, ncol=2, widths=c(unit(1, "npc"), unit(5, "cm"))), stat, nrow=2, heights=c(unit(.2, "npc"), unit(.8, "npc")))

I usually prefer to make a new plot with an appropriate legend and use this new legend:

 h <- ggplot(data.frame(a=rnorm(10), b=rnorm(10), c=factor(rbinom(10, 1,.5), labels=c("Gene segments", "Model")), d=factor("")), 
        aes(x=a, y=b)) +
   geom_line(aes(color=c), size=1.3) + geom_polygon(aes(fill=d)) +
   scale_color_manual(values=c("blue", "red"), name="Data type") + 
   scale_fill_manual(values="gray", name="P-value") 
 g_legend<-function(a.gplot){
   tmp <- ggplot_gtable(ggplot_build(a.gplot))
   leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
   legend <- tmp$grobs[[leg]]
   return(legend)
 }
 legend <- g_legend(h)

 grid.arrange(stat, legend, nrow=1, ncol=2, widths=c(unit(.8, "npc"), unit(.2, "npc")))
 grid.arrange(legend, stat, nrow=2, ncol=1, heights=c(unit(.2, "npc"), unit(.8, "npc")))

这篇关于将两个图例独立定位在ggplot2图中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆