【问题标题】:Possible to force non-occurring elements to show in ggplot legend?可以强制在ggplot图例中显示未发生的元素吗?
【发布时间】:2019-10-21 18:16:12
【问题描述】:

我正在绘制一种叶绿素,该叶绿素在一个研究区域中最多包含三种可选择的物种丰度。这个玩具代码的行为符合预期,几乎可以满足我的要求:

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'))

制作这个:

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

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

您会得到与所示相同的图例,仅显示“红色”和“蓝色”,因为其中没有绿色。搜索每个 max(Species) 的数据并将其分配给图例是可能的,但不会为仅以低比例出现的物种提供好的图例键。图例需要显示当前实体的idea,而不是它们已证实的存在——即使只检测到一个物种,图例中也有三种颜色。

我认为 scale_fill_manual() 或 override.aes 参数可能对我有所帮助,但我无法使任何组合起作用。

编辑:
第四集——新的死胡同

(感谢@r2evans 修复了我遗漏的软件包。) 我想我可以通过在处理管道中的 df 中改变一个名为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$anything。无论如何。]

我假设 (对吗?) 有一些方法可以使这个工作 [?],但它仍然不会使图例显示“红色”、“蓝色”和“绿色”我的玩具示例——这正是我最初的问题所在——因为其中仍然没有实际的绿色数据。所以重申一下,是否有任何方法可以强制 ggplot2 图例显示您想要谈论的内容,而不仅仅是数据中存在的内容?

【问题讨论】:

  • 一种解决方案的相关代码:lenkiefer.com/2017/04/24/bivariate-map
  • @JonSpring 谢谢你;我喜欢他在那里所做的事情,但这对我来说并不是真的。为传奇做一个 tri 变量(三角形?cuboid?)微型图对于生产工作来说是一个有吸引力的疯狂想法,但对于目测来说太过分了......老实说,一个三变量热图无论如何,您不应该要求人们多看一些东西。这些图真的只是为了我的预分析——所以如果他们有一个让我想起我在看什么的图例,那会很有帮助。

标签: r ggplot2 legend heatmap


【解决方案1】:

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

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

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

我不得不说我花了很多时间在 ggplot2 reference 中进行挖掘,但从未怀疑 limits() 是 break() 的正确替代方法——在该参考页面中明确提到了这一点,而限制() 没有出现。 ?limits() 页面信息量不大,我找不到任何可以说明两者之间区别的东西:当这个而不是那个。

【讨论】:

    【解决方案2】:

    我从热图用例中假设您不需要在图表中进行颜色映射。在这种情况下,一种可能的解决方法是单独保留填充比例,并创建一个具有颜色美学映射的不可见几何图层来生成所需的图例:

    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)))
    

    【讨论】:

    • 嗯,这并没有完全回答这个问题——我希望会有一个更直接的解决方案——但我很佩服它的独创性.除此之外,也是你回答了我最后一个问题!惊奇。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多