matlabcat
matlabcat

Reputation: 192

How can I turn R code from an old package's function into a working function in the current version of R

I typically use Matlab and am only an amateur when it comes to R. I have been trying to use someone elses code from 2011 and it is calling for a function called 'xyValues'. I have found that this used to be function within the Raster package (version 1.5.8) but no longer appears in the current version. The old raster package is incompatible with newer versions of R. I have tried downgrading R but then that causes other issues.

I have downloaded the tar.gz file and extracted the code for the xyValues function. I tried to paste it into my newer version of the Raster package, but unsurprisingly, it didn't work. Is there an easy way for me to turn the code for this function into an actual function that I can save and then use (as if I wrote the function myself)? I could do this easily in matlab, but it seems the process for writing a function is a little different in R and I don't really know where to start? I see some variations of this question on this site, but I'm wondering if it is possible for a new user of R (like me) to be able to do what I am suggesting. Perhaps it is only possible if you have a lot of knowledge regarding R. This is the code I extracted:

# Author: Robert J. Hijmans
# contact: [email protected]
# Date : November 2008
# Version 0.9
# Licence GPL v3


if (!isGeneric("xyValues")) {
  setGeneric("xyValues", function(object, xy, ...)
    standardGeneric("xyValues"))
}   


setMethod("xyValues", signature(object='Raster', xy='SpatialPoints'), 
          function(object, xy, method='simple', buffer=NULL, fun=NULL, na.rm=TRUE,...) { 
            callGeneric(object, coordinates(xy),  method, buffer, fun, na.rm, ...)
          } 
)


setMethod("xyValues", signature(object='Raster', xy='data.frame'), 
          function(object, xy, method='simple', buffer=NULL, fun=NULL, na.rm=TRUE,...) { 
            callGeneric(object, as.matrix(xy), method, buffer, fun, na.rm, ...)
          } 
)


setMethod("xyValues", signature(object='Raster', xy='vector'), 
          function(object, xy, method='simple', buffer=NULL, fun=NULL, na.rm=TRUE, ...) { 
            if (length(xy) == 2) {
              callGeneric(object, matrix(xy, ncol=2), method, buffer, fun, na.rm,  ...)
            } else {
              stop('xy coordinates should be a two-column matrix or data.frame, or a vector of two numbers.')
            }
          } )


setMethod("xyValues", signature(object='RasterLayer', xy='matrix'), 
          function(object, xy, method='simple', buffer=NULL, fun=NULL, na.rm=TRUE, ...) { 

            if (dim(xy)[2] != 2) {
              stop('xy has wrong dimensions; it should have 2 columns' )
            }

            if (! is.null(buffer)) {
              if (method != 'simple') { warning('method argument is ignored when a buffer is used') }
              return( .xyvBuf(object, xy, buffer, fun, na.rm=na.rm) )
            }

            if (method=='bilinear') {
              return(.bilinearValue(object, xy))
            } else if (method=='simple') {
              cells <- cellFromXY(object, xy)
              return(.readCells(object, cells))
            } else {
              stop('invalid method argument. Should be simple or bilinear.')
            }
          } 
)   


setMethod("xyValues", signature(object='RasterStack', xy='matrix'), 
          function(object, xy, method='simple', buffer=NULL, fun=NULL, na.rm=TRUE, ...) { 
            .xyvStackBrick(object, xy, method, buffer, fun, na.rm, ...)
          } )

setMethod("xyValues", signature(object='RasterBrick', xy='matrix'), 
          function(object, xy, method='simple', buffer=NULL, fun=NULL, na.rm=TRUE, ...) { 
            .xyvStackBrick(object, xy, method, buffer, fun, na.rm, ...)
          } )


.xyvStackBrick <- function(object, xy, method='simple', buffer=NULL, fun=NULL, na.rm=TRUE, ...) { 

  dots <- list(...)
  layer <- dots$layer
  n <- dots$nl
  nls <- nlayers(object)

  if (is.null(layer)) { layer <- 1 } 
  if (is.null(n)) { n <- nls } 
  layer <- min(max(1, round(layer)), nls)
  n <- min(max(1, round(n)), nls-layer+1)

  if (dim(xy)[2] != 2) {
    stop('xy has wrong dimensions; there should be 2 columns only' )
  }

  if (! is.null(buffer)) {
    if (method != 'simple') { warning('method argument is ignored when a buffer is used') }
    return( .xyvBuf(object, xy, buffer, fun, na.rm, layer=layer, n=n) )
  }

  if (method == 'bilinear') {
    result <- .bilinearValue(object, xy, layer=layer, n=n)
    return(result)      

  } else if (method=='simple') {

    cells <- cellFromXY(object, xy)
    return( cellValues(object, cells, layer=layer, n=n) )

  } else {
    stop('invalid method argument. Should be simple or bilinear.')
  }
}

