我正在尝试创建一个结合了 2 个独立图例和多个绘图网格的绘图。我遇到的问题是我发现很难对齐图例以使它们可见且不重叠。希望下面的例子能够解释我的意思。
首先,我将创建 2 个图。在这两个图中,我只对图例感兴趣,并且我放弃了实际的图(所以请忽略这两个图中的实际图)。为了获得图例,我正在使用
cowplot
包。
library(ggplot2)
library(cowplot)
# -------------------------------------------------------------------------
# plot 1 ------------------------------------------------------------------
# create fake data
dfLegend_1 <- data.frame(x = LETTERS[1:10], y = c(1:10))
# set colours
pointColours <- c(A = "#F5736A", B = "#D58D00", C = "#A0A300",
D = "#36B300", E = "#00BC7B", F = "#00BCC2",
G = "#00ADF4", H = "#928DFF", I = "#E568F0",
J = "#808080")
# plot
ggLegend_1 <- ggplot(dfLegend_1, aes(x=x, y=y))+
geom_point(aes(fill = pointColours), shape = 22, size = 10) +
scale_fill_manual(values = unname(pointColours),
label = names(pointColours),
name = 'Variable') +
theme(legend.key.size = unit(0.5, "cm")) +
theme_void()
# get legend
legend_1 <- get_legend(ggLegend_1)
# -------------------------------------------------------------------------
# plot 2 ------------------------------------------------------------------
# Create fake data
dflegend_2 <- data.frame(
x = runif(100),
y = runif(100),
z2 = abs(rnorm(100))
)
# plot
ggLegend_2 <- ggplot(dflegend_2, aes(x=x, y = y))+
geom_point(aes(color = z2), shape = 22, size = 10) +
scale_color_gradientn(
colours = rev(colorRampPalette(c('steelblue', '#f7fcfd', 'orange'))(5)),
limits = c(0,10),
name = 'Gradient',
guide = guide_colorbar(
frame.colour = "black",
ticks.colour = "black"
))
# get legend
legend_2 <- get_legend(ggLegend_2)
然后我创建许多图(在本例中,我创建 20 个单独的图)并将它们绘制在网格上:
# create data
dfGrid <- data.frame(x = rnorm(10), y = rnorm(10))
# make a list of plots
plotList <- list()
for(i in 1:20){
plotList[[i]] <- ggplot(dfGrid) +
geom_ribbon(aes(x = x, ymin = min(y), ymax = 0), fill = "red", alpha = .5) +
geom_ribbon(aes(x = x, ymin = min(0), ymax = max(y)), fill = "blue", alpha = .5) +
theme_void()
}
# plot them on a grid
gridFinal <- cowplot::plot_grid(plotlist = plotList)
最后,我将这两个图例连接在一起,并将它们添加到许多图的网格中:
# add legends together into on single plot
legendFinal <- plot_grid(legend_2, legend_1, ncol = 1)
# plot everything on the same plot
plot_grid(gridFinal, legendFinal, rel_widths = c(3, 1))
如您所见,图例重叠且间隔不是很好。我想知道是否有任何方法可以容纳所有内容,同时使图例适当间隔且可读?
我还应该注意,一般来说,可以有任意数量的变量和任意数量的网格图。
解决问题的一个选项是切换到
patchwork
将绘图和图例粘合在一起。特别是我利用 design
参数为 Variable
图例分配更多空间。但是,您应该意识到,与绘图相比,图例的灵活性要低得多,即图例的大小采用绝对单位,并且不会根据可用空间进行调整。因此,我不确定我的解决方案是否符合您对“一刀切”方法的渴望。
library(patchwork)
design <-
"
ABCDEU
FGHIJV
KLMNOV
PQRSTV
"
plotList2 <- c(plotList, list(legend_2, legend_1))
wrap_plots(plotList2) +
plot_layout(design = design)
基于您的图例中的颜色实际上代表图中显示的内容的大胆假设,我可以建议采用完全不同的方法来解决该问题。不要笨拙地创建完全不相关的图例,而是使用 ggplot 的自动图例创建功能,它将正确地将图例映射到您的情节美学。我想知道颜色渐变的用途是什么,但是您可以简单地使用假几何图层创建一个渐变。 (我正在使用
geom_point(shape = NA)
)。
这需要您将组(例如 A/B/C 等)正确映射到数据。完成此操作后,您将只能调用 geom_ribbon once。
然后我将使用拼凑来组合您的情节,您可以收集指南。这要求所有指南(图例)完全相同。您可以通过指定
scale_
函数内的限制来确保这一点。
但是,最好使用切面。这可以通过绑定假定的几个数据帧并使用原点作为分面的 ID 来实现。
丝带看起来有点不同,因为我实际上正在绘制与 y<0 and y>0 相对应的丝带。否则,我认为 x 毫无意义。显然也可以更改以填充整个 x 限制。
library(ggplot2)
library(dplyr)
library(patchwork)
pointColours <- c(
A = "#F5736A", B = "#D58D00", C = "#A0A300",
D = "#36B300", E = "#00BC7B", F = "#00BCC2",
G = "#00ADF4", H = "#928DFF", I = "#E568F0",
J = "#808080"
)
set.seed(1)
dfGrid <- data.frame(x = rnorm(10), y = rnorm(10))
## assuming that your color mean something, and this something is represented in your legend,
## you need to map the aesthetic to your data. based on this assumption, this example
df_ribbon <-
dfGrid %>%
mutate(
group = ifelse(y <= 0, pointColours["A"], pointColours["H"]),
## I find it better to define your ymin and ymax outside of ggplot
ymin = ifelse(y <= 0, min(y), 0),
ymax = ifelse(y > 0, max(y), 0)
)
# ls_p <- rep(
rep(list(ggplot(df_ribbon) +
## use fill as an aesthetic
geom_ribbon(aes(x = x, ymin = ymin, ymax = ymax, fill = I(group)), alpha = .5) +
## fake geom_layer
geom_point(aes(x = min(x), y = min(y), color = y), shape = NA, na.rm = T) +
scale_color_gradientn(
colours = rev(colorRampPalette(c("steelblue", "#f7fcfd", "orange"))(5)),
limits = c(0, 10),
name = "Gradient",
guide = guide_colorbar(
frame.colour = "black",
ticks.colour = "black"
)
) +
scale_fill_manual(
values = unname(pointColours),
label = names(pointColours),
## important to add limits
limits = pointColours,
name = "Variable"
) +
theme_void()), 20) %>%
## now merge the legends
patchwork::wrap_plots() +
plot_layout(guide = "collect")