Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow coord_fixed() with facet_grid(..., scales = "free", space = "free") when x and y scales are discrete #4584

Open
archavan opened this issue Aug 12, 2021 · 5 comments · May be fixed by #5977
Labels
facets 💎 feature a feature request or enhancement

Comments

@archavan
Copy link

It makes sense that it’s not possible to mix facet_grid(..., scales = "free", space = "free") with coord_fixed() in most situations. However, I think that it should be possible and makes sense to allow this when both, x and y, scales are discrete.

For example, a use case in this reprex with ggplot2 version 3.3.4:

library(tidyverse) # with ggplot2 v3.3.4
set.seed(1)
df <- expand_grid(x = letters[1:6], y = LETTERS[1:2]) %>% 
  mutate(w = case_when(x %in% letters[1:2] ~ "1",
                       x %in% letters[3:6] ~ "2")) %>% 
  mutate(value = rnorm(6*2))

gg <- ggplot(df) +
    geom_point(aes(x, y, color = value)) +
    facet_grid(cols = vars(w), scales = "free", space = "free")

gg

Here, we have different numbers and levels of factors in x scale, so it’s necessary to use scales = "free" and space = "free" for efficient use of space.

When I make plots like this one, I like to make sure that the breaks on x and y axes are placed equidistantly (so the background grid is made of squares), which would generally be accomplished with coord_fixed() but not possible in this case since we are using free scales and space.

gg + coord_fixed()
#> Error: coord_fixed doesn't support free scales

As of version 3.3.3 of ggplot2 it was possible to still accomplish this without coord_fixed() by the (perhaps hacky and off-label) use of theme(aspect.ratio = 1), also pointed out in this SO post. See reprex below with version 3.3.3. This is however no longer possible since this bug was fixed (#4432).

library(tidyverse) # with ggplot2 v3.3.3
set.seed(1)
df <- expand_grid(x = letters[1:6], y = LETTERS[1:2]) %>% 
  mutate(w = case_when(x %in% letters[1:2] ~ "1",
                       x %in% letters[3:6] ~ "2")) %>% 
  mutate(value = rnorm(6*2))

gg <- ggplot(df) +
  geom_point(aes(x, y, color = value)) +
  facet_grid(cols = vars(w), scales = "free", space = "free")

gg + theme(aspect.ratio = 1)

It would be great if this can be accomplished legitimately with coord_fixed() rather than by using hacks. Based on my admittedly superficial understanding, I think that the use of coord_fixed() when faceting with free scales and space should be legitimate as long as the x and y scales are discrete.

Created on 2021-08-12 by the reprex package (v2.0.0)

@Gsmith535
Copy link

I would like to second this (or at least something similar), for an additional use-example while using geom_tile() in order to constrain the rectangular shapes. The ability to combine coord/aspect specifications and free scaling was especially convenient for multi-panel, faceted tile plots, and even further if different aesthetics are desired. Can there somehow be exceptions for discrete axes perhaps?

library(tidyverse) # with ggplot2 v3.3.3
library(gridExtra)
set.seed(1)
df <- expand_grid(x = letters[1:6], y = LETTERS[1:2]) %>% 
  mutate(w = case_when(x %in% letters[1:2] ~ "1",
                       x %in% letters[3:6] ~ "2")) %>% 
  mutate(value = rnorm(6*2))

gg <- ggplot(df) +
  geom_tile(aes(x, y, fill = value)) +
  facet_grid(cols = vars(w), scales = "free", space = "free") +
  scale_fill_distiller(palette="Greens")

A <- gg
A

B <- gg + theme(aspect.ratio = 1)
B

C <- gg + coord_fixed()
C
#Error: coord_fixed doesn't support free scales
#Run `rlang::last_error()` to see where the error occurred.

D <- gg + coord_equal()
D
#Error: coord_fixed doesn't support free scales
#Run `rlang::last_error()` to see where the error occurred.

grid.arrange(A, B) 

df2 <- expand_grid(x = letters[17:26], y = LETTERS[1:2]) %>% 
  mutate(w = case_when(x %in% letters[17:23] ~ "3",
                       x %in% letters[24:26] ~ "4")) %>% 
  mutate(value = rnorm(5*4))

gg2 <- ggplot(df2) +
  geom_tile(aes(x, y, fill = value)) +
  facet_grid(cols = vars(w), scales = "free", space = "free") +
  scale_fill_distiller(palette="Blues")

E <- gg2
E

F <- gg2 + theme(aspect.ratio = 1)
F

grid.arrange(A, E, B, F, ncol = 2, widths = c(0.7,1)) 

Please let me know if anything in this request was unclear.

@thomasp85
Copy link
Member

I'm generally fine with this if it can be implemented in a clean way

@yutannihilation
Copy link
Member

yutannihilation commented Jun 25, 2022

Copying @baderstine's comment from #3834 (comment), which describes why the combination of theme(aspect.ratio = ) and facet_grid(space = "free") was useful. On #3834, we came to the conclusion the combination is probably against the semantics of aspect.ratio, but this usage (the last example) should be something that ggplot2 should provide if possible. I think the combination of coord_fixed() and facet_grid(scales = "free, space = "free") should produce this?


ok, this should help:

devtools::install_version("ggplot2", "3.3.3")
library(ggplot2)

ggplot(dat, aes(y = y, x = var)) +
  geom_tile(width = .8, height = .8) +
  theme(aspect.ratio = 1) +
  facet_grid(cols = vars(vargrp, varunt), drop = T) # , scales="free_x", space="free_x")

Plot 1: has the correct aspect ratio, but it includes every single x category in every facet, regardless of whether a value is actually present:

plot1

ggplot(dat, aes(y = y, x = var)) +
  geom_tile(width = .8, height = .8) +
  # theme(aspect.ratio = 1) +
  facet_grid(cols = vars(vargrp, varunt), drop = T, scales="free_x", space="free_x")

Plot 2: drops the irrelevant x categories in each facet, however my tiles are not the shape that i want (square):

plot2

my.aspect.ratio = length(unique(dat$y))

# without space = "free_x"
ggplot(dat, aes(y = y, x = var, color=xval)) +
  geom_tile(width = .8, height = .8) +
  theme(aspect.ratio = my.aspect.ratio) +
  facet_grid(cols = vars(vargrp, varunt), drop = T, scales="free_x")

Plot 3: drops irrelevant x categories and each facet's size is constant but the facets with more x categories are now squished... more categories, more squish. :(
plot3

# this plot is perfect (in ggplot2 v <=3.3.3), but now I'm not allowed to make it:
# I supply a custom aspect ratio, so that I can change the shape (aspect ratio) of my resulting tiles.

ggplot(dat, aes(y = y, x = var, color=xval)) +
  geom_tile(width = .8, height = .8) +
  theme(aspect.ratio = my.aspect.ratio) +
  facet_grid(cols = vars(vargrp, varunt), drop = T, scales="free_x", space="free_x")

Plot 4: drops irrelevant x categories and allows the size of each x facet to vary based on how many categories are in it, and with a specific aspect ratio applied, i can now make nice little squarish boxes.
plot4

@baptiste
Copy link
Contributor

Copying @baptiste's comment from #3834 (comment)

not me, @baderstine I believe

@yutannihilation
Copy link
Member

Aw, yes... Sorry for the noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
facets 💎 feature a feature request or enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants