我想要绘制几个不同的类别。这些是不同的类别,每个类别都有自己的标签集,但在文档中将它们组合在一起是有意义的。下面给出了一些简单的堆积条形图示例:
df <- data.frame(x=c("a", "b", "c"),
y=c("happy", "sad", "ambivalent about life"))
ggplot(df, aes(x=factor(0), fill=x)) + geom_bar()
ggplot(df, aes(x=factor(0), fill=y)) + geom_bar()
问题在于,对于不同的标签,图例具有不同的宽度,这意味着图表具有不同的宽度,如果我制作表格或\subfigure
元素,会导致看起来有点傻。我该如何解决这个问题?
有没有办法明确设置绘图或图例的宽度(绝对或相对)?
答案 0 :(得分:36)
修改:github提供egg
套餐非常简单
# install.package(devtools)
# devtools::install_github("baptiste/egg")
library(egg)
p1 <- ggplot(data.frame(x=c("a","b","c"),
y=c("happy","sad","ambivalent about life")),
aes(x=factor(0),fill=x)) +
geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),
y=c("happy","sad","ambivalent about life")),
aes(x=factor(0),fill=y)) +
geom_bar()
ggarrange(p1,p2, ncol = 1)
原始过时使用ggplot2 2.2.1
这是一个使用gtable
包中的函数的解决方案,并侧重于图例框的宽度。 (可以找到更通用的解决方案here。)
library(ggplot2)
library(gtable)
library(grid)
library(gridExtra)
# Your plots
p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar()
# Get the gtables
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# Set the widths
gA$widths <- gB$widths
# Arrange the two charts.
# The legend boxes are centered
grid.newpage()
grid.arrange(gA, gB, nrow = 2)
如果另外,传奇框需要左对齐,并借用@Julius编写的here中的一些代码
p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar()
# Get the widths
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# The parts that differs in width
leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm")
leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm")
# Set the widths
gA$widths <- gB$widths
# Add an empty column of "abs(diff(widths)) mm" width on the right of
# legend box for gA (the smaller legend box)
gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm"))
# Arrange the two charts
grid.newpage()
grid.arrange(gA, gB, nrow = 2)
替代解决方案 rbind
包中有cbind
和gtable
个函数,用于将grob组合到一个grob中。对于此处的图表,宽度应使用size = "max"
设置,但CRAN版本的gtable
会引发错误。
一个选项:显而易见的是,第二个图中的图例更宽。因此,请使用size = "last"
选项。
# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# Combine the plots
g = rbind(gA, gB, size = "last")
# Draw it
grid.newpage()
grid.draw(g)
左对齐的传说:
# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# The parts that differs in width
leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm")
leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm")
# Add an empty column of "abs(diff(widths)) mm" width on the right of
# legend box for gA (the smaller legend box)
gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm"))
# Combine the plots
g = rbind(gA, gB, size = "last")
# Draw it
grid.newpage()
grid.draw(g)
第二种选择是使用Baptiste的rbind
包中的gridExtra
# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# Combine the plots
g = gridExtra::rbind.gtable(gA, gB, size = "max")
# Draw it
grid.newpage()
grid.draw(g)
左对齐的传说:
# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# The parts that differs in width
leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm")
leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm")
# Add an empty column of "abs(diff(widths)) mm" width on the right of
# legend box for gA (the smaller legend box)
gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm"))
# Combine the plots
g = gridExtra::rbind.gtable(gA, gB, size = "max")
# Draw it
grid.newpage()
grid.draw(g)
答案 1 :(得分:8)
正如@hadley建议的那样,rbind.gtable
应该能够处理这个问题,
grid.draw(rbind(ggplotGrob(p1), ggplotGrob(p2), size="last"))
但是,布局宽度理想情况下应为size="max"
,doesn't cope well具有某些类型的网格单元。
答案 2 :(得分:8)
cowplot
包也有align_plots
功能用于此目的(输出未显示),
both2 <- align_plots(p1, p2, align="hv", axis="tblr")
p1x <- ggdraw(both2[[1]])
p2x <- ggdraw(both2[[2]])
save_plot("cow1.png", p1x)
save_plot("cow2.png", p2x)
以及plot_grid
将图表保存到同一个文件中。
library(cowplot)
both <- plot_grid(p1, p2, ncol=1, labels = c("A", "B"), align = "v")
save_plot("cow.png", both)
答案 3 :(得分:2)
只是偶然,我注意到他在评论中提出的Arun解决方案尚未被提及。我觉得他简单而有效的方法非常值得一试。
Arun建议将图例移到顶部或底部:
ggplot(df, aes(x=factor(0), fill=x)) + geom_bar() + theme(legend.position = "bottom")
ggplot(df, aes(x=factor(0), fill=y)) + geom_bar() + theme(legend.position = "bottom")
现在,图表的宽度与请求的宽度相同。此外,两种情况下的绘图区域大小相同。
如果有更多因素甚至更长的标签,可能需要使用图例,例如,以两行或更多行显示图例。 theme()
和guide_legend()
有几个参数来控制ggplot2
中图例的位置和外观。
答案 4 :(得分:1)
我根据@Sandy的答案创建了一个小功能。
same.size.ggplot <- function(vector.string.graph, # a vector of strings which correspond to Robject ggplot graphs
reference.string.graph, # a string of a Robject ggplot graphs where height and/or height will be taken for reference
width = T, # if you wanna adapat only the width
height = F # if you wanna adapat only the height
) {
# example: same.size.ggplot(p0rep(c("a", "b"), thre), "a30")
which(vector.string.graph %in% reference.string.graph)
newref <- ggplotGrob(get(reference.string.graph))
ref.width <- newref$widths
ref.height <- newref$heights
assign(reference.string.graph, newref, env = parent.frame(1))
for(i in seq_along(vector.string.graph)) {
if(vector.string.graph[i] != reference.string.graph) {
new <- ggplotGrob(get(vector.string.graph[i]))
if( width ) {
new$widths <- ref.width
}
if( height ) {
new$heights <- ref.height
}
assign(vector.string.graph[i], new, env = parent.frame(1))
}
}
}
p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar()
p3 <- ggplot(data.frame(x=c("a","b","c"),y=c("Crazy happy","sad","Just follow the flow")),aes(x=factor(0),fill=y)) + geom_bar()
grid.arrange(p1, p2, p3, ncol = 1)
same.size.ggplot(c("p1", "p2", "p3"), "p2") # same as same.size.ggplot(c("p2", "p3"), "p1")
grid.arrange(p1, p2, p3, ncol = 1)
之前
之后