ggplot2 add separate legend each for two Y axes in facet plot

前端 未结 2 762
滥情空心
滥情空心 2020-12-30 13:05

I am trying to add legends next to axis titles. I followed this stackoverflow answer to get the plot.

How to add legend on two y axes?. I would like

相关标签:
2条回答
  • 2020-12-30 13:43

    This source has an simple and easy answer. It describes the logic used by ggplot to create a legend based on assigned aes mapping, then provides a step by step solution without all this extra code. Perfect for ggplot with a second y axis, that is, plots that combine multiple geom_ or stat_summary objects into one beautifully slick graph :)

    http://zevross.com/blog/2014/08/04/beautiful-plotting-in-r-a-ggplot2-cheatsheet-3/#manually-adding-legend-items-guides-override.aes

    0 讨论(0)
  • 2020-12-30 13:58

    In order to make this a bit shorter I cut down your theme definitions.


    I make use of the fact that you can extract single grobs from your ggplot elements. In this case we extract 3 legends.

    For the desired result we need to create 4 plots:

    1. Plot p: a plot without legends
    2. Plot l1: a plot for the green legend
    3. Plot l2: a plot for the blue legend
    4. Plot l3: a plot for the red legend

    We make use of the function get_legend() which is part of the package cowplot. It lets you extract the legend of a plot.

    After we extracted both legends for the left side we use arrangeGrob to combine them and name that combined legend llegend. After we extracted the red legend, we us grid.arrange to plot all three objects (llegend, p and rlegend).

    Concerning the orientation of the legend keys you should notice that we print the legends on top of the corresponding plots. That way we can use editGrob to rotate the (combined) legends after extracting them and the legend keys have the correct orientation.

    This is all the code:

    library(ggplot2)
    library(gridExtra)
    library(grid)
    library(cowplot)
    
    # actual plot without legends
    p <- ggplot(mapping = aes(x = plate_num, y = value, group = variable)) +
      geom_line(data = subset(df1, variable %in% c('Before Treatment', 'After Treatment')), aes(color = variable), size = 1, show.legend = F) +
      geom_point(data = subset(df1, variable %in% c('Before Treatment', 'After Treatment')), aes(color = variable), size = 2, show.legend = F) +
    
      geom_line(data = subset(df1, variable %in% c('norm_ratio')), aes(color = 'Test'), col = 'red', size = 1) +
      geom_point(data = subset(df1, variable %in% c('norm_ratio')), aes(color = 'Test'), col = 'red', size = 2) +
      facet_wrap(~ grp) +
      scale_y_continuous(sec.axis = sec_axis(trans = ~ . * (max2 / max1),
                                             name = 'Ratio of Main Effect of Before and After Treatment\n')) +
      scale_color_manual(values = c('green', 'blue'), guide = 'legend') +
      theme_bw() + 
      theme(axis.text.x = element_text(size=11, face="bold", angle = 0, vjust = 1), 
            axis.title.x = element_text(size=11, face="bold"),
            axis.text.y = element_text(size=11, face="bold", color = 'black'),
            axis.text.y.right = element_text(size=11, face="bold", color = 'red'),
            axis.title.y.right = element_text(size=11, face="bold", color = 'red', margin=margin(0,0,0,0)),
            axis.title.y = element_text(size=11, face="bold", margin=margin(0,-30,0,0)),
            panel.grid.minor = element_blank(),
            strip.text.x = element_text(size=15, face="bold", color = "black", angle = 0),
            plot.margin = unit(c(1,1,1,1), "cm")) +
      ylab('Main Effect of TDP43\n\n\n') + 
      xlab('\nPlate Number')
    
    # Create legend on the left 
    l1 <- ggplot(mapping = aes(x = plate_num, y = value, group = variable)) +
      geom_line(data = subset(df1, variable %in% c('Before Treatment')), aes(color = variable), size = 1, show.legend = TRUE) +
      geom_point(data = subset(df1, variable %in% c('Before Treatment')), aes(color = variable), size = 2, show.legend = TRUE) +
      scale_color_manual(values = 'green', guide = 'legend') +
      theme(legend.direction = 'horizontal', 
            legend.text = element_text(angle = 0, colour = c('green', 'blue')),
            legend.position = 'top',
            legend.title = element_blank(),
            legend.margin = margin(0, 0, 0, 0, 'cm'),
            legend.box.margin = unit(c(0, 0 , -2.5 ,0), 'cm'))
    
    l2 <- ggplot(mapping = aes(x = plate_num, y = value, group = variable)) +
      geom_line(data = subset(df1, variable %in% c('After Treatment')), aes(color = variable), size = 1, show.legend = TRUE) +
      geom_point(data = subset(df1, variable %in% c('After Treatment')), aes(color = variable), size = 2, show.legend = TRUE) +
      scale_color_manual(values = 'blue', guide = 'legend') +
      theme(legend.direction = 'horizontal', 
            legend.text = element_text(angle = 0, colour = c('blue')),
            legend.position = 'top',
            legend.title = element_blank(),
            legend.margin = margin(0, 0, 0, 0, 'cm'),
            legend.box.margin = unit(c(0, 0 , -2.5 ,0), 'cm'))
    
    legend1 <- get_legend(l1)
    legend2 <- get_legend(l2)
    
    # Combine green and blue legend
    llegend <- editGrob(arrangeGrob(grobs = list(legend1, legend2), 
                           nrow = 1, ncol = 2), vp = viewport(angle = 90))
    
    # Plot with legend on the right
    l3 <- ggplot(mapping = aes(x = plate_num, y = value, group = variable)) +
       geom_line(data = subset(df1, variable %in% c('norm_ratio')), aes(color = variable), size = 1) +
      geom_point(data = subset(df1, variable %in% c('norm_ratio')), aes(color = variable), size = 2) +
      scale_color_manual(values = 'red', guide = 'legend') +
      theme(legend.direction = 'horizontal', 
            legend.text = element_text(angle = 0, colour = 'red'),
            legend.position = 'top',
            legend.title = element_blank(),
            legend.margin = margin(0, 0, 0, 0, 'cm'),
            legend.box.margin = unit(c(0, 0, -3, 0), 'cm'))
    
    # extract legend
    rlegend <- editGrob(get_legend(l3), vp = viewport(angle = 270))
    
    grid.arrange(grobs = list(llegend, p, rlegend), ncol = 3, 
                 widths = unit(c(3, 16, 3), "cm"))
    

    0 讨论(0)
提交回复
热议问题