Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add and example with a raster function returning multiple layers #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 74 additions & 6 deletions source/pkg/_R/appendix1.rmd
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,74 @@ Note that most of the additional arguments are passed on to writeStart:
Only the `progress=` argument goes to `pbCreate`


## A complete function with multiple layers

For functions with output in multiple layers.

```{r code-10}
f9 <- function(x, a, filename='', ...) {
nLayersOut<- 2 # mean & sd
out<- brick(x, values=FALSE, nl=nLayersOut)
names(out)<- c("mean", "sd")
big<- !canProcessInMemory(out, nlayers(x) + nLayersOut)
filename<- trim(filename)

if (nlayers(x) < 2){
out<- setValues(out, x[] + a, layer=1)
if (filename != ''){
out<- writeRaster(out, filename, ...)
}
return(out)
}

if (big & filename == '') {
filename<- rasterTmpFile()
}
if (filename != '') {
out<- writeStart(out, filename, ...)
todisk<- TRUE
} else {
vv<- array(NA_real_, dim=c(ncol(out), nrow(out), nlayers(out)))
todisk<- FALSE
}

bs<- blockSize(x)
pb<- pbCreate(bs$n, ...)

if (todisk) {
for (i in 1:bs$n) {
v<- getValues(x, row=bs$row[i], nrows=bs$nrows[i])
v<- v + a
v<- cbind(rowMeans(v), apply(v, 1, sd))
out<- writeValues(out, v, bs$row[i])
pbStep(pb, i)
}
out<- writeStop(out)
} else {
for (i in 1:bs$n) {
v<- getValues(x, row=bs$row[i], nrows=bs$nrows[i])
v<- v + a
v<- cbind(rowMeans(v), apply(v, 1, sd))
cols<- bs$row[i]:(bs$row[i] + bs$nrows[i] - 1)
vv[, cols, ]<- array(v, dim=c(ncol(x), length(cols), nLayersOut))
pbStep(pb, i)
}
out<- setValues(out, as.vector(vv))
}
pbClose(pb)
return(out)
}

s <- f9(r, 5)
s

rr <- stack(lapply(-1:2, function(x) r * x))
s <- f9(rr, 5, filename='test', overwrite=TRUE)
s

```


## Debugging

Typically functions are developed and tested with small (RasterLayer) objects. But you also need to test your functions for the case it needs to write values to disk. You can use a very large raster for that, but then you may need to wait a long time each time you run it. Depending on how you design your function you may be able to test alternate forks in your function by providing a file name. But this would not necessarily work for function f7. You can force functions of that type to treat the input as a very large raster by setting to option 'todisk' to `TRUE` as in `setOptions(todisk=TRUE)`. If that option is set, `canProcessInMemory` always returns `FALSE`. This should only be used in debugging.
Expand All @@ -276,20 +344,20 @@ Typically functions are developed and tested with small (RasterLayer) objects. B

The raster package is build with S4 classes and methods. If you are developing a package that builds on the raster package I would advise to also use S4 classes and methods. Thus, rather than using plain functions, define generic methods (where necessary) and implement them for a RasterLayer, as in the example below (the function does not do anything; replace 'return(x)' with something meaningful along the pattern explained above.

```{r code-10}
if (!isGeneric("f9")) {
setGeneric("f9", function(x, ...)
standardGeneric("f9"))
```{r code-11}
if (!isGeneric("f10")) {
setGeneric("f10", function(x, ...)
standardGeneric("f10"))
}


setMethod('f9', signature(x='RasterLayer'),
setMethod('f10', signature(x='RasterLayer'),
function(x, filename='', ...) {
return(x)
}
)

s <- f9(r)
s <- f10(r)
```

## Mutli-core functions
Expand Down