在R中创建具有相同轴的多个散点图
我试图在R中以2 x 2的排列绘制四个散点图(我实际上是通过rpy2绘制的)。我希望每个图的纵横比都是1,但比例也相同,所以所有子图的X和Y记号都相同,这样就可以进行比较了。我试着用在R中创建具有相同轴的多个散点图,r,graphics,plot,rpy2,R,Graphics,Plot,Rpy2,我试图在R中以2 x 2的排列绘制四个散点图(我实际上是通过rpy2绘制的)。我希望每个图的纵横比都是1,但比例也相同,所以所有子图的X和Y记号都相同,这样就可以进行比较了。我试着用par: par(mfrow=c(2,2)) # scatter 1 plot(x, y, "p", asp=1) # scatter 2 plot(a, b, "p", asp=1) # ... 编辑: 下面是我现在所拥有的一个直接例子: > par(mfrow=c(2,2)) > for (n in
par
:
par(mfrow=c(2,2))
# scatter 1
plot(x, y, "p", asp=1)
# scatter 2
plot(a, b, "p", asp=1)
# ...
编辑:
下面是我现在所拥有的一个直接例子:
> par(mfrow=c(2,2))
> for (n in 1:4) { plot(iris$Petal.Width, rnorm(length(iris$Petal.Width)), "p", asp=1) }
它创建了正确的散射类型,但具有不同的比例。在对上述plot
的每次调用中将ylim
和xlim
设置为相同并不能解决问题。在每个轴上仍然会有非常不同的记号和记号号,这使得不必要地难以解释散布。我希望X轴和Y轴相同。例如,这:
对于(1:4中的n){plot(iris$Petal.Width,rnorm(length(iris$Petal.Width)),“p”,asp=1,xlim=c(-4,6),ylim=c(-2,4))}
生成错误的结果:
确保在所有子批次中使用相同轴的最佳方法是什么
我所寻找的只是一个类似于axis=same
的参数,或者类似于par(mfrow=…)
的参数,这听起来像是lattice
的默认行为,以使轴在每个子批次中共享和相同
lgautier给出了带有ggplot的漂亮代码,但它需要事先知道轴。我想澄清的是,我希望避免迭代每个子批次中的数据,并计算出要绘制的正确刻度。如果必须事先知道这一点,那么ggplot解决方案比仅使用plot
和显式绘制要复杂得多
研究给出了一个晶格的解。这看起来与我想要的最接近,因为您不必显式地预计算每个散射的刻度位置,但是作为一个新用户,我无法弄清楚如何使晶格看起来像一个普通的绘图。我得到的最接近的结果是:
> xyplot(y~x|group, data =dat, type='p',
between =list(y=2,x=2),
layout=c(2,2), aspect=1,
scales =list(y = list(relation='same'), alternating=FALSE))
这将产生:
我怎样才能让它看起来像R底座?我不希望这些组字幕出现在每个子批次的顶部,或者在每个散点的顶部和右侧挂着未标记的记号,我只希望散点的每个x和y都被标记。我也不是在寻找X和Y的共享标签——每个子地块都有自己的X和Y标签。轴标签在每个散射中都必须相同,尽管这里选择的数据没有意义
除非有一种简单的方法使网格看起来像R基,否则答案似乎是,如果不预先计算每个子批次中每个勾号的确切位置,就无法完成我在R中尝试做的事情(令人惊讶),这需要提前迭代数据 使用lattice
和ggplot2
您需要重塑数据。例如:
创建4个数据帧(x=x1,y=y1)
为每个data.frame添加组列,组=1,2
r按一次键入4 data.frame
下面是一个使用lattice
dat <- data.frame(x = rep(sample(1:100,size=10),4),
y = rep(rnorm(40)),
group = rep(1:4,each =10))
xyplot(y~x|group, ## conditional formula to get 4 panels
data =dat, ## data
type='l', ## line type for plot
groups=group, ## group ti get differents colors
layout=c(2,2)) ## equivalent to par or layout
编辑
晶格绘图有大量参数
允许控制绘图的许多细节的函数,例如我自定义:
用于条带标签和标题的文本
轴标记标签的大小和位置
面板的列和行之间的间隙大小
xyplot(y~x|group, data =dat, type='l',groups=group,
between =list(y=2,x=2),
layout=c(2,2),
strip = myStrip,
scales =list(y = list(relation='same',alternating= c(3,3))))
在哪里
myStrip <- function(var.name,which.panel, which.given,...) {
var.name <- paste(var.name ,which.panel)
strip.default(which.given,which.panel,var.name,...)
}
ggplot2在开始时可能具有最高的美观/简单比率
rpy2的示例:
from rpy2.robjects.lib import ggplot2
from rpy2.robjects import r, Formula
iris = r('iris')
p = ggplot2.ggplot(iris) + \
ggplot2.geom_point(ggplot2.aes_string(x="Sepal.Length", y="Sepal.Width")) + \
ggplot2.facet_wrap(Formula('~ Species'), ncol=2, nrow = 2) + \
ggplot2.GBaseObject(r('ggplot2::coord_fixed')()) # aspect ratio
# coord_fixed() missing from the interface,
# therefore the hack. This should be fixed in rpy2-2.3.3
p.plot()
阅读前面答案的评论,我明白你的意思可能是完全不同的
情节。在R的默认绘图系统中,par(mfrow(c(2,2))
或par(mfcol(c(2,2))
将是最简单的方法,并通过通常的固定方式保持纵横比、轴范围和记号一致
在R中绘制最灵活的系统可能是grid
。它并不像看上去那么糟糕,可以将其想象为场景图。使用rpy2、ggplot2和grid:
from rpy2.robjects.vectors import FloatVector
from rpy2.robjects.lib import grid
grid.newpage()
lt = grid.layout(2,2) # 2x2 layout
vp = grid.viewport(layout = lt)
vp.push()
# limits for axes and tickmarks have to be known or computed beforehand
xlims = FloatVector((4, 9))
xbreaks = FloatVector((4,6,8))
ylims = FloatVector((-3, 3))
ybreaks = FloatVector((-2, 0, 2))
# first panel
vp_p = grid.viewport(**{'layout.pos.col':1, 'layout.pos.row': 1})
p = ggplot2.ggplot(iris) + \
ggplot2.geom_point(ggplot2.aes_string(x="Sepal.Length",
y="rnorm(nrow(iris))")) + \
ggplot2.GBaseObject(r('ggplot2::coord_fixed')()) + \
ggplot2.scale_x_continuous(limits = xlims, breaks = xbreaks) + \
ggplot2.scale_y_continuous(limits = ylims, breaks = ybreaks)
p.plot(vp = vp_p)
# third panel
vp_p = grid.viewport(**{'layout.pos.col':2, 'layout.pos.row': 2})
p = ggplot2.ggplot(iris) + \
ggplot2.geom_point(ggplot2.aes_string(x="Sepal.Length",
y="rnorm(nrow(iris))")) + \
ggplot2.GBaseObject(r('ggplot2::coord_fixed')()) + \
ggplot2.scale_x_continuous(limits = xlims, breaks = xbreaks) + \
ggplot2.scale_y_continuous(limits = ylims, breaks = ybreaks)
p.plot(vp = vp_p)
在ggplot2和网格文档中以及之后有更多文档。虽然已经选择了答案,但该答案使用的是ggplot
而不是OP想要的基R。虽然ggplot
非常适合快速打印,但对于发布,您通常希望对打印进行更好的控制<代码>ggplot
提供。这就是基本绘图的优势所在
我建议阅读可以巧妙使用par
的魔法,以及其他一些不错的技巧,比如使用layout()
和split.screen()
根据他的解释,我得出了以下结论:
# Assume that you are starting with some data,
# rather than generating it on the fly
data_mat <- matrix(rnorm(600), nrow=4, ncol=150)
x_val <- iris$Petal.Width
Ylim <- c(-3, 3)
Xlim <- c(0, 2.5)
# You'll need to make the ylimits the same if you want to share axes
par(mfrow=c(2,2))
par(mar=c(0,0,0,0), oma=c(4,4,0.5,0.5))
par(mgp=c(1, 0.6, 0.5))
for (n in 1:4) {
plot(x_val, data_mat[n,], "p", asp=1, axes=FALSE, ylim=Ylim, xlim=Xlim)
box()
if(n %in% c(1,3)){
axis(2, at=seq(Ylim[1]+0.5, Ylim[2]-0.5, by=0.5))
}
if(n %in% c(3,4)){
axis(1, at=seq(min(x_val), max(x_val), by=0.1))
}
}
#假设您从一些数据开始,
#而不是动态生成
data_mat如果您想要普通比例,则使用ggplot2或晶格和镶嵌面或网格(分别)会容易得多。我对任何一个都很感兴趣,尤其是lattice,因为ggplot2对我来说可能太复杂了。好吧,计算轴的记号和范围是lattice或ggplot2在没有引擎盖的情况下所做的。似乎您正在寻找一个解决方案,该解决方案会在生成新的绘图时更新以前的绘图,因此记号和坐标范围是相同的。这可以用网格来实现,但前面计算刻度线和范围的工作量似乎要小得多。@lgautier:那么在R base中进行预计算的标准方法是什么呢?正如我在编辑设置xlim/ylim中所写的那样,这是不够的。此外,它不必是实时更新的-我很乐意将所有数据放在r矩阵或数据帧中的所有分散首先当查看您提供的带有r基本图形的图形时,对我来说,刻度线在绘图中看起来非常相同。我通常也对理想解决方案应该具备的要求感到困惑。可能模型会更有用。谢谢,但此布局
from rpy2.robjects.vectors import FloatVector
from rpy2.robjects.lib import grid
grid.newpage()
lt = grid.layout(2,2) # 2x2 layout
vp = grid.viewport(layout = lt)
vp.push()
# limits for axes and tickmarks have to be known or computed beforehand
xlims = FloatVector((4, 9))
xbreaks = FloatVector((4,6,8))
ylims = FloatVector((-3, 3))
ybreaks = FloatVector((-2, 0, 2))
# first panel
vp_p = grid.viewport(**{'layout.pos.col':1, 'layout.pos.row': 1})
p = ggplot2.ggplot(iris) + \
ggplot2.geom_point(ggplot2.aes_string(x="Sepal.Length",
y="rnorm(nrow(iris))")) + \
ggplot2.GBaseObject(r('ggplot2::coord_fixed')()) + \
ggplot2.scale_x_continuous(limits = xlims, breaks = xbreaks) + \
ggplot2.scale_y_continuous(limits = ylims, breaks = ybreaks)
p.plot(vp = vp_p)
# third panel
vp_p = grid.viewport(**{'layout.pos.col':2, 'layout.pos.row': 2})
p = ggplot2.ggplot(iris) + \
ggplot2.geom_point(ggplot2.aes_string(x="Sepal.Length",
y="rnorm(nrow(iris))")) + \
ggplot2.GBaseObject(r('ggplot2::coord_fixed')()) + \
ggplot2.scale_x_continuous(limits = xlims, breaks = xbreaks) + \
ggplot2.scale_y_continuous(limits = ylims, breaks = ybreaks)
p.plot(vp = vp_p)
# Assume that you are starting with some data,
# rather than generating it on the fly
data_mat <- matrix(rnorm(600), nrow=4, ncol=150)
x_val <- iris$Petal.Width
Ylim <- c(-3, 3)
Xlim <- c(0, 2.5)
# You'll need to make the ylimits the same if you want to share axes
par(mfrow=c(2,2))
par(mar=c(0,0,0,0), oma=c(4,4,0.5,0.5))
par(mgp=c(1, 0.6, 0.5))
for (n in 1:4) {
plot(x_val, data_mat[n,], "p", asp=1, axes=FALSE, ylim=Ylim, xlim=Xlim)
box()
if(n %in% c(1,3)){
axis(2, at=seq(Ylim[1]+0.5, Ylim[2]-0.5, by=0.5))
}
if(n %in% c(3,4)){
axis(1, at=seq(min(x_val), max(x_val), by=0.1))
}
}