Closed robjhyndman closed 4 years ago
The same happened to me ! I updated my R version to 4.0.0 recently.
Same happened to me after I updated to R 4.0.0
+1 My R is 3.6.1
Same happened to me after I updated to R 4.0.0
Anyone know if a solution is to be expected soon? If I can help in anyway, please let me know.
No idea, but it would help if someone could find the source of the problem. At least then it would be easier to fix it (via PR or Thomas himself).
I will look into this within a week or two
So I took a look into that issue and the behaviour of all.equal is not the same in R 4.0.0 on grobs (https://github.com/thomasp85/patchwork/blob/master/R/guides.R#L31). Although, I don't know (yet) how to fix this.
library(patchwork)
library(ggplot2)
library(gtable)
p <- ggplot(iris, aes(Sepal.Length, Petal.Length, colour = Species)) +
geom_point()
guides <- list(
gtable_filter(ggplotGrob(p), "guide-box"),
gtable_filter(ggplotGrob(p), "guide-box")
)
unnamed <- lapply(guides, patchwork:::unname_grob)
i <- 2
j <- 1
res <- all.equal(unnamed[[i]], unnamed[[j]], check.names = FALSE, check.attributes = FALSE)
head(res)
#> [1] "Component \"grobs\": Component 1: Component 1: Component 1: Component 1: Component 2: Component 3: Component 3: Component 1: Component 2: Component 1: Component 2: Component 2: Component 1: Component 2: Component 9: 1 string mismatch"
#> [2] "Component \"grobs\": Component 1: Component 1: Component 1: Component 1: Component 2: Component 3: Component 3: Component 1: Component 2: Component 2: Component 2: Component 2: Component 1: Component 2: Component 9: 1 string mismatch"
#> [3] "Component \"grobs\": Component 1: Component 1: Component 1: Component 1: Component 2: Component 3: Component 3: Component 1: Component 2: Component 3: 1 string mismatch"
#> [4] "Component \"grobs\": Component 1: Component 1: Component 1: Component 1: Component 2: Component 3: Component 3: Component 1: Component 2: Component 5: Component 1: Component 11: Component 3: Component 2: Component 2: Component 1: Component 2: Component 9: 1 string mismatch"
#> [5] "Component \"grobs\": Component 1: Component 1: Component 1: Component 1: Component 2: Component 3: Component 3: Component 1: Component 2: Component 5: Component 1: Component 11: Component 4: Component 2: Component 2: Component 1: Component 2: Component 9: 1 string mismatch"
#> [6] "Component \"grobs\": Component 1: Component 1: Component 1: Component 1: Component 2: Component 3: Component 3: Component 1: Component 2: Component 5: Component 1: Component 17: 1 string mismatch"
thanks - yeah, I suspected some change in all.equal()
was the root cause
For the ones more expert in grid
than me, the challenge to solve the issue is to return TRUE with the following code (in R 4.0.0):
library("grid")
x <- grob()
y <- grob()
all.equal(x, y)
#> [1] "Component \"name\": 1 string mismatch"
EDIT:
library("grid")
x <- patchwork:::unname_grob(grob())
y <- patchwork:::unname_grob(grob())
all.equal(x, y)
#> [1] TRUE
Maybe unname_grob needs to be called recursively on the guides.
EDIT2: Following my previous reprex, I think the issue comes from the new unit class used in grid.
# R 4.0.0
x <- unnamed[[1]]$grobs[[1]]$grobs[[1]]$grobs[[2]]$children[[1]]$widths[[2]]
y <- unnamed[[2]]$grobs[[1]]$grobs[[1]]$grobs[[2]]$children[[1]]$widths[[2]]
all.equal(x, y, check.names = FALSE, check.attributes = FALSE)
#> [1] "Component 1: Component 2: Component 1: Component 2: Component 9: 1 string mismatch"
# this is the location of the component '$name : chr "GRID.text.509"', in the sub element of classes "text", "grob" and "gDesc"
class(x)
#> [1] "unit" "unit_v2"
class(y)
#> [1] "unit" "unit_v2"
# R 3.6.3
x <- unnamed[[1]]$grobs[[1]]$grobs[[1]]$grobs[[2]]$children[[1]]$widths[[2]]
y <- unnamed[[2]]$grobs[[1]]$grobs[[1]]$grobs[[2]]$children[[1]]$widths[[2]]
all.equal(x, y, check.names = FALSE, check.attributes = FALSE)
#> [1] TRUE
class(x)
#> [1] "unit.arithmetic" "unit"
class(y)
#> [1] "unit.arithmetic" "unit"
Is there a workaround for now that we can use?
Yes, to manually remove the duplicated legends.
library(patchwork)
library(ggplot2)
p <- ggplot(iris, aes(Sepal.Length, Petal.Length, colour = Species)) +
geom_point()
p + p + plot_layout(guides = "collect")
(p + theme(legend.position = "none")) + p + plot_layout(guides = "collect")
Thanks, logical! To combine this with the legend positions new problems arise of course. E.g.
library(patchwork)
library(ggplot2)
p <- ggplot(iris, aes(Sepal.Length, Petal.Length, colour = Species)) +
geom_point()
(p + theme(legend.position = "none")) + p + plot_layout(guides = "collect") & theme(legend.position = "bottom")
vs
library(patchwork)
library(ggplot2)
p <- ggplot(iris, aes(Sepal.Length, Petal.Length, colour = Species)) +
geom_point()
(p + theme(legend.position = "none")) + p + plot_layout(guides = "collect") & theme(legend.position = "bottom")
Both are not ideal, but if you define the position for the first legend and then remove the later ones it works as we want to:
library(patchwork)
library(ggplot2)
p <- ggplot(iris, aes(Sepal.Length, Petal.Length, colour = Species)) +
geom_point()
(p + plot_layout(guides = "collect") & theme(legend.position = "bottom")) + (p + theme(legend.position = "none"))
Use guides to remove the legend then
library(patchwork)
library(ggplot2)
p <- ggplot(iris, aes(Sepal.Length, Petal.Length, colour = Species)) +
geom_point()
p_theme <- p + theme(legend.position = "none")
p_guide <- p + guides(colour = "none")
p_theme + p +
plot_layout(guides = "collect") & theme(legend.position = "bottom")
p_guide + p +
plot_layout(guides = "collect") & theme(legend.position = "bottom")
This was working in R3.6.3, but not in R4.0.
Created on 2020-04-27 by the reprex package (v0.3.0)