可以强制非出现元素显示在ggplot图例中吗?

时间:2019-10-21 18:16:12

标签: r ggplot2 legend heatmap

我正在绘制整个研究区域中多达三种可选物种丰度的叶绿素。此玩具代码的行为符合预期,并且几乎满足我的要求:

library(dplyr)
library(ggplot2)
square <- expand.grid(X=0:10, Y=0:10)
sq2 <- square[rep(row.names(square), 2),] %>%
  arrange(X,Y) %>%
  mutate(SPEC = rep(c('red','blue'),len=n())) %>%
  mutate(POP = ifelse(SPEC %in% 'red', X, Y)) %>%
  group_by(X,Y) %>% 
  mutate(CLR = rgb(X/10,0,Y/10)) %>% ungroup()

ggplot(sq2, aes(x=X, y=Y, fill=CLR)) + geom_tile() +
  scale_fill_identity("Species", guide="legend",
    labels=c('red','blue'), breaks=c('#FF0000','#0000FF'))

产生这个:

X=red; Y=blue; plotted as gradient tiling

修改后的版本会正确绘制真实地图,并适当地混合RGB以显示每个地图单位的物种比例。但是考虑到混合,实际数据不一定包含breaks中列出的特定值,在这种情况下,该物种的图例中不会出现任何条目。如果您将示例的最后一行更改为

labels=c('red','blue','green'), breaks=c('#FF0000','#0000FF','#00FF00'))

您将获得与所示相同的图例,仅显示“红色”和“蓝色”,因为其中没有绿色。可以搜索每个max(Species)的数据并将其分配给图例,但是对于仅以低比例出现的物种而言,这并不是很好的图例关键字。对于图例来说,需要的是显示存在实体的 idea ,而不是它们经证实的存在-即使只检测到一种物种,图例中也要显示三种颜色。

我认为scale_fill_manual()override.aes的论点可能对我有帮助,但我无法进行任何组合。

编辑:
第四集-新的死角

(感谢@ r2evans修复我遗漏的软件包。) 我以为我可以通过在处理管道中将另外的列突变为spCLR来表示图例,以表示对每个条目的种类进行编码的颜色(例如,“#FF0000”)(冗余信息,但是精细)。现在,在我的真实版本中进行绘图调用:

df %>% [everything] %>%
    ggplot(aes(x = X, y = Y, height = WIDTH, width = WIDTH, fill = CLR)) +
      geom_tile() +
      scale_fill_identity("Species", guide="legend",
        labels=spCODE, breaks=spCLR)

但这会产生错误:Error in check_breaks_labels(breaks, labels) : object 'spCLR' not found这似乎很奇怪,因为spCLR实际上在管道修改的df中,并且在提供给ggplot函数的所有值中,spCODE是原始df中唯一的一个值-因此,如果存在 [重新编辑-我看到标签和中断都不希望查看df $任何东西。无论如何。]

我认为(正确吗?)有某种方法可以使这一功能生效[?],但仍然无法使图例在其中显示“红色”,“蓝色”和“绿色”我的玩具示例(这是我最初的问题的实质所在),因为其中仍然没有实际的绿色数据。因此,重申一下,有没有办法强迫ggplot2图例显示您要谈论的内容,而不仅仅是显示数据中存在的内容?

2 个答案:

答案 0 :(得分:1)

我从热图用例假设,您在图表中不需要其他颜色映射。在这种情况下,可能的解决方法是不使用填充比例,并使用颜色美学映射创建不可见的geom图层,以生成所需的图例:

ggplot(sq2, aes(x=X, y=Y)) +
  geom_tile(aes(fill = CLR)) + # move fill mapping here so new point layer doesn't inherit it
  scale_fill_identity() + # scale_*_identity has guide set to FALSE by default

  # add invisible layer with colour (not fill) mapping, within x/y coordinates within
  # same range as geom_tile layer above
  geom_point(data = . %>% 
               slice(1:3) %>% 
               # optional: list colours in the desired label order
               mutate(col = forcats::fct_inorder(c("red", "blue", "green"))),
             aes(colour = col), 
             alpha = 0) +

  # add colour scale with alpha set to 1 (overriding alpha = 0 above),
  # also make the shape square & larger to mimic the default legend keys
  # associated with fill scale
  scale_color_manual(name = "Species",
                     values = c("red" = '#FF0000', "blue" = '#0000FF', "green" = '#00FF00'),
                     guide = guide_legend(override.aes = list(alpha = 1, shape = 15, size = 5)))

plot

答案 1 :(得分:0)

我后来发现我的问题与this几乎是重复的。那里接受的答案(来自@joran)对此不起作用,但是第二个答案(来自@Axeman)起作用。所以我要走的路是最后一行应该是

labels=c('red','blue','green'), limits=c('#FF0000','#0000FF','#00FF00'))

调用limits()而不是breaks(),现在我的示例和实际版本可以按需工作。

我不得不说,我花了很多时间在ggplot2 reference中进行挖掘,而从未怀疑过limit()是breaks()的正确替代品-在该参考页中有明确提及而limits()没有出现。 ?limits()页面的信息不多,我找不到任何能说明两者之间区别的东西:何时而不是那样。