1

I'm trying to create a plot for a publication that requires faceting. It has to show the same x axis on each facet and maintain even spacing of each y-axis metric.

facet_grid allows me to create the y metric spacing I want, but I can't get the x-axis to show across each facet. This seems to be part of how facet_grid works though as per this answer

facet_wrap allows me to show the x-axis on each facet, but it disrupts the y metric spacing. The values of each x-axis are also different which I need to be the same.

facet_rep_grid seems like it should be a solution but it throws me an error "Error in axisgrob$height$arg1 : $ operator is invalid for atomic vectors"

Using patchwork seems like it could be a solution but this also disrupts the y axis spacing that I need to be the exact same for each grid.

Reproducible examples of the plots I just described:

install.packages("lemon")
library(lemon)
data("mtcars")

df <- mtcars %>%
  rownames_to_column(var = "car")

mt <- ggplot(df, aes(mpg, car, colour = factor(cyl))) +
  theme(strip.placement = "outside")+
  geom_point()

# Good y metric spacing, can't get x-axis to show on each
mt + 
  facet_grid(vars(cyl), switch = "y", scales = "free", space = "free") 

# Incorrect y metric spacing, shows x-axis on each but uses different scales
mt + 
  facet_wrap(~cyl,  scales = "free", ncol=1, switch = "y") 

# Throws an error

mt +
  facet_rep_grid(vars(cyl), scales = "free"
                 , switch = "both", space = "free")


facet_grid version:

facet_grid

facet_wrap version:

facet_wrap

vb66
  • 353
  • 3
  • 14
  • can you provide your data (`df`)? It doesn't appear to be just the default `mpg` built-in set. – dandrews Mar 12 '23 at 15:49
  • 1
    the `scales="free"` argument allows the x-axis to vary, if you want it to be the same for every facet remove this – dandrews Mar 12 '23 at 15:50
  • 1
    @dandrews apologies I cut off the df set up when I was copying and pasting. Fixed! Removing `scales = "free"` doesn't solve my issue because I do need a scale on each facet which `scales = "free"` creates. By removing it, I only have an x-axis on the bottom facet. – vb66 Mar 12 '23 at 16:21

3 Answers3

2

Your final solution works for me.

mt +
  facet_rep_grid(vars(cyl), scales = "free"
                 , switch = "both", space = "free",
                 repeat.tick.labels = T)

enter image description here

If you still are getting an error can you post it? I had to re-install rlang and vctrs packages to get it to work.

dandrews
  • 967
  • 5
  • 18
2

Actually using lemon::facet_rep_grid works fine for me. But another option would be ggh4x::facet_grid2 which also allows to add interior axes:

library(ggplot2)
library(ggh4x)
library(tibble)

df <- mtcars %>%
  rownames_to_column(var = "car")

mt <- ggplot(df, aes(mpg, car, colour = factor(cyl))) +
  theme(strip.placement = "outside") +
  geom_point()

mt +
  facet_grid2(cyl ~ .,
    scales = "free_y",
    axes = "x", space = "free_y", switch = "y"
  )

stefan
  • 90,330
  • 6
  • 25
  • 51
  • Could you please check my answer and tell me how to get color aesthetics correct? Many thanks. – TarJae Mar 12 '23 at 17:28
  • 1
    @TarJae One option would be to add `limits = levels(factor(mtcars$cyl))` to `scale_color_manual`. Also, your code is missing the `legend`. One reason I would go for patchwork. – stefan Mar 12 '23 at 17:33
0

Here is an approximate solution using complete different approach:

library(tidyverse)

df_list <- mtcars %>%
  rownames_to_column("car") %>%
  group_split(cyl)

create_plot <- function(df) {
  ggplot(df, aes(mpg, car, color = factor(cyl))) +
    theme(strip.placement = "outside") +
    geom_point(show.legend = FALSE) +
    xlim(0, 30) +
    scale_color_manual(values = c("red", "green", "blue"),
                       limits = levels(factor(mtcars$cyl)))+
    facet_grid(cyl ~ .,
                scales = "free_y", switch = "y")
}

# Use map to apply function to each data frame in list
plots_list <- map(df_list, create_plot)

library(patchwork)
plots_list[[1]] / plots_list[[2]] / plots_list[[3]] + plot_layout(ncol = 1, heights = c(0.8, 0.5, 1))

enter image description here

TarJae
  • 72,363
  • 6
  • 19
  • 66
  • 1
    No this has two problems I described above. First, there is only an x-axis on the bottom axis. I need an x-axis on ALL 3 facets (i.e. the `facet_wrap` version I posted) with the SAME scale (`facet_wrap` has different scales). Second, I need all of the metrics on the y-axis to be perfectly evenly spaced. This means that the facets will have different widths because there is a different number of metrics in each group (ie. the `facet_grid` version I posted) – vb66 Mar 12 '23 at 16:24
  • I have updated! – TarJae Mar 12 '23 at 17:27
  • 1
    This does work too as an alternate solution using patchwork. – vb66 Mar 13 '23 at 14:03