如何在 R 中的网格上的特定位置排列图?
How to arrange plots in specific positions on a grid in R?
我正在尝试使用特定坐标将多个图(不同大小)绘制到网格上。为此,我正在使用 treemap
包创建一个树状图来获取坐标,然后使用这些坐标,我试图放置我的个人地块。希望我下面的例子能更好地解释我的问题。
首先,我创建了一些条形图,然后创建了一个树状图,如下所示:
library(ggplot2)
library(treemap)
#create data
df <- data.frame(var1 = c("A", "B", "C"),
var2 = runif(3),
var3 = runif(3),
var4 = runif(3),
size = c(10, 5, 3),
labels = c(1:3))
# Basic barplot
p1 <- ggplot(data=df, aes(x=var1, y=var2)) +
geom_bar(stat="identity")
p2 <- ggplot(data=df, aes(x=var1, y=var3)) +
geom_bar(stat="identity")
p3 <- ggplot(data=df, aes(x=var1, y=var4)) +
geom_bar(stat="identity")
#create treemap
tm <- treemap(df,
index = "labels",
vSize = "size",
palette = "Set2")
如果我们看一下树图对象 tm
,我们可以看到它提供了如下所示树图的坐标,其中 x0
、y0
、w
,h
是坐标。
> tm$tm
labels vSize vColor stdErr vColorValue level x0 y0 w h color
1 1 10 1 10 NA 1 0.0000000 0.000 0.5555556 1.000 #66C2A5
2 2 5 1 5 NA 1 0.5555556 0.375 0.4444444 0.625 #FC8D62
3 3 3 1 3 NA 1 0.5555556 0.000 0.4444444 0.375 #8DA0CB
所以,我想做的是将我的三个条形图 p1
、p2
和 p3
放入树图中,这样 p1
就会位于树状图的 1
位置.... p2
将位于 2
位置等...
为清楚起见,我想要的结果如下所示:
关于我如何做到这一点有什么建议吗?我尝试使用 patchwork
包,但 运行 涉及绘图重叠的问题......但我愿意接受使用任何包的建议(例如 gridExtra
或只是 ggplot
)
编辑
稍微澄清一下,根据彼得在下面给出的关于 patchwork
包的答案,我无法手动输入坐标作为绘图布局(我最初使用 area
中的函数 patchwork
并将树图的坐标输入 area
函数)。但是,正如下面评论中提到的,如果我有很多条形图,并且树状图的大小和形状发生变化,那么我就无法手动输入布局值。我正在尝试找到一种自动化流程的方法
patchwork
似乎工作正常:
library(patchwork)
library(ggplot2)
design <- "
11122
11122
11133
"
p1 + p2 + p3 + plot_layout(design = design)
由 reprex package (v2.0.1)
于 2021-11-28 创建
这需要一些算法,并不完美,但应该是使用 patchwork
更复杂的布局选项的开始。有几个技巧可以解决:
treemap
根据视口缩放其尺寸,这意味着它计算的位置取决于观察者,例如RStudio 的绘图窗格。相反,这不是绝对必要的,但您可能应该决定纵横比以确保框的位置是您想要的。
- 您需要将小数位和大小转换为整数,不是简单地乘以某个数字并四舍五入,而是找到它们的小数当量的分母并乘以它。例如,第一个框的宽度为 0.55555,即 5/9;为了得到整数,我们需要知道这个盒子应该是 5 个单位宽,总共 9 个单位。取最大宽高是任意的;关键是要得到一个不等于 1.0 的值。
- 从不同的维度中加减 1 不是最好的方法,但却是一种足够简单的方法来获得例如一个盒子从 1 到 5,下一个盒子从 6 到 9。
- 地块的顺序不正确,但大小是...还没弄明白为什么,但为了尝试诊断这个问题,我为每个地块添加了标签。
library(ggplot2)
library(treemap)
library(dplyr)
asp <- 1.25
tm <- treemap(df, index = "labels", vSize = "size", palette = "Set2", sortID = "labels",
aspRatio = asp)
denoms <- tm$tm %>%
tidyr::pivot_longer(w:h, names_to = "direction") %>%
filter(value < 1) %>%
group_by(direction) %>%
slice_max(value, n = 1) %>%
mutate(denom = MASS::fractions(value) %>%
stringr::str_extract("\d+$") %>%
as.numeric()) %>%
select(direction, denom) %>%
tibble::deframe()
denoms
#> h w
#> 8 9
areas <- tm$tm %>%
mutate(across(c(x0, w), ~. * denoms[["w"]]),
across(c(y0, h), ~. * denoms[["h"]]),
top = y0 + 1,
left = x0 + 1,
bottom = top + h - 1,
right = left + w - 1) %>%
select(top:right) %>%
purrr::pmap(function(top, left, bottom, right) patchwork::area(top, left, bottom, right)) %>%
purrr::reduce(c)
patchwork::wrap_plots(p1, p2, p3, design = areas)
我正在尝试使用特定坐标将多个图(不同大小)绘制到网格上。为此,我正在使用 treemap
包创建一个树状图来获取坐标,然后使用这些坐标,我试图放置我的个人地块。希望我下面的例子能更好地解释我的问题。
首先,我创建了一些条形图,然后创建了一个树状图,如下所示:
library(ggplot2)
library(treemap)
#create data
df <- data.frame(var1 = c("A", "B", "C"),
var2 = runif(3),
var3 = runif(3),
var4 = runif(3),
size = c(10, 5, 3),
labels = c(1:3))
# Basic barplot
p1 <- ggplot(data=df, aes(x=var1, y=var2)) +
geom_bar(stat="identity")
p2 <- ggplot(data=df, aes(x=var1, y=var3)) +
geom_bar(stat="identity")
p3 <- ggplot(data=df, aes(x=var1, y=var4)) +
geom_bar(stat="identity")
#create treemap
tm <- treemap(df,
index = "labels",
vSize = "size",
palette = "Set2")
如果我们看一下树图对象 tm
,我们可以看到它提供了如下所示树图的坐标,其中 x0
、y0
、w
,h
是坐标。
> tm$tm
labels vSize vColor stdErr vColorValue level x0 y0 w h color
1 1 10 1 10 NA 1 0.0000000 0.000 0.5555556 1.000 #66C2A5
2 2 5 1 5 NA 1 0.5555556 0.375 0.4444444 0.625 #FC8D62
3 3 3 1 3 NA 1 0.5555556 0.000 0.4444444 0.375 #8DA0CB
所以,我想做的是将我的三个条形图 p1
、p2
和 p3
放入树图中,这样 p1
就会位于树状图的 1
位置.... p2
将位于 2
位置等...
为清楚起见,我想要的结果如下所示:
关于我如何做到这一点有什么建议吗?我尝试使用 patchwork
包,但 运行 涉及绘图重叠的问题......但我愿意接受使用任何包的建议(例如 gridExtra
或只是 ggplot
)
编辑
稍微澄清一下,根据彼得在下面给出的关于 patchwork
包的答案,我无法手动输入坐标作为绘图布局(我最初使用 area
中的函数 patchwork
并将树图的坐标输入 area
函数)。但是,正如下面评论中提到的,如果我有很多条形图,并且树状图的大小和形状发生变化,那么我就无法手动输入布局值。我正在尝试找到一种自动化流程的方法
patchwork
似乎工作正常:
library(patchwork)
library(ggplot2)
design <- "
11122
11122
11133
"
p1 + p2 + p3 + plot_layout(design = design)
由 reprex package (v2.0.1)
于 2021-11-28 创建这需要一些算法,并不完美,但应该是使用 patchwork
更复杂的布局选项的开始。有几个技巧可以解决:
treemap
根据视口缩放其尺寸,这意味着它计算的位置取决于观察者,例如RStudio 的绘图窗格。相反,这不是绝对必要的,但您可能应该决定纵横比以确保框的位置是您想要的。- 您需要将小数位和大小转换为整数,不是简单地乘以某个数字并四舍五入,而是找到它们的小数当量的分母并乘以它。例如,第一个框的宽度为 0.55555,即 5/9;为了得到整数,我们需要知道这个盒子应该是 5 个单位宽,总共 9 个单位。取最大宽高是任意的;关键是要得到一个不等于 1.0 的值。
- 从不同的维度中加减 1 不是最好的方法,但却是一种足够简单的方法来获得例如一个盒子从 1 到 5,下一个盒子从 6 到 9。
- 地块的顺序不正确,但大小是...还没弄明白为什么,但为了尝试诊断这个问题,我为每个地块添加了标签。
library(ggplot2)
library(treemap)
library(dplyr)
asp <- 1.25
tm <- treemap(df, index = "labels", vSize = "size", palette = "Set2", sortID = "labels",
aspRatio = asp)
denoms <- tm$tm %>%
tidyr::pivot_longer(w:h, names_to = "direction") %>%
filter(value < 1) %>%
group_by(direction) %>%
slice_max(value, n = 1) %>%
mutate(denom = MASS::fractions(value) %>%
stringr::str_extract("\d+$") %>%
as.numeric()) %>%
select(direction, denom) %>%
tibble::deframe()
denoms
#> h w
#> 8 9
areas <- tm$tm %>%
mutate(across(c(x0, w), ~. * denoms[["w"]]),
across(c(y0, h), ~. * denoms[["h"]]),
top = y0 + 1,
left = x0 + 1,
bottom = top + h - 1,
right = left + w - 1) %>%
select(top:right) %>%
purrr::pmap(function(top, left, bottom, right) patchwork::area(top, left, bottom, right)) %>%
purrr::reduce(c)
patchwork::wrap_plots(p1, p2, p3, design = areas)