Closed dvaiman closed 3 years ago
space = "free"
has no effect unless the scales also vary, so probably the bellow example is more appropriate? In my understanding, there's no workaround and specifying aspect.ratio = 1
should be errored as specifying coord_fixed()
does.
library(ggplot2)
p <- ggplot(mtcars, aes(hp, mpg)) +
geom_point(aes()) +
facet_grid(vars(cyl), scales = "free", space = "free")
# works
p
# fails properly
p + coord_fixed()
#> Error: coord_fixed doesn't support free scales
# do not fail, but the plot is strange
p + theme(aspect.ratio = 1)
Created on 2020-02-29 by the reprex package (v0.3.0)
Thanks for the input, I think your example more correctly describes the problem!
@thomasp85
Ah bummer. This change breaks a perfectly fine plot. :(
MWE below... If I want to make a gridded heatmap plot with geom_tile(), y is a factor, and x is character there is really no inherent scale to either axis. However, the only way to guarantee that my output plot has square tiles, while dropping irrelevant categories, is to use theme(aspect.ratio = 1)
in combination with facet_grid(..., scales="free_x", and space="free_x")
(unless you have other ideas?). Now this plot is impossible because it is blocked by this new error message. Can the error be changed to a warning() instead so that it is not a blocking change? There are valid use cases for this combination.
Example:
y = factor(x=c(1:6), labels=letters[1:6])
x = c("cat","dog","house","farm","road","tree")
xgrp = c("animal","animal","building","building","infrastructure","nature")
xval = rnorm(6)
dat = data.frame(y,x,xgrp, stringsAsFactors=F)
# this plot has the correct aspect ratio, but it includes every single x category in every facet, regardless of whether a value is actually present:
ggplot(dat, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
theme(aspect.ratio = 1) +
facet_grid(cols = vars(xgrp, x), drop=T) # , scales="free_x", space="free_x")
# this plot drops the irrelevant x categories in each facet, however my tiles are no longer guaranteed to be square:
ggplot(dat, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
# theme(aspect.ratio = 1) +
facet_grid(cols = vars(xgrp, x), drop=T, scales="free_x", space="free_x")
# this plot is perfect (in a previous version of ggplot2), but now I'm not allowed to make it:
ggplot(dat, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
theme(aspect.ratio = 1) +
facet_grid(cols = vars(xgrp, x), drop=T, scales="free_x", space="free_x")
@baderstine I'm surprised that this ever worked. It's unclear in the general case what exactly the output should be. You can always make individual plots and stitch them together with patchwork. Shouldn't be that much more work. See below for a rough example. You'd have to put in a little more work to remove the y axis labels from the interior plots, but that's maybe 5 additional lines of code or so.
library(tidyverse)
library(patchwork)
y <- factor(x=c(1:6), labels=letters[1:6])
x <- c("cat","dog","house","farm","road","tree")
xgrp <- c("animal","animal","building","building","infrastructure","nature")
data <- tibble(y, x, xgrp)
make_plot <- function(data) {
ggplot(data, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
scale_y_discrete(limits = letters[1:6]) +
coord_fixed() +
facet_grid(cols = vars(xgrp, x))
}
data %>%
mutate(
group = interaction(x, xgrp)
) %>%
nest(data = -group) %>%
mutate(
plots = map(data, ~make_plot(.x))
) %>%
pull(plots) %>%
wrap_plots(nrow = 1)
Created on 2021-10-21 by the reprex package (v2.0.0)
Interesting... so something like the following does the trick (although this is digging into a separate patchwork issue https://github.com/thomasp85/patchwork/issues/150)
library(tidyverse)
library(patchwork)
y <- factor(x=c(1:6), labels=letters[1:6])
x <- c("cat","dog","house","farm","road","tree")
xgrp <- c("animal","animal","building","building","infrastructure","nature")
data <- tibble(y, x, xgrp)
make_plot <- function(data) {
p <- ggplot(data, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
scale_y_discrete(limits = letters[1:6]) +
coord_fixed() +
facet_grid(cols = vars(xgrp, x)) +
theme(axis.title = element_blank(),
axis.ticks.y = element_blank())
if(data$plotnum != 1)
p <- p + theme(axis.text.y = element_blank())
p
}
data %>%
mutate(
group = interaction(x, xgrp),
plotnum = row_number()
) %>%
nest(data = -group) %>%
mutate(
plots = map(.x=data, .f=~make_plot(.x))
) %>%
pull(plots) %>%
wrap_plots(nrow = 1)
I was just wondering is it possible to have this properly fixed?
as in, restore the previous functionality when the x and y axes are discrete or what?
Yes, please!
@baderstine @Gsmith535 Yes, please, can space = "free" correctly work for facet_grid().
Yep it's a bummer that a plot is possible to render but instead we get an error message.
restore the previous functionality when the x and y axes are discrete
I'm getting to feel this might sound right, though I'm still in confusion what's the appropriate behavior... Anyway, it's not a good idea to keep discussing on a closed issue. Could you file a new issue describing what's the problem and what would be the "fix", with a minimal reprex?
The rendered version of https://github.com/tidyverse/ggplot2/issues/3834#issuecomment-948966404 at v3.3.3
tag.
y <- factor(x = c(1:6), labels = letters[1:6])
x <- c("cat", "dog", "house", "farm", "road", "tree")
xgrp <- c("animal", "animal", "building", "building", "infrastructure", "nature")
xval <- rnorm(6)
dat <- data.frame(y, x, xgrp, stringsAsFactors = F)
devtools::load_all("~/GitHub/ggplot2/")
#> ℹ Loading ggplot2
# this plot has the correct aspect ratio, but it includes every single x category in every facet, regardless of whether a value is actually present:
ggplot(dat, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
theme(aspect.ratio = 1) +
facet_grid(cols = vars(xgrp, x), drop = T) # , scales="free_x", space="free_x")
# this plot drops the irrelevant x categories in each facet, however my tiles are no longer guaranteed to be square:
ggplot(dat, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
# theme(aspect.ratio = 1) +
facet_grid(cols = vars(xgrp, x), drop = T, scales = "free_x", space = "free_x")
# this plot is perfect (in a previous version of ggplot2), but now I'm not allowed to make it:
ggplot(dat, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
theme(aspect.ratio = 1) +
facet_grid(cols = vars(xgrp, x), drop = T, scales = "free_x", space = "free_x")
Created on 2022-06-24 by the reprex package (v2.0.1)
@baderstine @yutannihilation I was just wondering why is this issue closed? Is the proper thing to reopen this issue or to open a new issue. Thank you.
I think the real issue is that we (maybe just me) have confused coord_fixed()
with the aspect.ratio
setting in the theme at some places in the code. I thought they did the same, but they do not.
library(tidyverse)
df <- tibble(
x = 1:3,
y = 2*(1:3),
z = 3*(1:3)
)
ggplot(df, aes(x, y)) +
geom_point() +
theme(aspect.ratio = 1)
ggplot(df, aes(x, y)) +
geom_point() +
coord_fixed()
Created on 2022-06-24 by the reprex package (v2.0.1)
Allowing coord_fixed()
with free scales is not possible, because it creates facets of all different shapes and sizes and then we don't know how to tile them. But allowing a fixed aspect ratio for all facets should always be possible.
The new issue should focus on this point specifically.
But allowing a fixed aspect ratio for all facets should always be possible.
In my understanding, aspect.ratio
is applied per panel, so it should conflict with scales = "free"
scales = "free" + space = "free"
because it varies the aspect ratios, at least the scale is continuous, isn't it...?
Are you suggesting
ggplot(mtcars, aes(hp, mpg)) +
geom_point() +
theme(aspect.ratio = 1) +
facet_grid(vars(cyl), scales = "free", space = "free")
should draw something like this, ignoring space = "free"
?
library(ggplot2)
l <- split(mtcars, mtcars$cyl)
plots <- purrr::imap(unname(l), \(x, i) {
ggplot(x, aes(hp, mpg)) +
theme(aspect.ratio = 1) +
geom_point() +
facet_grid(vars(cyl)) +
if (i != 3L) theme(axis.text.x = element_blank(), axis.title.x = element_blank())
})
patchwork::wrap_plots(plots, ncol = 1)
Created on 2022-06-25 by the reprex package (v2.0.1)
@yutannihilation I think that's the request, yes, and it would be consistent with what theme(aspect.ratio = 1)
does for a plot with a single panel.
And then this should also be properly documented, because right now if you read the documentation for aspect.ratio
in theme()
and for ratio
in coord_fixed()
they basically use the same language but apparently do entirely different things. There may also be other places in the code where this has been confused.
@yutannihilation better version of the reprex:
devtools::install_version("ggplot2", "3.3.3")
library(ggplot2)
y <- factor(x = c(1:6), labels = letters[1:6])
x <- c("cat", "dog", "house", "farm", "road", "tree")
xgrp <- c("animal", "animal", "building", "building", "infrastructure", "nature")
xval <- rnorm(6)
dat <- data.frame(y, x, xgrp, stringsAsFactors = F)
# this plot has the correct aspect ratio, but it includes every single x category in every facet, regardless of whether a value is actually present:
ggplot(dat, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
theme(aspect.ratio = 1) +
facet_grid(cols = vars(xgrp, x), drop = T) # , scales="free_x", space="free_x")
# this plot drops the irrelevant x categories in each facet, however my tiles are no longer guaranteed to be square:
ggplot(dat, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
# theme(aspect.ratio = 1) +
facet_grid(cols = vars(xgrp, x), drop = T, scales = "free_x", space = "free_x")
# this plot is perfect (in ggplot2 v <=3.3.3), but now I'm not allowed to make it:
# I am allowed to supply a custom aspect ratio, so that I can make square tiles, and therefore makes a rather nice heatmap plot.
my.aspect.ratio = length(unique(dat$y))
ggplot(dat, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
theme(aspect.ratio = my.aspect.ratio) +
facet_grid(cols = vars(xgrp, x), drop = T, scales = "free_x", space = "free_x")
@clauswilke
Sorry, I edited the comment above. Then, I found we can just remove space = "free"
.
library(ggplot2)
ggplot(mtcars, aes(hp, mpg)) +
geom_point() +
theme(aspect.ratio = 1) +
facet_grid(vars(cyl), scales = "free")
Created on 2022-06-25 by the reprex package (v2.0.1)
@baderstine Would you mind rendering the reprex by yourself?
@yutannihilation Wait, does @baderstine just have to remove space = "free_x"
to get the plot he wants?
@baderstine Is this what you want?
library(ggplot2)
y <- factor(x = c(1:6), labels = letters[1:6])
x <- c("cat", "dog", "house", "farm", "road", "tree")
xgrp <- c("animal", "animal", "building", "building", "infrastructure", "nature")
xval <- rnorm(6)
dat <- data.frame(y, x, xgrp, stringsAsFactors = F)
my.aspect.ratio <- length(unique(dat$y))
ggplot(dat, aes(y = y, x = x)) +
geom_tile(width = .8, height = .8) +
theme(aspect.ratio = my.aspect.ratio) +
facet_grid(cols = vars(xgrp, x), drop = T, scales = "free_x")
Created on 2022-06-25 by the reprex package (v2.0.1)
I think he wants the individual facets square rather than the overall plot.
Yep, it's about the shape of the individual plotted elements within each facet, not about the shape of the overall plot.
I guess i don't have a good enough reprex to demonstrate the issue. If I remove the space = "free_x" then individual facets that contain multiple x values are squished. I'll work on a new example.
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:
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):
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. :(
# 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.
Thanks, now I understand your intention, but I don't feel aspect.ratio
works as intended (again, I believe it should be reflected to the ratios of each panel). I agree it's nice if ggplot2 can provide some way to do it.
@clauswilke
Do you think what the last example shows is the correct use of aspect.ratio
and space = "free*"
?
Re-reading the documentation of everything, I think aspect.ratio
should set the overall aspect ratio of the plot and space = "free*"
should work as shown. So no, the example output does not look right. I don't think the aspect ratio for the overall plot is correct. I think it's awkward to apply the aspect ratio to individual facets, in particular if there's an option space = "free*"
that we also expect to work.
We also have to accept that sometimes we have to carefully calculate the width and height of a plot such that individual facets come out just right, and this can't always be the job of ggplot2, sometimes it's on the user. That's what I did for example to make sure that all the individual squares came out right in this chapter of my book: https://clauswilke.com/dataviz/directory-of-visualizations.html
Hmm. thanks. I don't agree with the idea of the overall aspect ratio of the plot at the moment, but it might be just that I don't read the documentation enough. As it turned out we all have different opinions on this topic, probably a closed issue is too small for the discussion. But let me clarify before filing a new issue. Do you mean both of the following results are wrong as aspect.ratio
sets the aspect ratio of the individual facets, not that of the whole plot? Or, are you discussing only about the cases with space = "free*"
?
library(ggplot2)
d <- data.frame(
x = c(1, 2, 3, 1, 1, 2),
y = c(1, 2, 3, 2, 3, 2),
g = rep(c("a", "b", "c"), times = c(3, 1, 2))
)
p <- ggplot(d, aes(x, y)) +
geom_point() +
theme(aspect.ratio = 1)
p + facet_wrap(vars(g))
p + facet_grid(vars(g))
Created on 2022-06-25 by the reprex package (v2.0.1)
Oh, sorry, maybe I misunderstood and was wrong about the aspect ratio. Are you saying it currently applies consistently to individual facets? Maybe that's fine then, except I don't know what it would/should do when the axis ranges are different in different facets.
Are you saying it currently applies consistently to individual facets?
Yes, I believe that's the current behavior.
what it would/should do when the axis ranges are different in different facets.
In my understanding, as you commented on https://github.com/tidyverse/ggplot2/issues/3834#issuecomment-1165656653, the aspect ratio is about the frame of the plot/panel and irrelevant to the actual values inside. So, I think the same rule applies to scales = "free"
without any problems (while it might not be always a good idea to use it especially when the scale is continuous).
Ok, that seems reasonable to me, but it would probably not produce the plot @baderstine was hoping for.
Thanks. Yeah, let's think about what option is needed to make it possible again next...
I was about to file a new issue, but it seems #4584 is the one.
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.
Is there any way to get the same plot as plot4 in the new version of ggplot2 (e.g., 3.4.0)? Thanks!
have you tried ggforce ? library(ggforce) ggplot(dat, aes(y = y, x = x)) + geom_tile(width = .8, height = .8) + theme(aspect.ratio = 1) + facet_row(~ xgrp+ x, drop = T, scales="free_x")+ theme(aspect.ratio = 6)
I believe the ggh4x
package solves this problem if you use ggh4x::facet_grid2
with options space=free
and scale=free
along with theme(aspect.ratio=1
Hi, in ggplot I want to set the aspect ratio of the plot to a certain number.
space = "free"
infacet_grid
does not seem to work withtheme(aspect.ratio = 1)
. Is there a workaround for this. Also I usecoord_flip
which hinders the use ofcoord_fixed.
This is what I get: