【问题标题】:ggplot2 assigning aesthetics falselyggplot2错误地分配美学
【发布时间】:2019-07-04 07:27:56
【问题描述】:

我正在使用 ggplot2 创建绘图,由于某种原因,该函数的行为非常奇怪。

我有一个数据框 df,我想可视化几列。

任何数据框似乎都可以正常工作。我已经生成了这个虚拟数据框。

df <- data.frame(Date = seq.Date(as.Date.character("2019-01-01"), by = 1, length.out = 10), 
                 Value = rnorm(10), 
                 Foo = rnorm(10))

所以我要做的是

  library(ggplot2)
  gg <- ggplot(df, aes(x = Date)) + geom_line(aes(y = Value, color = "Value", linetype = "Value"))
  gg <- gg + geom_line(aes(y = Foo, color = "SomeWord", linetype = "SomeWord"))
  gg <- gg + scale_color_manual(name="Legend", 
      breaks=c("Value", "SomeWord"), values=c("steelblue", "firebrick")) + 
    scale_linetype_manual(name="Legend", 
      breaks=c("Value", "SomeWord"), values=c("solid", "twodash"))
  gg

通常,ggplot2 现在会正确地将颜色 steelblue 和线型 solid 分配给列 Value,同时分配 firebricktwodashFoo 列,我将其命名为 SomeWord。但是,根据我选择的名称,ggplot 会以错误的方式分配颜色和线型。例如,使用“Test1”作为名称似乎可以正常工作,但“Einschritt”会导致 ggplot2 将我的整个规则集扔出窗口。

我试过用谷歌搜索,但没有找到任何线索说明为什么 ggplot 似乎不接受某些名称,而其他名称则很好。我还想在颜色和线型参考名称中使用连字符,我认为 可能 是个问题。

编辑:例如,我刚刚尝试在我的虚拟数据框上复制它。使用上面发布的代码,当我使用以下名称时,线型和颜色匹配错误:

  • 列“值”的“值”,列 Foo 的任何内容。
  • “值”列的“Ein-Schritt-Prognose”,Foo 列的任何内容。
  • “值”列的“SomeWord”,Foo 列的任何内容。

但是,当我切换到类似的东西时:

  • “ABD”用于列 Value,任何用于列 Foo。

那么它们就被正确匹配了。

【问题讨论】:

  • 一些有趣的阅读 :-) how to make a great r reproducible example
  • 连字符在 R 中被认为是减号。如果您在输入文件的列名中包含点,它们会自动替换为点。
  • @J.Grünenwald:我认为您仍然需要修改您的代码以使其“可运行”。即转到fun reading post 中的第 2 项 :-)
  • 不确定是否有帮助,但请阅读?scale_*_manuel 中关于values 参数的信息:一组将数据值映射到的美学值。如果这是一个命名向量,则将根据名称匹配值。 如果未命名,值将按顺序(通常按字母顺序)与刻度限制匹配。任何不匹配的数据值都将被赋予 na.value。
  • @markus 谢谢!这正是我一直在寻找的。看来我还没有完全理解 scale__manual 功能是如何工作的。我认为 values 中给出的属性是根据 breaks 参数中给出的值匹配的。然而,这似乎是完全错误的。我得查一下。再次感谢您!

标签: r ggplot2


【解决方案1】:

首先,明确一点:连字符与此无关。

问题在于breaks 参数根本没有用于定义数据到美学的比例映射。 breaks 只控制图例上显示的数据值以及顺序。没有别的了。

这是一个演示(仅简化为颜色;概念相同):

library(ggplot2)

set.seed(42)

mydf <- data.frame(
  Date = seq.Date(as.Date.character("2019-01-01"), by = 1, length.out = 10),
  Value = rnorm(10), Foo = rnorm(10)
)

p <- ggplot(mydf, aes(x = Date)) +
  geom_line(aes(y = Value, color = "Value")) +
  geom_line(aes(y = Foo, color = "SomeWord"))

p1 <- p + scale_color_manual(
  breaks = c("Value", "SomeWord"),
  values = c("steelblue", "firebrick")
)

