通过重用旧的绘图参数来加速格子图?

时间:2013-10-30 00:57:53

标签: r performance plot lattice

我正在对大型数据集进行一些探索性分析(约10,000个数据点分组为~10条曲线)。我正在使用RStudio中的manipulate包来更改x轴限制。问题是,使用新参数重绘图可能需要5秒以上。我希望有一种方法来加快这一点。我正在使用lattice包。这是一个简化的例子......

set.seed(100)
x = rep(1:5,20)
y = rnorm(100)
groups = gl(20,5)
p = xyplot(y~x,groups=groups,type="l",
           auto.key=list(space="right",lines=TRUE,
                         points=TRUE,rectangles=TRUE) )

Rprof(interval=0.001)
print(p)
Rprof(NULL)
head( summaryRprof()$by.total )
                  total.time total.pct self.time self.pct
"print"                0.239    100.00     0.000     0.00
"printFunction"        0.239    100.00     0.000     0.00
"print.trellis"        0.239    100.00     0.000     0.00
"do.call"              0.126     52.72     0.001     0.42
"draw.key"             0.098     41.00     0.001     0.42
"evaluate.legend"      0.098     41.00     0.000     0.00

请注意draw.key需要41%的运行时间(是的,选择这个多余的传说来强调我的观点)。就我的目的而言,我的传奇永远不会改变,但情节会如此。那么有没有办法从一个图中保存图例,关键字或任何内容并反复重复使用(可能重用Grob中的lattice::draw.key对象)?我已经研究了lattice:::plot.trellis的一些代码,看起来应该有办法做到这一点。但是,看起来需要大量新代码才能这样做。有简单的解决方案吗?或者,是否有任何其他绘图功能或包以其速度而闻名?我当然可以在我的数据中使用平滑的曲线来“压缩/缩减采样”它,但我宁愿不这样做。

2 个答案:

答案 0 :(得分:1)

我有时会发现绘制文件比绘制屏幕更快,然后打开文件。

这不是你想要的,但如果它足够快,那将会更加简单......

答案 1 :(得分:1)

简而言之,是的,有一些方法可以根据预先计算的网格对象或其他参数加速格子图的打印。但是,据我所知,没有简单的解决方案。为此,我需要深入研究晶格绘图功能plot.trellis的来源,以确定可以优化速度的位置。继续问题的例子......

# Save the legend from the last plot
plot.grob = trellis.last.object()
legend.grob = lattice:::evaluate.legend( plot.grob$legend )

# Modify the default plotting function
f = lattice:::plot.trellis
b = body(f)
fun.line = which(!is.na(str_match(as.character(b),"evaluate.legend")))
new.line = substitute(legend <- if(is.null(legend.object)) 
                        evaluate.legend(x$legend) else legend.object)
body(f)[[fun.line]] = new.line
args = formals(f)
formals(f) = do.call(alist, c( args[2:length(args)-1], alist(legend.object=NULL,...=)) )

# Note that evaluate.legend is no longer taking up any time because it's not called
Rprof()
f(plot.grob,legend.object=legend.grob)
Rprof(NULL)
head(summaryRprof()$by.total)

# the modified function is faster
times = data.frame( modified.fun=NA, standard.fun=NA )
for( i in 1:100 ) {
  t1 = profr( f(plot.grob,legend.object=legend.grob), interval=0.001 )[1,"time"]
  t2 = profr( plot(plot.grob), interval=0.001 )[1,"time"]
  times = rbind( times, c( t1, t2 ) )
}
colMeans(na.omit(times))
modified.fun standard.fun 
     0.11435      0.19757

我修改后的函数减少了大约40%的时间,这是有道理的,因为evaluate.legend调用占问题中给出的plot.trellis示例中运行时间的大约40%。 plot.trellis函数中还有许多其他点可以优化速度。如果要继续前进,他们最终可以将功能归结为裸骨,以便只调用grid包中的函数。这基本上是重写一个全新的plot.trellis函数,灵活性降低但速度更快。但是,这不是我想要的。

另一方面,我注意到我的屏幕上绘图的实际绘制时间比分析代码报告的运行时间长。我用一个秒表来计算在报告代码运行完毕后显示的情节花了不到1秒的时间。我尝试了其他依赖grid的绘图包并找到了类似的结果。因此,无论绘图函数的优化程度如何,我都认为当我达到1秒或更短的时间时,grid,基本R或我的硬件最终会成为限制因素。这个新问题有解决方案,但那是另一个话题......