在 ggplot2 中为每个 facet_wrap 网格放置一个图例
Posted
技术标签:
【中文标题】在 ggplot2 中为每个 facet_wrap 网格放置一个图例【英文标题】:Place a legend for each facet_wrap grid in ggplot2 【发布时间】:2013-01-28 05:32:52 【问题描述】:我有这个数据框:
Date Server FileSystem PercentUsed
1 12/1/2011 A / 60
2 1/2/2012 A /var 50
3 2/1/2012 A tmp 90
4 2/10/2012 A /db 86
5 2/13/2012 A /app 90
6 12/1/2011 B C: 67
7 1/2/2012 B D: 67
8 2/1/2012 B F: 34
9 2/10/2012 B /restore 89
10 2/13/2012 B G: 56
11 12/1/2011 C / 90
12 1/2/2012 C /tmp 78
13 2/1/2012 C /data 67
14 2/10/2012 C /Storage 34
15 2/13/2012 C /database 12
dput(x)
structure(list(Date = structure(c(2L, 1L, 3L, 4L, 5L, 2L, 1L,
3L, 4L, 5L, 2L, 1L, 3L, 4L, 5L), .Label = c("1/2/2012", "12/1/2011",
"2/1/2012", "2/10/2012", "2/13/2012"), class = "factor"), Server = structure(c(1L,
1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L), .Label = c("A",
"B", "C"), class = "factor"), FileSystem = structure(c(1L, 9L,
14L, 5L, 2L, 10L, 11L, 12L, 6L, 13L, 1L, 8L, 3L, 7L, 4L), .Label = c("/",
"/app", "/data", "/database", "/db", "/restore", "/Storage",
"/tmp", "/var", "C:", "D:", "F:", "G:", "tmp"), class = "factor"),
PercentUsed = c(60L, 50L, 90L, 86L, 90L, 67L, 67L, 34L, 89L,
56L, 90L, 78L, 67L, 34L, 12L)), .Names = c("Date", "Server",
"FileSystem", "PercentUsed"), class = "data.frame", row.names = c(NA,
-15L))
我想在每个facet_wrap
网格旁边放一个图例,它自己的FileSystem
:
当我这样做时,它会将图例放在所有FileSystem
的情节一侧。是否可以将FileSystem
属于每个网格旁边的每个服务器?
ggplot(x, aes(Date, PercentUsed, group=1, colour=FileSystem)) +
geom_jitter(size=0.5) + geom_smooth(method="loess", se=T) +
facet_wrap(~Server, ncol=1)
【问题讨论】:
【参考方案1】:最好的方法是使用 gridExtra 包:
library(gridExtra)
xs <- split(x,f = x$Server)
p1 <- ggplot(xs$A,aes(x = Date,y = PercentUsed,group = 1,colour = FileSystem)) +
geom_jitter(size=0.5) +
geom_smooth(method="loess", se=T) +
facet_wrap(~Server, ncol=1)
p2 <- p1 %+% xs$B
p3 <- p1 %+% xs$C
grid.arrange(p1,p2,p3)
【讨论】:
我应该注意到您在geom_jitter
中提出的观点非常小,我不知道为什么,但我保持原样。点在那里,但很难看到。
我对@987654324@ 运算符有点感兴趣。你能解释一下它的作用吗?
@Legend 这是一种使 ggplot 对象“模块化”的方法,因为您可以使用它来简单地放入新的数据框,但使用之前绘图中的所有相同几何规范。当然,只有当列名全部匹配,并且你没有在其他层使用任何 other 数据框时,它才会起作用。
+1 感谢您的及时回复。这是重用对象的绝佳方式!
@joran 如何让网格中的每个图占据相等的空间,以便它们的 x 刻度对齐?【参考方案2】:
嗯,@joran 打败了我(我的 gridExtra
已经过时了,但我花了 10 分钟才意识到这一点)。这是一个类似的解决方案,但这个解决方案通常按Server
中的级别为猫剥皮。
library(gridExtra)
out <- by(data = x, INDICES = x$Server, FUN = function(m)
m <- droplevels(m)
m <- ggplot(m, aes(Date, PercentUsed, group=1, colour = FileSystem)) +
geom_jitter(size=2) + geom_smooth(method="loess", se=T)
)
do.call(grid.arrange, out)
# If you want to supply the parameters to grid.arrange
do.call(grid.arrange, c(out, ncol=3))
【讨论】:
非常好。我没有意识到droplevels()
有一个data.frame
s 的方法。这很方便!
有没有一种简洁的方法来强制对齐,即保持绘图区域宽度相同?规定图例宽度?
@mlt 考虑将图例移动到第一个图的顶部并将其从其余部分中删除。
确实,我同时将所有图例移到了顶部。我不能使用单个图例,因为它们每个情节都是独一无二的。虽然很高兴知道是否有规定宽度的方法。
@mlt 考虑提出一个新问题,尽管 AFAIK,但这是不可能的(尽管可以定义边距)。【参考方案3】:
我们可以不使用构面,而是为每个组创建一个绘图列表,然后使用 cowplot::plot_grid 进行绘图。每个人都有自己的传奇:
# make list of plots
ggList <- lapply(split(x, x$Server), function(i)
ggplot(i, aes(Date, PercentUsed, group = 1, colour = FileSystem)) +
geom_jitter(size = 2) +
geom_smooth(method = "loess", se = TRUE))
# plot as grid in 1 columns
cowplot::plot_grid(plotlist = ggList, ncol = 1,
align = 'v', labels = levels(x$Server))
按照@Axeman 的建议,我们可以使用facet_grid(~Server)
添加标签,而不是labels = levels(x$Server)
。
【讨论】:
太棒了。如果您希望显示灰色刻面条,您仍然可以添加+ facet_grid(~Server)
。在plot_grid
中使用align = 'v'
会得到更好看的结果。
@Axeman 关于“v”的好点,谢谢,更新了。我想避免使用 facet,所以用 label 代替。【参考方案4】:
我喜欢@joran 的回答,并以他们的代码为起点提供了几个选项。 这两个选项都解决了未对齐方面的问题。
方面之外的图例
如果您为图例项选择等宽字体,您可以使用str_pad
在所有图例项的右侧添加填充,强制每个项的长度保持一致。
如果您愿意使用等宽字体,这是一种快速解决方法。
library(ggplot2)
library(dplyr)
library(gridExtra)
library(stringr)
l <- max(nchar(as.character(x$FileSystem)))
mylevels <- as.character(levels(x$FileSystem))
mylevels <- str_pad(mylevels, width = l, side = "right", pad = " ")
x <- mutate(x, FileSystem = factor(str_pad(FileSystem, width = l, side = "right", pad = " "),
levels = mylevels))
windowsFonts("Lucida Sans Typewriter" = windowsFont("Lucida Sans Typewriter"))
xs <- split(x,f = x$Server)
p1 <- ggplot(xs$A,aes(x = Date,y = PercentUsed,group = 1,colour = FileSystem)) +
geom_jitter(size=0.5) +
geom_smooth(method="loess", se=T) +
facet_wrap(~Server, ncol=1) +
theme(legend.text = element_text(family = "Lucida Sans Typewriter"))
p2 <- p1 %+% xs$B
p3 <- p1 %+% xs$C
grid.arrange(p1,p2,p3)
方面内的图例
如果您不介意每个 facet 中的图例,您可以使用 scale
调用中的“expand”参数为每个 facet 添加额外的空间:
library(lubridate)
x <- mutate(x, Date = as.Date(as.character(Date), format = "%m/%d/%Y"))
xs <- split(x,f = x$Server)
p1 <- ggplot(xs$A,aes(x = Date,y = PercentUsed,group = 1,colour = FileSystem)) +
geom_jitter(size=0.5) +
scale_x_date(expand = expansion(add = c(5, 20)),
date_labels = "%d-%m-%Y") +
geom_smooth(method="loess", se=T) +
facet_wrap(~Server, ncol=1) +
theme_bw() +
theme(legend.position = c(0.9, 0.5))
p2 <- p1 %+% xs$B
p3 <- p1 %+% xs$C
grid.arrange(p1,p2,p3)
【讨论】:
【参考方案5】:现在游戏中除了gridExtra
和cowplot
之外,还有patchwork
。因此,您可以执行以下操作:
require(ggplot2)
require(patchwork)
# split
dfs = split(df, f = df$Server)
# apply ggplot function and write to list
gg_l = lapply(dfs, function(x)
ggplot(x, aes(x = Date,y = PercentUsed, group = 1, colour = FileSystem)) +
geom_jitter(size = 0.5) +
geom_smooth(method = "loess", se = TRUE) +
facet_wrap(~ Server, ncol = 1)
)
# patchwork
wrap_plots(gg_l, ncol = 1)
您也可以手动组合图,看看here。我将 OP 的数据用于df
。
【讨论】:
以上是关于在 ggplot2 中为每个 facet_wrap 网格放置一个图例的主要内容,如果未能解决你的问题,请参考以下文章
在 R 中使用带有 facet_wrap 的 ggplot2 显示多个轴标签
R语言ggplot2可视化分面图(facet,facet_wrap): 不同分面配置不同的数据范围自定义每个分面的轴数据格式化形式及数据范围
ggplot2:将各个facet_wrap构面另存为单独的图对象
在 ggplot2 的 facet-grid/facet_wrap 中调整面板的相对空间
R语言ggplot2可视化分面图(faceting)可视化分面条形图(facet_wrap bar plot)使用strip.text函数自定义分面图每个分面标题条带strip的大小(cutomi