p2 <- p + scale_color_manual(
  breaks = c("SomeWord", "Value"),
  values = c("steelblue", "firebrick")
)

egg::ggarrange(p1, p2)

如您所见,美学映射保持不变:"Value" 仍然是红色,"SomeWord" 仍然是蓝色;只有传说的顺序发生了变化。如果您想控制数据到审美的映射,您有两种选择:

首先,正如@markus 在 cmets 中提到的,您可以为values 参数给出的向量设置名称:

p + scale_color_manual(
  values = c("Value" = "steelblue", "SomeWord" = "firebrick")
)

或者(虽然不推荐),您可以依赖按limits 的顺序映射的美学:

p + scale_color_manual(
  limits = c("Value", "SomeWord"),
  values = c("steelblue", "firebrick")
)

(请注意,这里的图例顺序也发生了变化:这是因为如果没有给出,breaks 将设置为 limits。)

默认情况下,限制按字母顺序排序,这就是您看到的行为的原因:V 出现在 S 之后,这就是为什么(如果您不设置 limits"Value" 得到匹配使用第二种颜色,"SomeWord" 使用第一种颜色。

关于limitsbreaks 的区别:limits 控制映射哪些数据值。如果我们有一个未包含在limits 中的数据值,则映射美学设置为NA

p + scale_color_manual(
  limits = c("Value"),
  values = c("steelblue", "firebrick")
)
#> Warning: Removed 10 rows containing missing values (geom_path).

而如果您在breaks 中留下一个值,所有数据仍会被映射,但省略的值不会显示在图例中:

p + scale_color_manual(
  breaks = c("Value"),
  values = c("steelblue", "firebrick")
)

reprex package (v0.3.0) 于 2019-07-04 创建

【讨论】:

  • 谢谢,我会将其设置为已接受的答案,因为这解决了问题的根源。
【解决方案2】:

“Ein-Schritt-Prognose”不能用作列名。请在您的问题下方查看我的评论。在 ggplot2 中,colnames 没有被引用,因此在 colname 中使用连字符会使它看起来像 Ein - Schritt - Prognose(一个表达式)。在 R 中谨慎使用连字符。

【讨论】:

  • 谢谢。这是有道理的,但是,即使我的名字中没有使用连字符,问题仍然存在,具体取决于我选择的名字。我发现它特别令人费解,因为我没有看到什么有效和什么无效的模式,正如我在编辑中看到的那样。
【解决方案3】:

正如@HongboZhu 正确所说,问题是连字符。现在,您真正的问题是您想在图例中使用连字符。有很多方法可以更改图例标签。一种方法是在您的 scale_x_manual 函数中。

请注意,我略微缩短了您的代码,并将您的数据框的名称更改为mydfdf 是一个 baseR 函数,不推荐(尽管经常使用)作为 SO 上的示例名称。

mydf <- data.frame(Date = seq.Date(as.Date.character("2019-01-01"), by = 1, length.out = 10),Value = rnorm(10), Foo = rnorm(10))

library(ggplot2)
ggplot(mydf, aes(x = Date)) + geom_line(aes(y = Value, color = "Value", linetype = "Value")) +
  geom_line(aes(y = Foo, color = "SomeWord", linetype = "SomeWord")) +
  scale_color_manual(breaks=c("Value", "SomeWord"), values=c("steelblue", "firebrick"), label = c('value','Ein-SChritt-Prognose')) + 
  scale_linetype_manual(name="Legend", breaks=c("Value", "SomeWord"), values=c("solid", "twodash"))

reprex package (v0.2.1) 于 2019-07-04 创建

【讨论】:

  • 非常感谢。我不知道您也可以在比例函数中使用 label 参数手动编写图例。然而,这只解决了一个小问题,因为仍然存在一个问题,例如,为什么使用“Value”或“SomeWord”作为第一列的参考名称会导致 ggplot 翻转颜色和线型分配。
  • 也许过去我自己的一个问题可能对你有帮助:stackoverflow.com/questions/53703989/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
  • 2020-04-11
  • 1970-01-01
  • 1970-01-01
  • 2019-02-07
  • 1970-01-01
相关资源
最近更新 更多