ggplot2:将图例分成两列,每列都有自己的标题 [英] ggplot2: Divide Legend into Two Columns, Each with Its Own Title

查看:93
本文介绍了ggplot2:将图例分成两列,每列都有自己的标题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这些因素

require(ggplot2)
names(table(diamonds$cut))
# [1] "Fair"      "Good"      "Very Good" "Premium"   "Ideal" 

我想在图例中直观地分为两组(也指示组名):

which I want to visually divide into two groups in the legend (indicating also the group name):

"First group" -> "Fair", "Good"

"Second group" -> "Very Good", "Premium", "Ideal"

从这个情节开始

ggplot(diamonds, aes(color, fill=cut)) + geom_bar() + 
  guides(fill=guide_legend(ncol=2)) +
  theme(legend.position="bottom")

我想得到

(注意非常好"在第二列/组中滑落)

(note that "Very Good" slipped in the second column/group)

推荐答案

您可以通过添加虚拟因子级别并将其颜色设置为图例中的白色,将非常好"类别移动到图例的第二列,因此它不能被看到.在下面的代码中,我们在好"和非常好"之间添加了一个空白因子级别,所以现在我们有六个级别.然后,我们使用scale_fill_manual 将此空白级别的颜色设置为白色".drop=FALSE 强制 ggplot 在图例中保持空白级别.可能有一种更优雅的方法来控制 ggplot 放置图例值的位置,但至少这可以完成工作.

You can shift the "Very Good" category to the second column of the legend by adding a dummy factor level and setting its colour to white in the legend, so that it can't be seen. In the code below, we add a blank factor level between "Good" and "Very Good", so now we have six levels. Then, we use scale_fill_manual to set the color of this blank level to "white". drop=FALSE forces ggplot to keep the blank level in the legend. There might be a more elegant way to control where ggplot places the legend values, but at least this will get the job done.

diamonds$cut = factor(diamonds$cut, levels=c("Fair","Good"," ","Very Good",
                                             "Premium","Ideal"))

ggplot(diamonds, aes(color, fill=cut)) + geom_bar() + 
  scale_fill_manual(values=c(hcl(seq(15,325,length.out=5), 100, 65)[1:2], 
                             "white",
                             hcl(seq(15,325,length.out=5), 100, 65)[3:5]),
                    drop=FALSE) +
  guides(fill=guide_legend(ncol=2)) +
  theme(legend.position="bottom")

更新:我希望有更好的方法来为图例中的每个组添加标题,但我现在能想到的唯一选择是诉诸 grob,这总是给我很头疼.下面的代码改编自对this SO question的回答.它添加了两个文本 grob,每个标签一个,但标签必须手动定位,这是一个巨大的痛苦.绘图的代码也必须修改为图例创造更多空间.此外,即使我关闭了所有 grob 的裁剪,标签仍然被图例 grob 裁剪.您可以将标签放置在剪切区域之外,但它们离图例太远了.我希望真正知道如何使用 grobs 的人可以解决这个问题,并且更普遍地改进下面的代码(@baptiste,你在那里吗?).

UPDATE: I'm hoping there's a better way to add titles to each group in the legend, but the only option I can come up with for now is to resort to grobs, which always gives me a headache. The code below is adapted from the answer to this SO question. It adds two text grobs, one for each label, but the labels have to be positioned by hand, which is a huge pain. The code for the plot also has to be modified to create more room for the legend. In addition, even though I've turned off clipping for all grobs, the labels are still clipped by the legend grob. You can position the labels outside of the clipped area, but then they're too far from the legend. I'm hoping someone who really knows how to work with grobs can fix this and more generally improve upon the code below (@baptiste, are you out there?).

library(gtable)

p = ggplot(diamonds, aes(color, fill=cut)) + geom_bar() + 
  scale_fill_manual(values=c(hcl(seq(15,325,length.out=5), 100, 65)[1:2], 
                             "white",
                             hcl(seq(15,325,length.out=5), 100, 65)[3:5]),
                    drop=FALSE) +
  guides(fill=guide_legend(ncol=2)) +
  theme(legend.position=c(0.5,-0.26),  
        plot.margin=unit(c(1,1,7,1),"lines")) +
  labs(fill="") 

# Add two text grobs
p = p + annotation_custom(
    grob = textGrob(label = "First
Group", 
                    hjust = 0.5, gp = gpar(cex = 0.7)),
    ymin = -2200, ymax = -2200, xmin = 3.45, xmax = 3.45) +
  annotation_custom(
    grob = textGrob(label = "Second
Group",
                    hjust = 0.5, gp = gpar(cex = 0.7)),
    ymin = -2200, ymax = -2200, xmin = 4.2, xmax = 4.2)

# Override clipping
gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip <- "off"
grid.draw(gt)

结果如下:

这篇关于ggplot2:将图例分成两列,每列都有自己的标题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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