使用共享轴排列图中的面板
Arrange Panels in Figure with Shared Axis
我正在尝试在 ggplot 中制作一个包含三个面板的图形。我想删除两个面板相邻的轴标题和文本(请参见下面的示例),并将一个图例放置在空面上。
面板 A 和 B 应该具有相同的 y-axis,所有三个面板都具有相同的 x-axis(A 和 B 基本上是完整数据集和子集的图,而 C 显示百分比变化).我在 Whosebug 上看到了很多有用的帖子,但是 none 准确地解释了我想知道的内容。
我试过:
1) 使用 facet_wrap()
将面板绘制为面,使用 element_blank()
控制轴限制(如解释的 here) and use 函数替换图例:
# function to replace legend
library(lemon)
shift_legend2 <- function(p) {
# ...
# to grob
gp <- ggplotGrob(p)
facet.panels <- grep("^panel", gp[["layout"]][["name"]])
empty.facet.panels <- sapply(facet.panels, function(i) "zeroGrob" %in% class(gp[["grobs"]][[i]]))
empty.facet.panels <- facet.panels[empty.facet.panels]
# establish name of empty panels
empty.facet.panels <- gp[["layout"]][empty.facet.panels, ]
names <- empty.facet.panels$name
# example of names:
#[1] "panel-3-2" "panel-3-3"
# now we just need a simple call to reposition the legend
reposition_legend(p, 'center', panel=names)
}
# add dummy data for element_blank()
dat <- dat %>%
mutate(y_min = ifelse(figure == "pct_change", 0.8, 0),
y_max = ifelse(figure == "pct_change", 1.6, 150))
# plot
plot1 <- ggplot(dat, aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
facet_wrap(~figure, nrow = 2, scales = "free_y") +
geom_blank(aes(y = y_min)) +
geom_blank(aes(y = y_max))
# rearrange legend
shift_legend2(plot1)
2) 单独绘制面板并稍后排列
a <- ggplot(dat[dat$figure == "d_complete",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none",
axis.title.x = element_blank(),
axis.text.x = element_blank())
b <- ggplot(dat[dat$figure == "d_subset",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none",
axis.title.y = element_blank(),
axis.text.y = element_blank()) +
ylim(c(0, 120)
c <- ggplot(dat[dat$figure == "pct_change",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none")
plot2 <- plot_grid(a, b, c, ncol=2, align = "hv", axis = "bl")
结果如下:
现在的问题是:
- 在图 1 中,面板 A 的 x-axis 行消失了,我无法为面板 A 和 C 放置不同的 y-axis 图例,而面板 B 的 y-axis 文本仍然存在
- 在情节 2 中,情节之间的差距非常难看,我不知道如何添加图例
感谢您的帮助!
数据:
dput(dat)
structure(list(class = c("AUN", "AUN", "AUN", "AUN", "AUN", "AUN",
"AUN", "AUN", "AUN", "CHE", "CHE", "CHE", "CHE", "CHE", "CHE",
"CHE", "CHE", "CHE"), year = c(0L, 0L, 0L, 5L, 5L, 5L, 10L, 10L,
10L, 0L, 0L, 0L, 5L, 5L, 5L, 10L, 10L, 10L), figure = c("d_subset",
"d_complete", "pct_change", "d_subset", "d_complete", "pct_change",
"d_subset", "d_complete", "pct_change", "d_subset", "d_complete",
"pct_change", "d_subset", "d_complete", "pct_change", "d_subset",
"d_complete", "pct_change"), values = c(73, 99, 1, 84, 118, 1.19191919191919,
80, 96, 0.96969696969697, 12, 16, 1, 19, 27, 1.6875, 16, 20,
1.25), y_min = c(0, 0, 0.8, 0, 0, 0.8, 0, 0, 0.8, 0, 0, 0.8,
0, 0, 0.8, 0, 0, 0.8), y_max = c(150, 150, 1.6, 150, 150, 1.6,
150, 150, 1.6, 150, 150, 1.6, 150, 150, 1.6, 150, 150, 1.6)), class = c("grouped_df",
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -18L), groups = structure(list(
class = c("AUN", "CHE"), .rows = list(1:9, 10:18)), row.names = c(NA,
-2L), class = c("tbl_df", "tbl", "data.frame"), .drop = TRUE))
我认为您非常接近第二个选项。您只需修改 a、b 和 c 图的 plot.margin
以减小可怕间隙的大小,然后使用 ggdraw
将图例添加为 grob。这是生成所需绘图的完整代码。
library(tidyverse)
library(cowplot)
# Your original plots with the corresponding plot.margin
# Set the bottom margin to 0 to decrease the vertical gap between a and c plots
a <- ggplot(dat[dat$figure == "d_complete",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none",
axis.title.x = element_blank(),
axis.text.x = element_blank(),
# modify the plot's margins: top, right, bottom, left
plot.margin = unit(c(0.2,0,0,0), "cm"))
# Use same margins as plot a
b <- ggplot(dat[dat$figure == "d_subset",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none",
axis.title.y = element_blank(),
axis.text.y = element_blank(),
# modify the plot's margins: top, right, bottom, left
plot.margin = unit(c(0.2,0,0,0), "cm")) +
ylim(c(0, 120))
# Set top margin to -0.7 to decrease the vertical gap (between a and c)
c <- ggplot(dat[dat$figure == "pct_change",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none",
# modify the plot's margins: top, right, bottom, left
plot.margin = unit(c(-0.7,0,0.2,0), "cm"))
# Construct the c plot with legend
temp_plot <- dat %>%
filter(figure == "pct_change") %>%
ggplot(aes(x = year, y = values)) +
geom_line(aes(col = class))
# get the plot's legend and transform it to a grob
legend <- as_grob(get_legend(temp_plot))
# Put a, b and c plots together
plot2 <- plot_grid(a, b, c, ncol=2, align = "hv", axis = "bl")
# Add the legend
plot3 <- ggdraw(plot2) +
# set x and y position to draw the legend, usually requires playing with values between -1 and 1
draw_grob(legend, x = 0.25, y = 0.05, width = 1, height = 0.5)
我正在尝试在 ggplot 中制作一个包含三个面板的图形。我想删除两个面板相邻的轴标题和文本(请参见下面的示例),并将一个图例放置在空面上。
面板 A 和 B 应该具有相同的 y-axis,所有三个面板都具有相同的 x-axis(A 和 B 基本上是完整数据集和子集的图,而 C 显示百分比变化).我在 Whosebug 上看到了很多有用的帖子,但是 none 准确地解释了我想知道的内容。
我试过:
1) 使用 facet_wrap()
将面板绘制为面,使用 element_blank()
控制轴限制(如解释的 here) and use
# function to replace legend
library(lemon)
shift_legend2 <- function(p) {
# ...
# to grob
gp <- ggplotGrob(p)
facet.panels <- grep("^panel", gp[["layout"]][["name"]])
empty.facet.panels <- sapply(facet.panels, function(i) "zeroGrob" %in% class(gp[["grobs"]][[i]]))
empty.facet.panels <- facet.panels[empty.facet.panels]
# establish name of empty panels
empty.facet.panels <- gp[["layout"]][empty.facet.panels, ]
names <- empty.facet.panels$name
# example of names:
#[1] "panel-3-2" "panel-3-3"
# now we just need a simple call to reposition the legend
reposition_legend(p, 'center', panel=names)
}
# add dummy data for element_blank()
dat <- dat %>%
mutate(y_min = ifelse(figure == "pct_change", 0.8, 0),
y_max = ifelse(figure == "pct_change", 1.6, 150))
# plot
plot1 <- ggplot(dat, aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
facet_wrap(~figure, nrow = 2, scales = "free_y") +
geom_blank(aes(y = y_min)) +
geom_blank(aes(y = y_max))
# rearrange legend
shift_legend2(plot1)
2) 单独绘制面板并稍后排列
a <- ggplot(dat[dat$figure == "d_complete",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none",
axis.title.x = element_blank(),
axis.text.x = element_blank())
b <- ggplot(dat[dat$figure == "d_subset",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none",
axis.title.y = element_blank(),
axis.text.y = element_blank()) +
ylim(c(0, 120)
c <- ggplot(dat[dat$figure == "pct_change",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none")
plot2 <- plot_grid(a, b, c, ncol=2, align = "hv", axis = "bl")
结果如下:
现在的问题是:
- 在图 1 中,面板 A 的 x-axis 行消失了,我无法为面板 A 和 C 放置不同的 y-axis 图例,而面板 B 的 y-axis 文本仍然存在
- 在情节 2 中,情节之间的差距非常难看,我不知道如何添加图例
感谢您的帮助!
数据:
dput(dat)
structure(list(class = c("AUN", "AUN", "AUN", "AUN", "AUN", "AUN",
"AUN", "AUN", "AUN", "CHE", "CHE", "CHE", "CHE", "CHE", "CHE",
"CHE", "CHE", "CHE"), year = c(0L, 0L, 0L, 5L, 5L, 5L, 10L, 10L,
10L, 0L, 0L, 0L, 5L, 5L, 5L, 10L, 10L, 10L), figure = c("d_subset",
"d_complete", "pct_change", "d_subset", "d_complete", "pct_change",
"d_subset", "d_complete", "pct_change", "d_subset", "d_complete",
"pct_change", "d_subset", "d_complete", "pct_change", "d_subset",
"d_complete", "pct_change"), values = c(73, 99, 1, 84, 118, 1.19191919191919,
80, 96, 0.96969696969697, 12, 16, 1, 19, 27, 1.6875, 16, 20,
1.25), y_min = c(0, 0, 0.8, 0, 0, 0.8, 0, 0, 0.8, 0, 0, 0.8,
0, 0, 0.8, 0, 0, 0.8), y_max = c(150, 150, 1.6, 150, 150, 1.6,
150, 150, 1.6, 150, 150, 1.6, 150, 150, 1.6, 150, 150, 1.6)), class = c("grouped_df",
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -18L), groups = structure(list(
class = c("AUN", "CHE"), .rows = list(1:9, 10:18)), row.names = c(NA,
-2L), class = c("tbl_df", "tbl", "data.frame"), .drop = TRUE))
我认为您非常接近第二个选项。您只需修改 a、b 和 c 图的 plot.margin
以减小可怕间隙的大小,然后使用 ggdraw
将图例添加为 grob。这是生成所需绘图的完整代码。
library(tidyverse)
library(cowplot)
# Your original plots with the corresponding plot.margin
# Set the bottom margin to 0 to decrease the vertical gap between a and c plots
a <- ggplot(dat[dat$figure == "d_complete",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none",
axis.title.x = element_blank(),
axis.text.x = element_blank(),
# modify the plot's margins: top, right, bottom, left
plot.margin = unit(c(0.2,0,0,0), "cm"))
# Use same margins as plot a
b <- ggplot(dat[dat$figure == "d_subset",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none",
axis.title.y = element_blank(),
axis.text.y = element_blank(),
# modify the plot's margins: top, right, bottom, left
plot.margin = unit(c(0.2,0,0,0), "cm")) +
ylim(c(0, 120))
# Set top margin to -0.7 to decrease the vertical gap (between a and c)
c <- ggplot(dat[dat$figure == "pct_change",], aes(x = year, y = values)) +
geom_line(aes(col = class)) +
theme_cowplot(12) +
theme(legend.position = "none",
# modify the plot's margins: top, right, bottom, left
plot.margin = unit(c(-0.7,0,0.2,0), "cm"))
# Construct the c plot with legend
temp_plot <- dat %>%
filter(figure == "pct_change") %>%
ggplot(aes(x = year, y = values)) +
geom_line(aes(col = class))
# get the plot's legend and transform it to a grob
legend <- as_grob(get_legend(temp_plot))
# Put a, b and c plots together
plot2 <- plot_grid(a, b, c, ncol=2, align = "hv", axis = "bl")
# Add the legend
plot3 <- ggdraw(plot2) +
# set x and y position to draw the legend, usually requires playing with values between -1 and 1
draw_grob(legend, x = 0.25, y = 0.05, width = 1, height = 0.5)