在ggplot中组合颜色和线型图例

时间:2019-07-01 19:04:08

标签: r ggplot2

在用ggplot2生成的绘图中,我很难将颜色和线型参考线组合成单个图例。线型显示时,所有线型都以相同的方式进行键控,或者根本不显示。

我的绘图既包括显示大部分观测值的功能区,也包括显示最小值,中位数,最大值,有时还显示一年中观测值的线。

使用内置CO2数据集的示例代码:

library(tidyverse)

myExample <- CO2 %>%  
      group_by(conc) %>%
      summarise(d.min = min(uptake, na.rm= TRUE),
                d.ten = quantile(uptake,probs = .1, na.rm = TRUE),
                d.median = median(uptake, na.rm = TRUE),
                d.ninty = quantile(uptake, probs = .9, na.rm= TRUE),
                d.max = max(uptake, na.rm = TRUE))
myExample <- cbind(myExample, "Qn1"= filter(CO2, Plant == "Qn1")[,5])

plot_plant <- TRUE  # Switch to plot single observation series

myExample %>%
      ggplot(aes(x=conc))+
      geom_ribbon(aes(ymin=d.ten, ymax= d.ninty, fill = "80% of observations"), alpha = .2)+
      geom_line(aes(y=d.min, colour = "c"), linetype = 3, size = .5)+
      geom_line(aes(y=d.median, colour = "e"),linetype = 2, size = .5)+
      geom_line(aes(y=d.max, colour = "a"),linetype = 3, size = .5)+
      {if(plot_plant)geom_line(aes(y=Qn1, color = "f"), linetype = 1,size =.5)}+
      scale_fill_manual("Statistic", values = "blue")+
      scale_color_brewer(palette = "Dark2",name = "",
                         labels = c(
                               a= "Maximum",
                               e= "Median",
                               c= "Minimum",
                               f = current_year
                         ), breaks = c("a","e","c","f"))+
      scale_linetype_manual(name = "")+
      guides(fill= guide_legend(order = 1), color = guide_legend(order = 2), linetype = guide_legend(order = 2))

plot_plant设置为TRUE时,代码将绘制单个观察序列,但图例中根本不会显示线型: enter image description here

将plot_plant设置为FALSE时,线型显示在图例中,但我看不到虚线和虚线图例条目之间的区别: enter image description here

该图按预期工作,但是我希望线型区别出现在图例中。在视觉上,当我绘制单个观察序列时,这尤为重要,因为实线与虚线或点划线之间的区别更强。

在寻找答案时,我看到了一些建议,可以将不同的统计信息(最小值,中位数,最大值和单个序列)组合为一个变量,然后让ggplot确定线型(例如[this post] ggplot2 manually specifying color & linetype - duplicate legend )或创建一个描述线型的散列[例如] How to rename a (combined) legend in ggplot2?,但这些方法似乎都无法与功能区图结合使用。

我尝试将数据格式化为长格式,这对于ggplot通常效果很好。如果我将所有统计信息都绘制为线几何图形,则此方法有效,但是无法使功能区如我所愿地工作,并且覆盖单个观察序列似乎需要将其存储在不同的数据表中。

1 个答案:

答案 0 :(得分:0)

如您所述,ggplot喜欢长格式数据。所以我建议坚持下去。

我在这里生成一些组合数据:

library(tibble)
library(dplyr)
library(ggplot2)
library(tidyr)

set.seed(42)

tibble(x = rep(1:10, each = 10), 
       y = unlist(lapply(1:10, function(x) rnorm(10, x)))) -> tbl_long

如下所示:

# A tibble: 100 x 2
       x     y
   <int> <dbl>
 1     1 2.37 
 2     1 0.435
 3     1 1.36 
 4     1 1.63 
 5     1 1.40 
 6     1 0.894
 7     1 2.51 
 8     1 0.905
 9     1 3.02 
10     1 0.937
# ... with 90 more rows

然后我group_by(x)并计算每个组中y的感兴趣分位数:

