如何更改 ggplot2 中的线条颜色而不使图例消失?

Gru*_*nka 4 r ggplot2

我有以下问题:

\n\n

我有这个代码:

\n\n
oly12 <- VGAMdata::oly12\nggplot(oly12, aes(y = Weight, x = Height)\n) + \ngeom_hex(\n) +\nfacet_wrap("Sex", scales = "free"\n) + \ngeom_line(aes(y = 29.99*Height^2, color = "black")\n) +\ngeom_line(aes(y = 24.99*Height^2, color = "blue")\n) +\ngeom_line(aes(y = 18.50*Height^2, color = "red")\n) +\ngeom_line(aes(y = 17.00*Height^2, color = "pink")\n) +\nscale_color_discrete(name = "BMI limits", labels = c("Pre\xe2\x88\x92obese (upper \nbound)", "Normal range (upper bound)", "Normal range (lower bound)", "Mild \nthinness (lower bound)")\n) + \ntheme(legend.position="bottom", legend.direction="vertical"\n)\n
Run Code Online (Sandbox Code Playgroud)\n\n

我希望所有的线条都是黑色的,但是当我在代码中更改它时,所有的线条都是粉红色的,图例消失了。

\n\n

我不知道如何添加图片,它不起作用,所以很抱歉,但 R 中提供了数据。

\n\n

我究竟做错了什么?

\n\n

谢谢

\n

Z.L*_*Lin 6

MrFlick 的评论已经为您提供了解决方案,因此这里尝试解释问题出在哪里。

TL;DR 解释

color = "some color"部件位于内部aes(),但scale_color_discrete()尚未准备好正确处理它。

长解释

让我们使用基本数据集进行说明,因为并不是每个人都有 VGAMdata 包:

df <- subset(airquality, Month == 5)[, c("Day", "Wind", "Temp")]

> head(df)
  Day Wind Temp
1   1  7.4   67
2   2  8.0   72
3   3 12.6   74
4   4 11.5   62
5   5 14.3   56
6   6 14.9   66

> summary(df)
      Day            Wind            Temp      
 Min.   : 1.0   Min.   : 5.70   Min.   :56.00  
 1st Qu.: 8.5   1st Qu.: 8.90   1st Qu.:60.00  
 Median :16.0   Median :11.50   Median :66.00  
 Mean   :16.0   Mean   :11.62   Mean   :65.55  
 3rd Qu.:23.5   3rd Qu.:14.05   3rd Qu.:69.00  
 Max.   :31.0   Max.   :20.10   Max.   :81.00  
Run Code Online (Sandbox Code Playgroud)

阴谋:

ggplot(df,
       aes(x = Day)) +
  geom_line(aes(y = Wind, color = "red")) +
  geom_line(aes(y = Temp, color = "blue")) +
  scale_color_discrete(name = "Variables",
                       labels = c("wind", "temperature")) +
  theme(legend.position = "bottom", 
        legend.direction = "vertical")
Run Code Online (Sandbox Code Playgroud)

重现问题

我想到了几个问题:

  1. 从数据中我们知道,Temp 值(56-81)比 Wind 值(5.7-20.1)大几个数量级。那么为什么上面的线(温度值)标记为“风”呢?
  2. 当我们指定红色/蓝色时,为什么图中显示粉色/青色?

当在内部 指定颜色时aes(),默认情况下它被解释为变量值,而不是颜色(scale_XX_identity覆盖它)。color = "xyz"如果我用/替换上面的内容color = "abc",除了图例标签之外,图表看起来将完全相同。

本质上,ggplot 理解的代码是“线条颜色在第一个中采用变量值“红色”,在第二个中采用变量值“蓝色”;按字母顺序geom_line将“红色”和“蓝色”映射到默认调色板。如果向量提供了标签,它被映射到按字母顺序排序的向量 c("blue", "red")"

所以我们有:

|Variable |Assigned.color.value |Mapped.color.value |Mapped.label |
|:--------|:--------------------|:------------------|:------------|
|Temp     |blue                 |pink               |wind         |
|Wind     |red                  |cyan               |temperature  |
Run Code Online (Sandbox Code Playgroud)

(旁注:如果有两个值,则默认调色板转换为粉青色;如果有三个值,则默认调色板转换为红绿蓝;如果有四个值,则默认调色板转换为红绿蓝紫色,等等。请参阅此问题以了解有关如何使用的更多详细信息这就会发生。)

如果这还不够令人困惑,那么如果您将两种颜色更改为相同的值,就会发生这种情况(同样,该值是什么并不重要......可以是“黑色”,“白色”,“紫色”,或任何其他字符串):

|Variable |Assigned.color.value |Mapped.color.value |Mapped.label |
|:--------|:--------------------|:------------------|:------------|
|Temp     |black                |pink               |wind         |
|Wind     |black                |pink               |wind         |
Run Code Online (Sandbox Code Playgroud)

由于只给出了一个值,因此线条呈现默认调色板中的第一种颜色,并且仅将标签向量中的第一个值映射到它。因此,你的情节线条都变成了粉红色,除了第一行传说之外的所有线条都消失了。

替代解决方案

一般来说,如果我需要使用多geom_line()行并为每行分配不同的颜色(而不是将原始数据转换为长格式),我更喜欢使用其内部的预期标签定义每行的颜色aes(),并使用手动指定相应的颜色scale_XX_manual()

ggplot(df,
       aes(x = Day)) +
  geom_line(aes(y = Wind, color = "1: wind")) +
  geom_line(aes(y = Temp, color = "2: temp")) +
  scale_color_manual(name = "Variables",
                     values = c("1: wind" = "red", "2: temp" = "blue")) +
  theme(legend.position = "bottom", 
        legend.direction = "vertical")
Run Code Online (Sandbox Code Playgroud)

这样做的好处是可以将所有可移动部分保留在一个地方(内部scale_XX_manual()),这样如果我以后需要更新颜色,我只需要查看那一行。对值使用命名向量还可以确保颜色和标签始终正确地相互映射。

在这种情况下,如果我想将所有线条颜色更改为黑色,我只需使用values = c("1: wind" = "black", "2: temp" = "black")即可。

情节2

作为参考,这是我运行原始代码时得到的结果:

阴谋

图中显示的颜色遵循 ggplot 4 个值的默认模板,而不是黑色/蓝色/红色/粉色的任意组合。

此外,初始颜色值是(按规定的顺序)c("black", "blue", "red", "pink"),但字母顺序应该是c("black", "blue", "pink", "red")。标签映射到此字母顺序,这就是为什么紫色线(根据图例的“轻度薄度”)实际上是“正常范围(下限)”的线。