我使用knitr
制作一个使用terra
包绘制地图的文档。这是我最小的。rmd文件:
```{r init, echo=FALSE}
library(knitr)
opts_chunk$set(cache=TRUE)
```
```{r maps}
library(terra)
r = rast(matrix(1:12,3,4))
plot(r)
```
```{r test2}
print(r)
plot(r)
```
第一次运行(通过rmarkdown::render(...)
),这是有效的,创建一个test_cache
文件夹。第二次运行时(没有任何更改)它也运行良好。如果我对块2做一个小的改变(例如添加一个注释)并运行,我得到:
Quitting from lines 14-17 (cache.Rmd)
Error in .External(list(name = "CppMethod__invoke_notvoid", address = <pointer: (nil)>, :
NULL value passed as symbol address
我也有这个从另一个Rmd文件,可能相关:
Quitting from lines 110-115 (work.Rmd)
Error in x@ptr$readStart() : external pointer is not valid
清除缓存或使用cache=FALSE
运行是可行的,但是这样缓存的意义是什么呢?
我认为这是因为r
是通过Rcpp
分配的一些内存存在的某种引用类,而knitr只是缓存一个引用,所以当它试图读取缓存的版本时,它会得到一个对内存的引用,而内存中没有创建与引用一起去的对象。所以它失败了。
terra
栅格对象是这样的:
> str(r)
Formal class 'SpatRaster' [package "terra"] with 1 slot
..@ ptr:Reference class 'Rcpp_SpatRaster' [package "terra"] with 20 fields
.. ..$ depth : num 0
.. ..$ extent :Reference class 'Rcpp_SpatExtent' [package "terra"] with 2 fields
和
> r@ptr
C++ object <0x55ce6fdf2bd0> of class 'SpatRaster' <0x55ce5a6750b0>
是否有办法使knitr缓存工作与这些对象?我知道我可以从缓存中排除这些对象,但我的文档中90%都在处理这些对象,这就是我想使用缓存来加快速度的原因。但是每次我遇到这个错误,我都必须停下来,清空缓存,重新开始,我不知道这段时间是否值得我用缓存加速。
R 4.1.1 with
> packageVersion("knitr")
[1] ‘1.34’
> packageVersion("rmarkdown")
[1] ‘2.11’
terra做一些工作来允许序列化,例如:
library(terra)
f <- system.file("ex/elev.tif", package="terra")
r <- rast(f)
saveRDS(r, "test.rds")
readRDS("test.rds")
[1] "This is a PackedSpatRaster object. Use 'terra::rast()' to unpack it"
readRDS("test.rds") |> rast()
#class : SpatRaster
#dimensions : 90, 95, 1 (nrow, ncol, nlyr)
#resolution : 0.008333333, 0.008333333 (x, y)
#extent : 5.741667, 6.533333, 49.44167, 50.19167 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84 (EPSG:4326)
#source : memory
#name : elevation
#min value : 141
#max value : 547
但是似乎knitr缓存带有"save"到RData文件;在这种情况下,原始对象被存储,当重新加载时将无效。
我认为可能可以通过巧妙地使用钩子函数来解决这个问题;但是,这将是如此复杂,它会破坏缓存的目的。