As a followup to this question, initially, when I wanted to see if this function was in my raster package I tried typing help(xyValues) and nothing came up (because it didn't exist). However, when I try this for functions that DO exist within the package, they too, are not showing up. Does this mean my raster package isn't loaded correctly?

The piece of code I am using with the function in it is:

elevgrid <- xyValues(elev,cbind(xygrid[,2],xygrid[,1]))

where elev is a Formal class Rasterlayer of size 920x1000 and xygrid is 4800 obs of 2 variables (x y coordinates)

I tried using:

> source("C:/Users/Documents/raster/R/xyValues.R")

but I got all these errors:

in method for ‘xyValues’ with signature ‘object="Raster",xy="data.frame"’: no definition for class “Raster”
in method for ‘xyValues’ with signature ‘object="Raster",xy="vector"’: no definition for class “Raster”
in method for ‘xyValues’ with signature ‘object="RasterLayer",xy="matrix"’: no definition for class “RasterLayer”
in method for ‘xyValues’ with signature ‘object="RasterStack",xy="matrix"’: no definition for class “RasterStack”
in method for ‘xyValues’ with signature ‘object="RasterBrick",xy="matrix"’: no definition for class “RasterBrick”
Warning message:
in method for ‘xyValues’ with signature ‘object="Raster",xy="SpatialPoints"’: no definition for classes “Raster”, “SpatialPoints” 

I tried the getvalues and approxNA functions and got this:

> elevgrid <- getValues(elev,cbind(xygrid[,2],xygrid[,1]))
Error in (function (classes, fdef, mtable)  : 
  unable to find an inherited method for function ‘getValues’ for signature ‘"RasterLayer", "matrix", "missing"’
> elevgrid <- approxNA(elev)
Error in (function (classes, fdef, mtable)  : 
  unable to find an inherited method for function ‘approxNA’ for signature ‘"RasterLayer"’

Upvotes: 0

Views: 708

Answers (2)

Robert Hijmans
Robert Hijmans

Reputation: 47146

the xyValyes method extracted values from a raster using points (xy coordinates). This function has been replaced with extract. So instead of

library(raster)
xyValues(x, xy, ...)

You should be able to do

extract(x, xy, ...)

Upvotes: 1

Badger
Badger

Reputation: 1053

Couple of ways you can address this issue.

First and foremost:

Do you actually need the old function to do the work, or can it be done with a newer generation function? I'm not really clear what you're trying to do, so I can't suggest a better function.

Based on my assumptions through what you're doing and the help documentation for xyValues() this is my guess. First you need to use approxNA()(requires stack) this performs the interpolation as it would in xyValues() to fill in NAs in your raster. Then you need to turn it into a data.frame or a vector of values. This can be done with either as.data.frame() or getValues(). If you do not have NAs you need to fill, you can just pull the values with getValues() or as.data.frame()

dat.r <- raster(matrix(nrow = 100,ncol = 100,sample(x = 1:1000,size = 10000,replace = T)))
dat.vector <- getValues(dat.r)
dat.dataframe <- as.data.frame(dat.r)

If you do have NAs - I found a suggestion here: Fill in gaps (e.g. not single cells) of NA values in raster using a neighborhood analysis

## Add in some NAs
dat.r[sample(1:10000,1000)] <- NA
fill.na <- function(x) {
  center = 0.5 + (width*width/2) 
  if( is.na(x)[center] ) {
    return( round(mean(x, na.rm=TRUE),0) )
  } else {
    return( round(x[center],0) )
  }
}  
  
width = 9
r2 <- focal(dat.r, w = matrix(1,width,width), fun = fill.na, 
            pad = TRUE, na.rm = FALSE)
dat.vector <- getValues(r2)
dat.dataframe<- as.data.frame(r2)

Second:

You can just source everything you need from the unpacked tar.

source("~/raster_1.5-8/raster/R/xyValues.R")
source("~/raster_1.5-8/raster/R/xyValuesBuffer.R")
source("~/raster_1.5-8/raster/R/bilinearValue.R")
source("~/raster_1.5-8/raster/R/readCells.R")

~ is the directory to where you have unpacked raster_1.5-8 A quick noted on why there are 4 scripts and not just the 1 you are after. Any function with a leading . is a hidden function that gets loaded with the package but is not explictly executable. As you are not instantiating the package, you need these helper functions.

Third Not Recommended:

You can attempt to install and older version of the package following the instructions here. https://support.rstudio.com/hc/en-us/articles/219949047-Installing-older-versions-of-packages The code you would need is:

require(devtools)
install_version("raster", version = "1.5-8", repos = "http://cran.us.r-project.org/")

This may result in problems down the line if you are trying to use current generation functions, so I would not recommend this method

Upvotes: 1

Related Questions