tbl_long %>% 
  group_by(x) %>% 
  mutate(q_0.0 = quantile(y, probs = 0.0), 
         q_0.1 = quantile(y, probs = 0.1),
         q_0.5 = quantile(y, probs = 0.5), 
         q_0.9 = quantile(y, probs = 0.9), 
         q_1.0 = quantile(y, probs = 1.0)) -> tbl_long_and_wide

看起来像:

# A tibble: 100 x 7
# Groups:   x [10]
       x     y q_0.0 q_0.1 q_0.5 q_0.9 q_1.0
   <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1     1 2.37  0.435 0.848  1.38  2.56  3.02
 2     1 0.435 0.435 0.848  1.38  2.56  3.02
 3     1 1.36  0.435 0.848  1.38  2.56  3.02
 4     1 1.63  0.435 0.848  1.38  2.56  3.02
 5     1 1.40  0.435 0.848  1.38  2.56  3.02
 6     1 0.894 0.435 0.848  1.38  2.56  3.02
 7     1 2.51  0.435 0.848  1.38  2.56  3.02
 8     1 0.905 0.435 0.848  1.38  2.56  3.02
 9     1 3.02  0.435 0.848  1.38  2.56  3.02
10     1 0.937 0.435 0.848  1.38  2.56  3.02
# ... with 90 more rows

然后,我将除x,y以及10%和90%变量之外的所有列汇总为两个变量:键和值。新的键变量采用每个值都来自的旧变量的名称。其他变量只是根据需要复制下来。

tbl_long_and_wide %>% 
  gather(key, value, -x, -y, -q_0.1, -q_0.9) -> tbl_super_long

看起来像:

# A tibble: 300 x 6
# Groups:   x [10]
       x     y q_0.1 q_0.9 key   value
   <int> <dbl> <dbl> <dbl> <chr> <dbl>
 1     1 2.37  0.848  2.56 q_0.0 0.435
 2     1 0.435 0.848  2.56 q_0.0 0.435
 3     1 1.36  0.848  2.56 q_0.0 0.435
 4     1 1.63  0.848  2.56 q_0.0 0.435
 5     1 1.40  0.848  2.56 q_0.0 0.435
 6     1 0.894 0.848  2.56 q_0.0 0.435
 7     1 2.51  0.848  2.56 q_0.0 0.435
 8     1 0.905 0.848  2.56 q_0.0 0.435
 9     1 3.02  0.848  2.56 q_0.0 0.435
10     1 0.937 0.848  2.56 q_0.0 0.435
# ... with 290 more rows

此格式将允许您像您想的那样使用geom_ribbon()geom_smooth(),因为行的变量包含在value中并按key分组,而要映射到yminymax的变量与value是分开的,并且在每个x组中都相同。

tbl_super_long %>% 
  ggplot() + 
  geom_ribbon(aes(x = x, 
                  ymin = q_0.1, 
                  ymax = q_0.9, 
                  fill = "80% of observations"), 
              alpha = 0.2) + 
  geom_line(aes(x = x, 
                y = value, 
                color = key, 
                linetype = key)) + 
  scale_fill_manual(name = element_text("Statistic"), 
                    guide = guide_legend(order = 1), 
                    values = viridisLite::viridis(1)) + 
  scale_color_manual(name = element_blank(), 
                     labels = c("Minimum", "Median", "Maximum"), 
                     guide = guide_legend(reverse = TRUE, order = 2), 
                     values = viridisLite::viridis(3)) + 
  scale_linetype_manual(name = element_blank(), 
                        labels = c("Minimum", "Median", "Maximum"), 
                        guide = guide_legend(reverse = TRUE, order = 2), 
                        values = c("dotted", "dashed", "solid")) + 
  labs(x = "x", y = "y")

example plot

此数据格式包含长且分组的x和y变量以及独立但重复的ymin和xmin变量,这将允许您同时使用geom_ribbon()geom_smooth()并允许linetypes以正确显示在图例中。