在R中xlim/ylim行为让人困惑

12

R-3.1.1,Win7x64

你好,我有一些数据,其中两个变量被测量,X的取值范围为0至70,Y的取值范围为0至100。我想制作一个简单的散点图。该散点图应该被尺寸化,使得x轴(从0到70)的大小是y轴(从0到100)的0.7倍。

我使用以下代码:

plot.new()
plot(0, 0, asp = 1, xlim = c(0, 70), ylim = c(0, 100), xlab = "", ylab = "", type = "n")

我很惊讶地看到这个代码生成了下面的图形:enter image description here

有两件事情不符合我的预期:1)x轴和y轴并没有按照xlim和ylim的限制范围展示。(为什么会这样?) 2)图形几乎是正方形的。

我可以手动调整图形大小,通过调整R窗口或在使用代码之前调整Rstudio窗口大小,但这并不可行,因为我需要绘制大量图形,其中许多具有不同的xlim和ylim大小,并且这些图形后来需要插入预先格式化的报告中(这就是为什么它们需要符合这些精确布局要求)。 我也尝试过使用

dev.new(width = 7, height = 10)

但这也没有帮助。

我的问题是: 1)我如何“强制”图像受限于传递给函数的确切xlim和ylim范围? 2)如何生成一个具有精确相对尺寸的图像(x轴宽度为y轴长度的0.7倍)?

3个回答

11

asp将覆盖xlimylim设置,如果您查看plot的帮助文档,则aspplot.window的帮助文档中进行了讨论:

 

如果asp是有限正值,则设置窗口使得x方向上的一个数据单位的长度等于asp * y方向上的一个数据单位。

    

请注意,在这种情况下,par("usr")不再由par("xaxs")等决定,而是由asp和设备的纵横比决定。(运行下面的示例后,查看交互式调整绘图设备会发生什么!)

    

特殊情况asp == 1生成距离屏幕上的点之间的准确距离的图。使用asp > 1的值可以在使用纬度和经度时生成更准确的地图。

如@mr.joshuagordon所指出,您可以使用pdf(或者如果您想要位图输出则使用pngjpeg)函数,并调整尺寸以获得所需的纵横比,同时从plot中删除asp参数,以便您可以设置xlimylim值。

另一个选择是切换到ggplot2,它使得轴限制和纵横比分别设置变得容易:

library(ggplot2) 

# Some fake data
dat = data.frame(x=c(2,30,50), y=c(10, 60, 90))

# 1 y-unit = 1 x-unit, so the plot area is not square
ggplot(dat, aes(x,y)) +
  geom_point() +
  scale_x_continuous(limits=c(0,70)) +
  scale_y_continuous(limits=c(0,100)) + 
  coord_fixed(ratio=1)  

# 1 y-unit = 0.7 * 1 x-unit, so the plot is square, but the physical distance
# of each x-unit and y-unit are no longer the same
ggplot(dat, aes(x,y)) +
  geom_point() +
  scale_x_continuous(limits=c(0,70)) +
  scale_y_continuous(limits=c(0,100)) + 
  coord_fixed(ratio=70/100)  

更新:以下是如何在基础图形中独立控制xlimylim和纵横比的方法: 使用图形参数pin而不是asp来设置绘图区域的物理尺寸。此设置不会影响xlimylim的名义值,但会改变1个x单位和1个y单位的物理距离度量。以下是一些示例:

示例1:我们将在一个PDF页面上创建两个面板,每个面板具有不同的纵横比:

# Create a 12" x 6" pdf graphics device 
pdf("test.pdf", width=12, height=6)

# Divide graphics device into two regions, each of which will contain a plot
par(mfrow=c(1,2))

# Left Panel: 5" x 5" plot area (plot region is square, so 1 y-unit = 
# 0.7 * 1 x-unit in terms of physical distance in the plot region)
par(pin=c(5,5))
plot(0, 0, xlim = c(0, 70), ylim = c(0, 100), xlab = "", ylab = "", 
     type = "n",main='par(pin=c(5,5)')

# Right Panel: 0.7*5" x 5" plot area (so 1 x-unit = 1 y-unit 
# in terms of physical distance in the plot region)
par(pin=c(0.7*5,5))
plot(0, 0, xlim = c(0, 70), ylim = c(0, 100), xlab = "", ylab = "", 
     type = "n",main='par(pin=c(5,0.7*5)')

