I'm having some unexpected behavior in ggplot with geom_tile()
and facet
ing.
Here's the classic "volcano" tile:
library(ggplot2)
library(reshape2)
volcano %>%
reshape2::melt() %>%
ggplot() + geom_tile(aes(x = Var1, y = Var2, fill = value))
Good. Now let's add an index column and facet
the image...
volcano %>%
reshape2::melt() %>%
cross_join(tibble(idx = c(1,2,3))) %>%
ggplot() + geom_tile(aes(x = Var1, y = Var2, fill = value)) +
facet_wrap(vars(idx))
OK. That's nice. Now I'm going to create different scales on the x axis and use the scales = "free"
parameter...
volcano %>%
reshape2::melt() %>%
cross_join(tibble(idx = c(1,2,3))) %>%
mutate(Var1 = Var1/idx) %>%
ggplot() + geom_tile(aes(x = Var1, y = Var2, fill = value)) +
facet_wrap(vars(idx), scales = "free")
}
Note the x-axis values differ between the last graph and this one.
It's not that ggplot
has a fundamental problem with the re-scaled axis. Here I plot the third panel of the prior image by itself with no facet
ing.
volcano %>%
reshape2::melt() %>%
cross_join(tibble(idx = c(1,2,3))) %>%
mutate(Var1 = Var1/idx) %>%
filter(idx == 3) %>%
ggplot() + geom_tile(aes(x = Var1, y = Var2, fill = value))
The problem is facet
ing with different scales. The problem persists even if I don't use scales = "free"
parameter...
volcano %>%
reshape2::melt() %>%
cross_join(tibble(idx = c(1,2,3))) %>%
mutate(Var1 = Var1/idx) %>%
ggplot() + geom_tile(aes(x = Var1, y = Var2, fill = value)) +
facet_wrap(vars(idx))
Seems lake a bug to me, but I don't see an issue report when I search "geom_tile facet" on github tidyverse/ggplot.
Anyone out there have an idea how I could get a proper plot without the banding?
UPDATE: Here is a small example that shows what is going on in more detail. ggplot
appears to be calculating the width of each column in the tile using one scale, and applying that width to all of the plots...
# make some data
data.frame(x = 1:10, y = rep(1:10, each=10), value = runif(100)) %>%
# duplicate the data and alter the scale of the second set
bind_rows(., mutate(., x=x/3), .id = "idx") %>%
# plot with faceting
ggplot() + geom_tile(aes(x=x, y=y, fill = value)) + facet_wrap("idx")
You could vary tile width by facet. ggplot2 tiles are based on what ggplot2 identifies as the "resolution" of the data.
volcano %>%
reshape2::melt() %>%
cross_join(tibble(idx = c(1,2,3))) %>%
mutate(width = max(diff(Var1), na.rm = TRUE), .by = idx) |>
ggplot() +
geom_tile(aes(x = Var1, y = Var2, fill = value, width = width)) +
facet_wrap(vars(idx), scales = "free")