I have been working on an exercise using Rstudio. I want to do a kriging interpolation, but I get an error that I have not been able to solve.
I'd appreciate if some of you could tell me how to fix it.
Here my code:
#importing libraries
library(raster)
library(sf)
library(sp)
library(rgdal)
library(gstat)
library(tmap)
library(tidyverse)
#reading csv data
id <- "1u18s9g15USnzNhj-t2EEFYHsW6GZEIgd" # google file ID
read.csv(sprintf("https://docs.google.com/uc?id=%s&export=download", id))
silver_data = read.csv(sprintf("https://docs.google.com/uc?id=%s&export=download", id))
#creating spatial dataframe
silver_2 <- st_as_sf(silver_data, coords = c("long", "lat"))
st_crs(silver_2) <- 4326
#coordinates transformation
silver_utm2 <- st_transform(silver_2, crs=9155)
#setting variogram
ve <- variogram(silver ~ 1, silver_utm2, cutoff = 5000,width = 200)
plot(ve, plot.numbers = T, asp=1)
# experimental variogram
vt <- vgm(psill = 350, model = "Sph", range = 2000,nugget = 0)
plot(ve, pl = T, model = vt)
#automatic adjustment
va <- fit.variogram(ve, vt)
plot(ve, pl = T, model = va)
#empty raster in order to create grid for kriging interpolation
z <- raster(as(silver_utm2, "Spatial"), ncols = 200, nrows = 80)
# using raster to create grid
grilla2 <- rasterToPoints(z, spatial = TRUE)
gridded(grilla2) <- TRUE
grilla2 <- as(grilla2, "SpatialPixels")
# using kriging function
ok <- krige(silver~1, locations=silver_utm2, newdata=grilla2, model=va)
The error that appears:
> ok <- krige(silver~1, locations=silver_utm2, newdata=grilla2, model=va)
Error in UseMethod("st_crs<-") :
no applicable method for 'st_crs<-' applied to an object of class "c('SpatialPixels', 'SpatialPoints', 'Spatial', 'SpatialVector')
The tutorial I'm following is https://rstudio-pubs-static.s3.amazonaws.com/416462_1463d00750c54fce89955a925eaa4957.html, but the data are not the same.
st_crs() is a function from the package sf and is designed to operate on sf objects only. As your code stands, grilla2 is an sp object. Convert it to sf before using krige().
grilla2 <- sf::st_as_sf(grilla2)
Related
I want to assess if the observations in my data are spatially randomly distributed over the sampling area (Sweden). I wanted to reproduce the example given in this answer: Spatial Autocorrelation Analysis (Global Moran's I) in R
Here is a small subset of my data, and the spatial polygon I used. Note that the coordinates are in SWEREF99 (ESPG: 3006)
## spatial polygon of Sweden
library(rworldmap)
library(sp)
worldmap <- getMap(resolution = "high")
sweden <- worldmap[which(worldmap$SOVEREIGNT == "Sweden"),]
plot(sweden)
sweden
## conversion to EPSG: 3006 (SWEREF99 TM) (https://spatialreference.org/ref/epsg/3006/)
crs.laea <- CRS("+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs")
sweden_proj <- spTransform(sweden, crs.laea)
## Data subset
x <- c(669894, 669894, 669894, 671088, 671117, 671117, 671117, 670513, 670513, 670513, 669921, 669310, 669310, 669310, 669303, 629720, 630318, 630925, 630925, 630925)
y <- c(7116684, 7116684, 7116684, 7116706, 7114900, 7114900, 7114900, 7114896, 7114896, 7114896, 7114888, 7115473, 7115473, 7115473, 7116075, 7131172, 7131180, 7131190, 7131190, 7131190)
library(spatstat)
coords.ppp_1 <- ppp( x , y , xrange = c(280227, 911417) , yrange = c(6142436, 7605020) )
coords.ppp <- unique(coords.ppp_1)
### plot data and Sweden map for check
plot(coords.ppp_1)
plot(sweden_proj, add=T)
So far it seems ok. Then I convert the spatial polygon to an owin object, simulate random data for comparison, and do the analysis.
library(maptools)
sw <- as.owin.SpatialPolygons(sweden_proj)
# Generate completely spatially random point patterns to compare against the observed
n <- coords.ppp_1$n
ex <- expression(runifpoint( n , sw))
# Compute a simulation envelope using Gest, which estimates the nearest neighbour distance distribution function G(r)
set.seed(1)
res <- envelope( coords.ppp , Gest , nsim = 99, simulate = ex ,verbose = FALSE, savefuns = TRUE )
plot(res)
With the envelope() I get the following error message:
"In envelopeEngine(X = X, fun = fun, simul = simrecipe, nsim = nsim, :
Window containing simulated patterns is not a subset of data window"
I suspect that there is a problem with the conversion between sp and owin, but I couldn't figure out what the issue really is.
Any advice?
I use machine learning algorithms for species distribution modeling. This involves fitting a model in R and applying the model to a raster stack of environmental predictors using the predict() function. This is relatively straightforward for functions such as randomForest, glm, and maxent. However, I would like to use the best model selected using the h2o.automl function in the package h2o to predict occurrence probabilities across a stack of environmental predictors. Now, it is possible to convert raster stacks into data frames and then use these for h2o prediction. However, this tends to eat up a lot of RAM for large raster stacks. Below is an example using some publicly available low-resolution data.
library(sp)
library(raster)
library(maptools)
library(rgdal)
library(dismo)
library(h2o)
library(sp)
library(h2o)
bioclim.data <- getData(name = "worldclim",
var = "bio",
res = 2.5)
obs.data <- read.csv("https://raw.githubusercontent.com/jcoliver/learn-r/gh-pages/data/Carnegiea-gigantea-GBIF.csv")
obs.data <- obs.data[!is.na(obs.data$latitude), ]
obs.data <- obs.data[, c("longitude", "latitude")]
obs.sp<-SpatialPoints(obs.data, proj4string = CRS("+proj=longlat +datum=WGS84 +no_defs"))
# Determine geographic extent of our data
max.lat <- ceiling(max(obs.data$latitude))
min.lat <- floor(min(obs.data$latitude))
max.lon <- ceiling(max(obs.data$longitude))
min.lon <- floor(min(obs.data$longitude))
geographic.extent <- extent(x = c(min.lon, max.lon, min.lat, max.lat))
bioclim.data <- crop(x = bioclim.data, y = geographic.extent)
background<-randomPoints(mask = bioclim.data,
n = nrow(obs.data),
ext = geographic.extent,
extf = 1.25)
colnames(background)<-c("longitude", "latitude")
background.sp<-SpatialPoints(background, proj4string = CRS("+proj=longlat +datum=WGS84 +no_defs"))
presence<-data.frame(Presence = rep(1, times = nrow(obs.data)), extract(bioclim.data, obs.sp))
absence<-data.frame(Presence = rep(0, times = nrow(obs.data)), extract(bioclim.data, background.sp))
df<-rbind(presence, absence)
df$Presence<-as.factor(df$Presence)
h2o.init(max_mem_size = "4g")
set.seed(1234)
df_h2o <- as.h2o(df)
splits <- h2o.splitFrame(df_h2o, c(0.7, 0.15), seed = 1234)
train <- h2o.assign(splits[[1]], "train")
valid <- h2o.assign(splits[[2]], "valid")
test <- h2o.assign(splits[[3]], "test")
y <- "Presence"
x <- setdiff(names(df_h2o), y)
aml <- h2o.automl(x = x,
y= y,
training_frame = train,
leaderboard_frame = valid,
max_runtime_secs = 60) #default 1 hour 3600 secs, more time, more accurate
pred<-as.data.frame(predict(aml, test)) # this works. It reports predicted probabilities of presence vs. absence.
pred_rstr<-predict(aml, bioclim.data) # this doesn't work. Must be an H2oFrame
biodf<-as.data.frame(bioclim.data) # this forces the raster stack into a dataframe. This works, but only for low resolution rasters.
bio_h2o<-as.h2o(biodf)
pred2<-as.data.frame(predict(aml, bio_h2o))
pred_rstr<-bioclim.data[[1]] # pull one of the rasters from the stack to serve as a template
values(pred_rstr)<-as.vector(pred2$p1) # set raster values to predicted probabilities
plot(pred_rstr)
I have WRF output netCDF files with 149974991 dimensions produced with "Mercator" projection over the Horn Of Africa. I would like to convert netCDF files into raster stack to undertake further analysis. I have been trying different options but it didn't work for me. I am getting values on wrong locations. I require help in this regards and any help is much appreciated.
Here is the code :
ro_rast <- nc_open("wrf_CAM0_daily_pre.nc")
pre <- ncvar_get(ro_rast, "pre") ro_rast$dim$lon$vals -> lon ro_rast$dim$lat$vals -> lat ro_rast$dim$ncl2$vals -> time rm(ro_rast)
r1_brick <- brick(pre, xmn=min(lat), xmx=max(lat), ymn=min(lon), ymx=max(lon), crs=CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs+ towgs84=0,0,0"))
names(r1_brick)<- seq(as.Date('2018-06-01'), as.Date('2018-08-31'), 'days')
# convert names of layer into date par(mar = c(2, 2, 2, 2))
cam1_mean <- t(calc(r1_brick, sum))
# seasonal sum precipitation
cam1 <- flip(cam1_mean, direction = 2)
library(akima)# intepolation
lonlat_reg <- expand.grid(lon = seq(min(lon), max(lon), length.out = 1499),
lat = seq(min(lat), max(lat), length.out = 749))
test <- interp(x = as.vector(lon), y = as.vector(lat), z = as.vector(pre),
xo = unique(lonlat_reg[,"lon"]), yo = unique(lonlat_reg[,"lat"]),
duplicate = "error", linear = FALSE, extrap = FALSE)
test <- interp(x = as.vector(lon), y = as.vector(lat), z = as.vector(pre),
nx = 1499, ny = 749, linear = FALSE, extrap = FALSE)
# turn into a raster
test_ras <- raster(test)
The standard approach would be
library(raster)
b <- brick("wrf_CAM0_daily_pre.nc")
It that does not work, can you point us to the file you are using?
I get this error message (you should have added that to your question).
Error in .rasterObjectFromCDF(x, type = objecttype, band = band, ...) :
cells are not equally spaced; you should extract values as points
I checked the file, and in this case, the raster is not a regular grid. The size of the cells changes with latitude. The file does not provide the x and y values of the coordinate reference system used. So the best you can do is extract these values as points, as you were doing, using the interface of the ncdf4 or another package. You can then not directly make a RasterBrick. But you do so using rasterize or interpolate.
I have 608 observations of satellite-tagged turtles. I want to model these with environmental data which includes sea surface temperature, current speed, wind speed etc. Of course, both the tagging and environmental data vary spatially and temporally. I have generated pseudo-absence data using the code below which I adapted from here. However, it has now occurred to me that the data points I have generated are only spatial samples. Is there some way I can edit this code to sample temporally as well so that my resulting csv has a date/time for each point so that I can match it up to my environmental data? Alternatively, is there a different package I could try that would allow me to do this?
dir.create(path = "data")
library("sp")
library("raster")
library("maptools")
library("rgdal")
library("dismo")
bioclim.data <- getData(name = "worldclim",
var = "bio",
res = 2.5,
path = "data/")
# Read in observations
obs.data <- read.csv(file = "data/Presence.csv")
# Determine geographic extent of data
max.lat <- ceiling(max(obs.data$Latitude))
min.lat <- floor(min(obs.data$Latitude))
max.lon <- ceiling(max(obs.data$Longitude))
min.lon <- floor(min(obs.data$Longitude))
geographic.extent <- extent(x = c(min.lon, max.lon, min.lat, max.lat))
# Use the bioclim data files for sampling resolution
bil.files <- list.files(path = "data/wc2-5",
pattern = "*.bil$",
full.names = TRUE)
# only need one file, so use the first one in the list of .bil files
mask <- raster(bil.files[1])
# Randomly sample points (same number as our observed points)
background <- randomPoints(mask = mask, # Provides resolution of sampling points
n = nrow(obs.data), # Number of random points
ext = geographic.extent, # Spatially restricts sampling
extf = 1.25) # Expands sampling a little bit
write.csv(background, "pseudo-absence.csv")
I solved this issue by simply generating random times with the code below and merging the resulting and above .csv.
#ADD TIMES
time.start <- as.POSIXct('2014-12-01T01:00:00z', format = "%Y-%m-%dT%H:%M:%S")
time.end <- as.POSIXct('2015-04-30T01:00:00z', format = "%Y-%m-%dT%H:%M:%S")
seconds <- difftime(time.end, time.start, units = "secs")
# Option with runif()
v <- round(runif(6000, 0, seconds))
# Option with sample()
v <- sample(1:seconds, 6000, replace = T)
time.uniform <- time.start + v
write.csv(time.uniform, "time.csv")
tag<-read.csv("pseudo-absence.csv")
time<- read.csv("time.csv")
myfulldata = merge(tag,time)
write.csv(myfulldata, "pseudo-absence_with_time.csv")
I have a code similar to one provided in a StackOverflow response using this answer from Ege Rubak, however I am doing an analysis over the year, so I have an image for each month of a specific year.
library(gstat)
library(sp)
lat <- c(-23.49174, -23.49179, -23.49182, -23.49183, -23.49185, -23.49187)
long <- c(152.0718, 152.0718, 152.0717, 152.0717, 152.0717, 152.0717)
pH <- c(8.222411, 8.19931, 8.140428, 8.100752, 8.068141, 8.048852)
sample <- data.frame(lat, long, pH)
x.range <- range(sample$long)
y.range <- range(sample$lat)
x<-seq(x.range[1], x.range[2], length.out=20)
y<-seq(y.range[1], y.range[2], length.out=20)
grd<-expand.grid(x,y)
coordinates(sample) = ~long+lat
coordinates(grd) <- ~ Var1+Var2
gridded(grd) <- TRUE
proj4string(sample) <- CRS("+proj=longlat +datum=WGS84")
proj4string(grd) <- CRS("+proj=longlat +datum=WGS84")
dat.idw <- idw(formula=pH ~ 1, locations = sample, newdata = grd, idp = 2.0)
#> [inverse distance weighted interpolation]
plot(dat.idw, axes = T)
As in the image below, how can I merge the 12 images into a single plot and do something similar to a ggplot facet wrap?
Testing the code suggested in this answer:
library(gridExtra)
library(raster)
s <- stack(raster(dat.idw))
s2 <- stack(raster(dat.idw))
p1 <- levelplot(s)
p2 <- levelplot(s2)
grid.arrange(p1, p2, ncol=2)
# Error in UseMethod("levelplot") :
# no applicable method for 'levelplot' applied to an object of class
# "c('RasterStack', 'Raster', 'RasterStackBrick', 'BasicRaster')"
You can use the levelplot function from the rasterVis package by preparing a raster stack object and provide it to the function.
library(raster)
library(rasterVis)
r1 <- raster(dat.idw)
r2 <- raster(dat.idw)
# I am only using two rasters as an example
# You can stack 12 rasters for your raster stack
s <- stack(list(r1, r2))
rasterVis::levelplot(s)
Or use the spplot from the sp package.
sp::spplot(s)
Or the tmap package.
library(tmap)
tm_shape(s) +
tm_raster()