使用 R 在循环中打印大量图形对象的正确方法?
Proper way to print numerous graphical objects in a loop using R?
我经常听说,一般来说,使用 apply
函数比在 R 中使用 for
循环更好(并且 更合适 )。也适用于打印图形输出(没有理想的控制台输出或对象保存)?
例如:
如果我想在图表上打印 5 条线,我应该使用应用函数(例如 sapply
)还是 for
循环?
plot(x=1:5,y=1:5,type='n')
sapply(1:5,function(z) lines(y = 1:5, x=rep(z, length(1:5)))) #...or....
for(z in 1:5) { lines(y=1:5, x=rep(z, length(1:5))) }
apply 函数创建无用的控制台输出,但我的印象是 apply
比使用 for
循环更好。
也许是个愚蠢的问题,但我希望我的代码尽可能清晰和快速。
(此外,如果 sapply 或 for 循环都不是编写此命令的最佳方法,那是什么?)
1: 我想你可能对lines()
函数有误解。它在一系列 (x,y)
点之间绘制连接线。调用它通过沿线段传递 5 个点来绘制单个线段是没有意义的。这是 lines()
可以做什么的示例:
xlim <- c(0,4); ylim <- c(0,4); plot(NA,xlim=xlim,ylim=ylim,xlab='x',ylab='y');
lines(0:4,c(0,3,4,3,0));
2: 要绘制单独的线段,使用segments()
更合适。以下是使用此函数绘制 5 条线的方法:
xlim <- c(1,5); ylim <- c(1,5); plot(NA,xlim=xlim,ylim=ylim,xlab='x',ylab='y');
segments(1:5,1,y1=5);
如您所见,segments()
在其坐标参数上被矢量化(就像 lines()
一样),因此您可以通过一次调用绘制多条线。不需要循环。
3: 话虽这么说,在图形制作中有许多情况,您必须多次调用图形函数才能生成所需的输出。在这些情况下,我一直使用 for 循环而不是 *apply()
系列。当您关心 lambda 调用的 return 值时,*apply()
系列主要用于数据处理,因此要么将结果捕获到变量中,要么将其作为参数传递到另一个函数调用。图形函数几乎总是纯粹因其副作用而被调用,即在图形设备上绘制图形,因此图形调用的 return 值被丢弃。使用 *apply()
系列不太可能带来性能优势,尽管 the analysis is not quite so simple. But any performance benefit you might procure from the *apply()
family can only result from increased efficiency with respect to handling the data produced and returned by the lambda, so it can't apply to graphics calls that don't return data. For example, vapply()
在某些情况下可以提供显着的性能优势,因为它可以提前确定对象的类型和大小 return发送给来电者。同样,这不适用于 return 除了 NULL
.
之外的任何图形调用
4: 如果您发现必须调用 return 数据不可见的函数,并且您想阻止它显示在您的控制台中,您可以手动将其包装在 invisible()
中。以您的 sapply()
调用为例:
sapply(1:5,function(z) lines(y=1:5,x=rep(z,5L)));
## [[1]]
## NULL
##
## [[2]]
## NULL
##
## [[3]]
## NULL
##
## [[4]]
## NULL
##
## [[5]]
## NULL
##
invisible(sapply(1:5,function(z) lines(y=1:5,x=rep(z,5L)))); ## doesn't print anything
我经常听说,一般来说,使用 apply
函数比在 R 中使用 for
循环更好(并且 更合适 )。也适用于打印图形输出(没有理想的控制台输出或对象保存)?
例如:
如果我想在图表上打印 5 条线,我应该使用应用函数(例如 sapply
)还是 for
循环?
plot(x=1:5,y=1:5,type='n')
sapply(1:5,function(z) lines(y = 1:5, x=rep(z, length(1:5)))) #...or....
for(z in 1:5) { lines(y=1:5, x=rep(z, length(1:5))) }
apply 函数创建无用的控制台输出,但我的印象是 apply
比使用 for
循环更好。
也许是个愚蠢的问题,但我希望我的代码尽可能清晰和快速。
(此外,如果 sapply 或 for 循环都不是编写此命令的最佳方法,那是什么?)
1: 我想你可能对lines()
函数有误解。它在一系列 (x,y)
点之间绘制连接线。调用它通过沿线段传递 5 个点来绘制单个线段是没有意义的。这是 lines()
可以做什么的示例:
xlim <- c(0,4); ylim <- c(0,4); plot(NA,xlim=xlim,ylim=ylim,xlab='x',ylab='y');
lines(0:4,c(0,3,4,3,0));
2: 要绘制单独的线段,使用segments()
更合适。以下是使用此函数绘制 5 条线的方法:
xlim <- c(1,5); ylim <- c(1,5); plot(NA,xlim=xlim,ylim=ylim,xlab='x',ylab='y');
segments(1:5,1,y1=5);
如您所见,segments()
在其坐标参数上被矢量化(就像 lines()
一样),因此您可以通过一次调用绘制多条线。不需要循环。
3: 话虽这么说,在图形制作中有许多情况,您必须多次调用图形函数才能生成所需的输出。在这些情况下,我一直使用 for 循环而不是 *apply()
系列。当您关心 lambda 调用的 return 值时,*apply()
系列主要用于数据处理,因此要么将结果捕获到变量中,要么将其作为参数传递到另一个函数调用。图形函数几乎总是纯粹因其副作用而被调用,即在图形设备上绘制图形,因此图形调用的 return 值被丢弃。使用 *apply()
系列不太可能带来性能优势,尽管 the analysis is not quite so simple. But any performance benefit you might procure from the *apply()
family can only result from increased efficiency with respect to handling the data produced and returned by the lambda, so it can't apply to graphics calls that don't return data. For example, vapply()
在某些情况下可以提供显着的性能优势,因为它可以提前确定对象的类型和大小 return发送给来电者。同样,这不适用于 return 除了 NULL
.
4: 如果您发现必须调用 return 数据不可见的函数,并且您想阻止它显示在您的控制台中,您可以手动将其包装在 invisible()
中。以您的 sapply()
调用为例:
sapply(1:5,function(z) lines(y=1:5,x=rep(z,5L)));
## [[1]]
## NULL
##
## [[2]]
## NULL
##
## [[3]]
## NULL
##
## [[4]]
## NULL
##
## [[5]]
## NULL
##
invisible(sapply(1:5,function(z) lines(y=1:5,x=rep(z,5L)))); ## doesn't print anything