possibility to adjust height of individual facets according to number of items on y axis?

Am I correct that it is currently not possible to change the height of indiviudal facets in a 'multi column' plot? Many thanks!

I am trying to create a facetted heatmap and facets have different numbers of items on the y axis. What I want is that each heatmap's height is proportional to the number of items on the y axis (in the examples below number of different cars).

EDIT: To be more precise, I am not trying to change the hight of the facets but the height of the rectangles (bin-width?)

I am aware that the missing 'space' argument in facet_wrap was (partly) addressed in the wonderful ggforce's facet_row/col, but as far as I understand they 'only' refer to one-dimensional facets.

The plot with facet_wrap below should have facets of different hight. As its stands, I think, it is visually misleading/distorting.

library(tidyverse)
library(ggforce)
library(patchwork)


mtcars %>% 
  rownames_to_column(., "car_name") %>% 
  ggplot()+
  geom_tile(aes(y=car_name,
            x=gear,
            fill=mpg))+
  facet_wrap(vars(carb),
             nrow=2,
             scale="free_y")

Below, facet_grid offers the space argument. But afaik there is no option to adjust the number of columns (other than including another column).


mtcars %>% 
  rownames_to_column(., "car_name") %>% 
  ggplot()+
  geom_tile(aes(y=car_name,
                x=gear,
                fill=mpg))+
  facet_grid(vars(carb),
             space="free",
             scale="free_y")

Here ggforce's facet_col. Again, afaik there is no ncol option.


mtcars %>% 
  rownames_to_column(., "car_name") %>% 
  ggplot()+
  geom_tile(aes(y=car_name,
                x=gear,
                fill=mpg))+
  ggforce::facet_col(vars(carb),
             space="free",
             scale="free_y")

Finally, I gave patchwork a try and assign the different car numbers per facet as the height argument.
However, once I arrange the plots in multiple columns the facets have the height of the highest facet in the row.

plots_mtcars <- mtcars %>% 
  rownames_to_column(., "car_name") %>% 
  group_split(carb) %>% 
  map(~ggplot(.) +
        geom_tile(aes(y=car_name,
                x=gear,
                fill=mpg))+
        labs(title=paste0("carb:", unique(.$carb)))+
        theme(legend.position="none"))


plot_heights<- mtcars %>% 
  group_by(carb) %>% 
  summarise(n_obs=n()) %>% 
  pull(n_obs)

wrap_plots(plots_mtcars) +
  plot_layout(heights=plot_heights, ncol=2)

Created on 2019-12-06 by the reprex package (v0.3.0)

Hi @zoowalk. You can do it but a little bit tricky. Plot each facets and legend individually and arrange plots by plot_grid from cowplot and grid.arrange from gridExtra with layout_matrix.

library(tidyverse)
library(cowplot)
#> 
#> ********************************************************
#> Note: As of version 1.0.0, cowplot does not change the
#>   default ggplot2 theme anymore. To recover the previous
#>   behavior, execute:
#>   theme_set(theme_cowplot())
#> ********************************************************

gg <- map(levels(factor(mtcars$carb)), ~{
  mtcars %>%
    rownames_to_column(., "car_name") %>%
    mutate(gear = factor(gear)) %>%
    filter(carb == .x) %>%
    ggplot() +
    geom_tile(aes(gear, car_name, fill = mpg)) +
    scale_x_discrete(drop = FALSE) +
    coord_equal() +
    scale_fill_continuous(limits = c(min(mtcars$mpg), max(mtcars$mpg))) +
    theme(legend.position = "none") +
    labs(y = NULL, x = NULL) + 
    facet_wrap(~carb)
}) %>%
{plot_grid(plotlist = ., nrow = 2, align = "v")}

legend <- plot_grid(NULL, get_legend(mtcars %>%
                                       rownames_to_column(., "car_name") %>%
                                       ggplot() +
                                       geom_tile(aes(gear, car_name, fill = mpg)) +
                                       scale_fill_continuous(limits = c(min(mtcars$mpg), max(mtcars$mpg)))), nrow = 2)
  
gridExtra::grid.arrange(gg,legend, layout_matrix = cbind(rep(1, 3), rep(1, 3), rep(1, 3), c(NA, 2, NA)))

Created on 2019-12-07 by the reprex package (v0.3.0)

1 Like

Hi @raytong,

many thanks for your reply and detailing the 'tricky' appraoch. Obviously, I would have hoped there is a more direct and simple approach, but if this is the way to go....

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.