• R语言
  • 如何在ggplot中只给部分geom_xxx()绘制图例

问题描述

在ggplot中,可以通过叠加多个geom_xxx()函数实现多个图层的绘制。但是默认情况下,这些图层的图例都会被绘制出来。有时出于可读性考虑,并不需要显示所有图层的图例。

案例数据

现有如下R代码:

library(tidyverse)

# freeny是一个R自带的示例数据集
rownames_to_column(freeny, 'year') %>% tibble %>% mutate(year=as.numeric(year)) %>% select(-lag.quarterly.revenue) %>% gather(indicator, value, -year) -> dataset

# 只对其中一部分的数据走势感兴趣
filter(dataset, year==1971.75) %>% .[c(4, 1), ] -> status_quo

# 绘图
ggplot(dataset, aes(year, value, color=indicator))+geom_line()+geom_text(data=status_quo, aes(year, value, label=1:2), vjust=-1)+theme(legend.position='bottom')

上述代码绘制的统计图有两个图层,底下是geom_line()绘制的折线图,上面是geom_text()追加的文字层。但是我希望在图例中,不要显示折现的图例,而只显示文字图层的图例,且1、2对应的图例文本label=status_quo$value。目前的图例体现了两个图层的所有信息,比较杂乱。

案例数据与真实需求的区别

在我的真实需求中,折线图层里有接近100根线,且每根线对应一段较长的文本(平均一两百字)。我希望读者只关注截止时刻取值最大的三条曲线,分别标注1、2、3,并在图片下方显示三条曲线对应的文本。

    复杂的图我选择拼图,不简便,但是避免陷入到格式地狱里。

    library(tidyverse)
    library(cowplot)
    
    # freeny是一个R自带的示例数据集
    rownames_to_column(freeny, 'year') %>% tibble %>% mutate(year=as.numeric(year)) %>% select(-lag.quarterly.revenue) %>% gather(indicator, value, -year) -> dataset
    
    # 只对其中一部分的数据走势感兴趣
    filter(dataset, year==1971.75) %>% .[c(4, 1), ] -> status_quo
    
    # 绘图
    
    ## 主体
    p_body = ggplot() +
      geom_line(data=dataset, aes(year, value, color=indicator)) +
      geom_text(data=status_quo, aes(year, value, label=1:2, color=color), vjust=-1) +
      theme(legend.position='none')
    
    ## 分离图例
    p_legend = ggplot() +
      geom_text(data=status_quo, aes(year, value, label=1:2, color=indicator)) +
      theme(legend.position='bottom')
    
    ## 拼图
    plot_grid(
      plotlist = list(p_body, get_plot_component(p_legend, "guide-box", return_all = T)[[3]]), # 因为text不是图形,所以不能直接用`get_legend`
      nrow = 2, rel_heights = c(9, 1)
    )
      ggplot(dataset, aes(year, value, color = indicator)) +
          geom_line(show.legend = FALSE) +
          geom_text(
              data=status_quo, 
              aes(year, value, label=value), 
              vjust = 0) + 
          theme(legend.position='bottom') + 
          scale_color_manual(
              values = c(income.level = "red", 
                         market.potential = "green", 
                         price.index = "blue", 
                         y = "purple"), 
              breaks = c("market.potential", "y"), 
              labels = c("my_market_label", "my_y_label")
          )

      geom_line()里用show.legend = FALSE关闭本层的图例显示,那么显示出来的图例里就不会有折线的元素。

      剩下的就是用scale_color_manual()手动定制颜色图例,我只是给出其中的一种写法:

      • values 给出完整的颜色对照关系

      • breaks给出你想展示的几个层级

      • labels给出你想把对应的层级在图例中展示成什么文本

      4 天 后

      Vinnish 感谢回复!我喜欢你的分别绘制再拼在一起的思路。确实这样更简单可控。不过可惜ggplot2包居然没有原生支持这一特性。

      还有楼上几位群友的热心回复,先感谢一下 😃 我好好阅读一下链接指向的教材,再来回复。