2

I'm trying to make a facetted plot with two panels - left and right. The variable on the x-axis is continuous, and the variable on the y-axis is discrete, with relatively long labels. I would like to put the y-axis of the right hand side plot on the right side (and keep the y-axis of the left hand side left), so that the two panels are not split apart by the y-axis labels of the right hand side plot.

I've tried a couple of different workaround (e.g. cowplot) but I can't get anything that I would be satisfied with, because I also need a legend in my plot.

This is what I want to do: enter image description here

Here's a reprex:

library(tidyverse)

region <- sample(words, 20)
panel <- rep(c(0, 1), each = 10)
value <- rnorm(20, 0, 1)

df <- tibble(region, panel, value)

ggplot(df, aes(value, region)) +
  geom_point() +
  facet_wrap(~ panel, scales = 'free_y')

Thank you!

Adam B.
  • 788
  • 5
  • 14
  • I suspect you'll need to use `cowplot` or `grid` graphics to combine two separate plots (not faceted), where you explicitly control the y-axis location on one of them. – r2evans Jun 15 '20 at 03:15

1 Answers1

2

This solution lacks flexibility for cases with more than 2 plots but it does the job for your case. The idea is to generate the plots separately and combine the plots into a list. The ggplot function call contains an if else function for the scale_y_discrete layer which puts the y-axis either on the left-hand or right-hand side depending on the value of panel. We use gridExtra to combine the plots.

library(tidyverse)
library(gridExtra)

region <- sample(words, 20)
panel <- rep(c(0, 1), each = 10)
value <- rnorm(20, 0, 1)

df <- tibble(region, panel, value)

panel <- sort(unique(df$panel))
plot_list <- lapply(panel, function(x) {
  ggplot(data = df %>% filter(panel == x), 
         aes(value, region)) +
         geom_point() +
         if (x == 0) scale_y_discrete(position = "left") else scale_y_discrete(position = "right")
})

do.call("grid.arrange", c(plot_list, ncol = 2))

You can leave the facet_wrap(~ panel, scales = 'free_y') layer and you will retain the strips at the top in the plot.

enter image description here

UPDATE

Code updated to remove x-axis from the individual plots and add text at the bottom location of the grid plot; added a second if else to suppress the y-axis title in the right hand plot. Note that the if else functions need to be enclosed by curly brackets (did not know that either :-) but it makes sense):

plot_list <- lapply(panel, function(x) {
  ggplot(data = df %>% filter(panel == x), aes(x = value, y = region)) +
         geom_point() +
         theme(axis.title.x = element_blank()) +
         facet_wrap(. ~ panel) +
         {if (x == 0) scale_y_discrete(position = "left") else scale_y_discrete(position = "right")} +
         {if (x == 1) theme(axis.title.y = element_blank())}
})

do.call("grid.arrange", c(plot_list, ncol = 2, bottom = "value"))

enter image description here

Paul van Oppen
  • 1,443
  • 1
  • 9
  • 18
  • Awesome, thanks! Any ideas what to do to get only 1 x-axis title (and potentially legend)? – Adam B. Jun 15 '20 at 04:27
  • 1
    Check the vignette for `gridExtra` [here](https://cran.r-project.org/web/packages/gridExtra/vignettes/arrangeGrob.html) . It has functions to annotate the plot in various ways/ – Paul van Oppen Jun 15 '20 at 04:32
  • 1
    Surrpress the x-axis title in the individual plots by adding this theme: `theme(axis.title.x = element_blank())`. You can then create a title at the bottom of the plot by: `do.call("grid.arrange", c(plot_list, ncol = 2, bottom = "value"))` – Paul van Oppen Jun 15 '20 at 05:03