dev.off()

示例2:展示如果将pin设置为大于图形设备的大小,您将会收到一个错误。我们将使用默认设备(在我的情况下为RStudioGD)。

par(pin=c(10, 10))
plot(0, 0, xlim = c(0, 70), ylim = c(0, 100), xlab = "", ylab = "", 
     type = "n",main='par(pin=c(5,4)')

# Get dimensions of the default plot device 
par("din") 

# Create a plot that takes up an area just a bit smaller than the device size
par(pin=par("din")-0.2)
plot(0, 0, xlim = c(0, 70), ylim = c(0, 100), xlab = "", ylab = "", 
     type = "n",main='par(pin=c(5,4)')

# Create a plot that takes up an area just a bit larger than the device size 
# (we'll get an error this time)
par(pin=par("din") + 0.01)
plot(0, 0, xlim = c(0, 70), ylim = c(0, 100), xlab = "", ylab = "", 
     type = "n")

> Error in plot.new() : plot region too large

示例3:如果您超出了pdf(或png等)设备的大小限制,将会发生相同的错误:

# Create a 5" x 5" pdf graphics device
pdf("test.pdf", 5,5)
# Create a plot that takes up a little bit less than the device size
par(pin=c(5,5)-0.2)
plot(0, 0, xlim = c(0, 70), ylim = c(0, 100), xlab = "", ylab = "", 
     type = "n")
dev.off()

# Create a plot that takes up a little bit more than the device size
pdf("test.pdf", 5,5)
par(pin=c(5,5)+0.01)
plot(0, 0, xlim = c(0, 70), ylim = c(0, 100), xlab = "", ylab = "", 
     type = "n")
# Gives the following error: Error in plot.new() : plot region too large
dev.off()

感谢您为@mr.joshuagordon的回答添砖加瓦。这解释了为什么它不起作用,虽然我仍然觉得xlim和ylim需要被asp覆盖是令人困惑的。在我的情况下,我确实需要asp(因为1个x步长恰好等于1个y步长,因为它们代表数据中的米),但我也希望能够将图形限制在我正在使用的数据范围内。感谢您提供ggplot2解决方案,看来我终于要开始学习ggplot2了... - Peter Verbeet
我强烈推荐学习ggplot2。我也曾经避开它一段时间,因为学习新的图形思维方式似乎需要付出很多努力。但实际上并不需要花费太长时间,现在我几乎不再使用基础图形了。 - eipi10
谢谢@eipi10,你非常有帮助。你对答案的更新非常有用,肯定会激励我去学习ggplot2。迄今为止,我抵制它的一个原因是它似乎比基本图形绘制速度慢得多。 - Peter Verbeet
我发现ggplot2也比较慢,但是除非你处理的数据集非常大(至少在我的经验中超过一百万行——好吧,也许一百万行不再算是很大了),否则差异是无法察觉的。但如果这是个问题,只需使用dplyr(或您喜欢的R分割-应用-合并策略)来进行聚合和汇总,然后将摘要数据提供给ggplot2。此外,ggplot2的创建者Hadley Wickham一直在研究快速绘制大型数据集的方法,因此我预计随着时间的推移,任何速度差异都会减少。 - eipi10
很高兴听到这个消息。我很高兴听说Hadley正在努力加快ggplot2的速度。目前来看,我预计学习ggplot2的时间会比ggplot2本身慢一些 :-) - Peter Verbeet

7
您可以将图形保存为PDF,并指定其大小,方法如下:
pdf("SampleGraph.pdf",width=7,height=10)
plot(0, 0, xlim = c(0, 70), ylim = c(0, 100), asp=NA, xlab = "", ylab = "", type = "n") # change asp to NA
dev.off() # turn off plotting

可以,谢谢。我更喜欢不必写入单独的文件来完成这个操作,但是这确实有效地解决了问题,谢谢! - Peter Verbeet

3

绘制图表(...,xaxs = "i",yaxs = "i")


4
欢迎来到 Stack Overflow。要将某些内容格式化为代码,您可以使用编辑器中的按钮,或者用单个反引号包裹行内文本,或在前后各加三个反引号的行中编写代码,或使用四个空格缩进。仅有代码的答案通常可以通过添加一些解释说明它们的工作方式和原因而得到改善。 - Jason Aller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接