我想使用ggplot2 package并排放置两个图,即相当于par(mfrow=c(1,2))
。
例如,我希望以下两个图表以相同的比例并排显示。
x <- rnorm(100)
eps <- rnorm(100,0,.2)
qplot(x,3*x+eps)
qplot(x,2*x+eps)
我是否需要将它们放在相同的data.frame中?
qplot(displ, hwy, data=mpg, facets = . ~ year) + geom_smooth()
答案 0 :(得分:433)
gridExtra
包中的函数grid.arrange()
将合并多个图表;这就是你如何并排放置两个。
require(gridExtra)
plot1 <- qplot(1)
plot2 <- qplot(1)
grid.arrange(plot1, plot2, ncol=2)
当两个图不是基于相同的数据时,这很有用,例如,如果要在不使用reshape()的情况下绘制不同的变量。
这会将输出绘制为副作用。要将副作用打印到文件,请指定设备驱动程序(例如pdf
,png
等),例如
pdf("foo.pdf")
grid.arrange(plot1, plot2)
dev.off()
或,将arrangeGrob()
与ggsave()
结合使用,
ggsave("foo.pdf", arrangeGrob(plot1, plot2))
这相当于使用par(mfrow = c(1,2))
制作两个不同的图。这不仅节省了安排数据的时间,还需要两个不同的情节。
分面有助于为不同的群体制作类似的地块。这在下面的许多答案中都有所指出,但我想用与上述图相当的例子来强调这种方法。
mydata <- data.frame(myGroup = c('a', 'b'), myX = c(1,1))
qplot(data = mydata,
x = myX,
facets = ~myGroup)
ggplot(data = mydata) +
geom_bar(aes(myX)) +
facet_wrap(~myGroup)
cowplot
中的plot_grid
函数值得签出,以替代grid.arrange
。请参阅下面的answer @ claus-wilke和this vignette的等效方法;但该功能允许基于this vignette更精细地控制绘图位置和大小。
答案 1 :(得分:123)
基于grid.arrange
的解决方案的一个缺点是,它们很难用大多数期刊所需的字母(A,B等)标记图。
我写了cowplot包来解决这个(以及其他一些)问题,特别是函数plot_grid()
:
library(cowplot)
iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
geom_boxplot() + theme_bw()
iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
geom_density(alpha = 0.7) + theme_bw() +
theme(legend.position = c(0.8, 0.8))
plot_grid(iris1, iris2, labels = "AUTO")
plot_grid()
返回的对象是另一个ggplot2对象,您可以像往常一样用ggsave()
保存它:
p <- plot_grid(iris1, iris2, labels = "AUTO")
ggsave("plot.pdf", p)
或者,您可以使用cowplot函数save_plot()
,这是ggsave()
周围的薄包装,可以轻松获得组合图的正确尺寸,例如:
p <- plot_grid(iris1, iris2, labels = "AUTO")
save_plot("plot.pdf", p, ncol = 2)
(ncol = 2
参数告诉save_plot()
并排有两个图,save_plot()
使保存的图像宽两倍。)
有关如何在网格中排列图表的更深入说明,请参阅this vignette.还有一个插图解释如何使用shared legend.
制作图表一个常见的混淆点是cowplot包改变了默认的ggplot2主题。包的行为方式是因为它最初是为内部实验室使用而编写的,我们从不使用默认主题。如果这会导致问题,您可以使用以下三种方法之一来解决它们:
1。为每个情节手动设置主题。我认为总是为每个情节指定一个特定的主题是很好的做法,就像我在上面的例子中使用+ theme_bw()
一样。如果您指定特定主题,则默认主题无关紧要。
2。将默认主题恢复为ggplot2默认值。您可以使用一行代码执行此操作:
theme_set(theme_gray())
3。调用cowplot函数而不附加包。您也不能调用library(cowplot)
或require(cowplot)
,而是通过预先cowplot::
调用cowplot函数。例如,使用ggplot2默认主题的上述示例将变为:
## Commented out, we don't call this
# library(cowplot)
iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
geom_boxplot()
iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
geom_density(alpha = 0.7) +
theme(legend.position = c(0.8, 0.8))
cowplot::plot_grid(iris1, iris2, labels = "AUTO")
更新:从ggplot2 3.0.0开始,可以直接标记图,例如here. 强>
答案 2 :(得分:44)
您可以使用Winston Chang's R cookbook
中的以下multiplot
功能
multiplot(plot1, plot2, cols=2)
multiplot <- function(..., plotlist=NULL, cols) {
require(grid)
# Make a list from the ... arguments and plotlist
plots <- c(list(...), plotlist)
numPlots = length(plots)
# Make the panel
plotCols = cols # Number of columns of plots
plotRows = ceiling(numPlots/plotCols) # Number of rows needed, calculated from # of cols
# Set up the page
grid.newpage()
pushViewport(viewport(layout = grid.layout(plotRows, plotCols)))
vplayout <- function(x, y)
viewport(layout.pos.row = x, layout.pos.col = y)
# Make each plot, in the correct location
for (i in 1:numPlots) {
curRow = ceiling(i/plotCols)
curCol = (i-1) %% plotCols + 1
print(plots[[i]], vp = vplayout(curRow, curCol ))
}
}
答案 3 :(得分:18)
使用patchwork包,您只需使用export default class BookingPage extends React.Component{
constructor() {
super()
this.state = {
step: 1,
availableDates: [
{
"day": "22-01-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "23-01-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "24-01-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "25-01-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "26-01-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "27-01-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "28-01-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "29-01-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "30-01-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "31-01-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "01-02-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
{
"day": "02-02-2018",
"slots" : [
"13.00 - 14.00",
"14.00 - 15.00",
"15.00 - 16.00",
"16.00 - 17.00",
"17.00 - 18.00"
]
},
]
}
}
render() {
return(
<div className="section-booking">
<div className="section-content-wrapper">
<div className="section-content">
<div className="step-indicator">
</div>
<div className="booking-picker">
<BookingSlider dates={this.state.availableDates} />
</div>
</div>
</div>
</div>
)
}
}
class BookingSlider extends React.Component{
constructor(props) {
super(props)
this.state = {
activeItem: null
}
}
onItemActive(item) {
this.setState({activeItem: item})
}
render() {
let items = this.props.dates.map((item, index) => {
return (
<BookingSlots
key={index}
item={item}
onItemActive={this.onItemActive.bind(this)}
active={item === this.state.activeItem}
>
</BookingSlots>
);
});
return(
<div className="booking-date-wrapper">
<ul>
{items}
</ul>
<div>
<select>
<option value="">OPTIONS HERE</option>
</select>
</div>
</div>
)
}
}
class BookingSlots extends React.Component{
constructor(props){
super()
}
setActive() {
this.props.onItemActive(this.props.item);
}
render() {
let item = this.props.item;
return (
<li className={this.props.active ? 'active' : null} onClick={this.setActive.bind(this)}>
{item.day}
</li>
);
}
}
运算符:
+
答案 4 :(得分:17)
是的,您需要妥善安排数据。一种方法是:
X <- data.frame(x=rep(x,2),
y=c(3*x+eps, 2*x+eps),
case=rep(c("first","second"), each=100))
qplot(x, y, data=X, facets = . ~ case) + geom_smooth()
我相信在plyr或重塑中有更好的技巧 - 我仍然没有达到速度 在哈德利的所有这些强大的包装上。
答案 5 :(得分:15)
使用重塑包你可以做这样的事情。
library(ggplot2)
wide <- data.frame(x = rnorm(100), eps = rnorm(100, 0, .2))
wide$first <- with(wide, 3 * x + eps)
wide$second <- with(wide, 2 * x + eps)
long <- melt(wide, id.vars = c("x", "eps"))
ggplot(long, aes(x = x, y = value)) + geom_smooth() + geom_point() + facet_grid(.~ variable)
答案 6 :(得分:10)
更新:这个答案非常陈旧。 gridExtra::grid.arrange()
现在是推荐的方法。
我把它留在这里以防它可能有用。
Stephen Turner posted the arrange()
function on Getting Genetics Done blog(见申请说明的帖子)
vp.layout <- function(x, y) viewport(layout.pos.row=x, layout.pos.col=y)
arrange <- function(..., nrow=NULL, ncol=NULL, as.table=FALSE) {
dots <- list(...)
n <- length(dots)
if(is.null(nrow) & is.null(ncol)) { nrow = floor(n/2) ; ncol = ceiling(n/nrow)}
if(is.null(nrow)) { nrow = ceiling(n/ncol)}
if(is.null(ncol)) { ncol = ceiling(n/nrow)}
## NOTE see n2mfrow in grDevices for possible alternative
grid.newpage()
pushViewport(viewport(layout=grid.layout(nrow,ncol) ) )
ii.p <- 1
for(ii.row in seq(1, nrow)){
ii.table.row <- ii.row
if(as.table) {ii.table.row <- nrow - ii.table.row + 1}
for(ii.col in seq(1, ncol)){
ii.table <- ii.p
if(ii.p > n) break
print(dots[[ii.table]], vp=vp.layout(ii.table.row, ii.col))
ii.p <- ii.p + 1
}
}
}
答案 7 :(得分:9)
ggplot2基于网格图形,它提供了一种不同的系统,用于在页面上排列图形。 tick
命令没有直接等效命令,因为网格对象(称为 grobs )不一定立即绘制,但可以作为常规R对象存储和操作在转换为图形输出之前。这比绘制基本图形的现在模型具有更大的灵活性,但策略必然略有不同。
我写了par(mfrow...)
以提供尽可能接近grid.arrange()
的简单界面。最简单的形式是代码:
par(mfrow)
this vignette详细介绍了更多选项。
一个常见的抱怨是情节不一定是对齐的,例如:当他们有不同大小的轴标签时,这是设计的:library(ggplot2)
x <- rnorm(100)
eps <- rnorm(100,0,.2)
p1 <- qplot(x,3*x+eps)
p2 <- qplot(x,2*x+eps)
library(gridExtra)
grid.arrange(p1, p2, ncol = 2)
不会尝试特殊情况的ggplot2对象,并将它们平等地对待其他grob(例如,格子图)。它只是将凹凸放置在矩形布局中。
对于ggplot2对象的特殊情况,我编写了另一个函数grid.arrange
,它具有类似的界面,它试图对齐绘图面板(包括刻面图)并尝试在用户定义时尊重纵横比
ggarrange
这两个功能都与library(egg)
ggarrange(p1, p2, ncol = 2)
兼容。有关不同选项和一些历史背景的一般概述,this vignette offers additional information。
答案 8 :(得分:6)
还有multipanelfigure package值得一提。另请参见此answer。
library(ggplot2)
theme_set(theme_bw())
q1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
q2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
q3 <- ggplot(mtcars) + geom_smooth(aes(disp, qsec))
q4 <- ggplot(mtcars) + geom_bar(aes(carb))
library(magrittr)
library(multipanelfigure)
figure1 <- multi_panel_figure(columns = 2, rows = 2, panel_label_type = "none")
# show the layout
figure1
figure1 %<>%
fill_panel(q1, column = 1, row = 1) %<>%
fill_panel(q2, column = 2, row = 1) %<>%
fill_panel(q3, column = 1, row = 2) %<>%
fill_panel(q4, column = 2, row = 2)
figure1
# complex layout
figure2 <- multi_panel_figure(columns = 3, rows = 3, panel_label_type = "upper-roman")
figure2
figure2 %<>%
fill_panel(q1, column = 1:2, row = 1) %<>%
fill_panel(q2, column = 3, row = 1) %<>%
fill_panel(q3, column = 1, row = 2) %<>%
fill_panel(q4, column = 2:3, row = 2:3)
figure2
由reprex package(v0.2.0.9000)于2018-07-06创建。
答案 9 :(得分:4)
使用tidyverse
:
x <- rnorm(100)
eps <- rnorm(100,0,.2)
df <- data.frame(x, eps) %>%
mutate(p1 = 3*x+eps, p2 = 2*x+eps) %>%
tidyr::gather("plot", "value", 3:4) %>%
ggplot(aes(x = x , y = value)) +
geom_point() +
geom_smooth() +
facet_wrap(~plot, ncol =2)
df
答案 10 :(得分:1)
如果您想使用循环绘制多个ggplot图(例如,在此处询问:Creating multiple plots in ggplot with different Y-axis values using a loop),上述解决方案可能效率不高,这是分析未知(或大型)数据集的理想步骤(例如,当您想要绘制数据集中所有变量的计数时)。
下面的代码显示了如何使用上面提到的&#39; multiplot()&#39;,其来源位于:http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2):
plotAllCounts <- function (dt){
plots <- list();
for(i in 1:ncol(dt)) {
strX = names(dt)[i]
print(sprintf("%i: strX = %s", i, strX))
plots[[i]] <- ggplot(dt) + xlab(strX) +
geom_point(aes_string(strX),stat="count")
}
columnsToPlot <- floor(sqrt(ncol(dt)))
multiplot(plotlist = plots, cols = columnsToPlot)
}
现在运行该函数 - 获取在一页上使用ggplot打印的所有变量的计数
dt = ggplot2::diamonds
plotAllCounts(dt)
需要注意的一点是:
使用aes(get(strX))
,在使用ggplot
时通常会在循环中使用,在上面的代码而不是aes_string(strX)
中将不会绘制所需的绘图。相反,它会多次绘制最后一个情节。我还没弄清楚原因 - 可能需要aes
和aes_string
调用ggplot
。
否则,希望您能找到有用的功能。
答案 11 :(得分:0)
cowplot
包以适合发布的方式为您提供了一种很好的方法。
x <- rnorm(100)
eps <- rnorm(100,0,.2)
A = qplot(x,3*x+eps, geom = c("point", "smooth"))+theme_gray()
B = qplot(x,2*x+eps, geom = c("point", "smooth"))+theme_gray()
cowplot::plot_grid(A, B, labels = c("A", "B"), align = "v")
答案 12 :(得分:0)
根据我的经验,如果您试图循环生成图,则gridExtra:grid.arrange可以完美地工作。
短代码段:
gridExtra::grid.arrange(plot1, plot2, ncol = 2)