Search code examples
rggplot2legend-propertiespatchwork

plot_annotation(tag_levels = 'a') + plot_layout(guides = "collect") & theme(legend.position = "top") delivered duplicated legend


I used dummy data from this question Bar plot and scatterplot in GGPLOT facets

I need one legend only, at the top of the patched graph, so I have theme(legend.position = "top") for panel a and theme(legend.position = "none") for panel b.

library(ggplot2)
library(ggpubr)
library(ggpmisc)
library(reshape2)

  ## GENERATE CONTINUOUS VARIABLES FOR EACH TREATMENT (A - D)

        A <- rnorm(10, 1, 1)
        B <- rnorm(10, 3, 1)
        C <- rnorm(10, 5, 1)
        D <- rnorm(10, 7, 1)

        ## GENERATE RESPONSE TO TREATMENTS

        res_A<-rnorm(10, 28, 3)
        res_B<-rnorm(10, 22, 3)
        res_C<-rnorm(10, 18, 3)
        res_D<-rnorm(10, 12, 3)

        ## ESTABLISH DATA FRAMES FOR TREATMENTS AND RESPONSE

        treatments<-data.frame(A, B, C, D)
        response<-data.frame(res_A, res_B, res_C, res_D)

        ## CONVERT EACH DATA FRAME TO LONG FORM



        treatments <-treatments %>% gather(Treatment, cont_x, A:D)
        response <-response %>% gather(Treatment, Response, res_A:res_D)

        ## CREATE FINAL DATA FRAME WITH REQUIRED DATA

        data<-data.frame(treatments$Treatment, treatments$cont_x, response$Response)
        colnames(data) <- c("Treatment", "X", "Response")
        


a <- data %>% 
       group_by(Treatment) %>% 
       summarise(Response=mean(Response)) %>% 
       mutate(se = sd(Response)/sqrt(length(Response))) %>% ungroup %>%
     ggplot(aes(x=Treatment,y = Response, fill = as.factor(Treatment))) +
      geom_bar(position = "stack", stat= "identity")  +
       geom_text(aes(label=tolower(Treatment)), position=position_stack(vjust = 1.3)) +
       geom_errorbar(aes(ymin = Response - se, ymax = Response + se), width = 0.1) +
       labs(fill="TREATMENT EFFECTS") + theme(legend.position = "top")

b <- data %>% 
     ggplot(aes(x=X,y=Response)) + 
      geom_smooth(method="lm") + 
      geom_point(aes(color = as.factor(Treatment)), size=3) +
      scale_fill_manual(values = cols) +
      labs(color = "TREATMENT EFFECTS") +
      xlab("Continuous Variable") +
      stat_poly_eq(formula = y ~ x, label.x = 0.9, label.y = 0.95, aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")), parse = TRUE)  +
   theme(legend.position = "none")

In the following code, theme(legend.position = "top") disregarded plot_layout(guides = "collect")

a + b  +
  plot_annotation(tag_levels = 'a') + plot_layout(guides = "collect")  &  theme(legend.position = "top")   

enter image description here

I can have one legend only by using the default.

a + b  +
  plot_annotation(tag_levels = 'a') + plot_layout(guides = "collect") 

enter image description here

Thanks for your time.


Solution

  • The issue is that all theme adjustments done using e.g. & theme(...) will be applied individually to each plot of the patch and hence will override any adjustments you have done before, i.e. using & theme(legend.position = "top") you override the theme(legend.position = "none") for your b plot and both plots will end up with a legend on top which will not get merged as they differ.

    However, the patch has an overall theme which could be set via the theme argument of plot_annotation to achieve your desired result:

    library(patchwork)
    
    a + b +
      plot_annotation(
        tag_levels = "a",
        theme = theme_grey() + theme(legend.position = "top")
      ) +
      plot_layout(guides = "collect")
    

    enter image description here