How to create SpatialPixelsDataFrame object in R (compatible with adehabitat package) - r

My problem is simple. I have found very good package called adehabitat in R. To use it I need to transform my data into specificaly structured object containing raster map data and coordinates of an animal. To see it please type:
# example data in adahabitat package
data(bauges)
bauges
str(bauges)
How do I convert my data (bellow) into such structure? I figured out how to convert $locs into SpatialPoints, but I don't know how to convert map (in my example are raster values categorical codes of individual types of habitat -i.e. not continuous variable).
# My example data:
library(raster)
library(adehabitatHS)
# map
habitat_type_temp <- matrix(c(1,1,1,1,1,1,1,1,2,2,
1,1,2,2,1,1,1,2,2,2,
1,2,2,2,3,3,3,2,2,2,
2,2,2,1,1,1,3,2,2,1,
2,2,1,1,1,1,3,2,1,1,
2,1,1,1,1,1,3,3,1,1,
2,1,1,1,1,3,3,3,3,1,
1,1,1,1,1,1,1,3,3,3), 10)
habitat_type <- t(habitat_type_temp)
# coordinates
animal_coords <- data.frame(x = c(2,4,5,5,6,9),
y = c(2,8,3,2,4,3))
# see the situation
plot(raster(habitat_type, xmn=1, xmx=10, ymn=1, ymx=8))
points(animal_coords$x, animal_coords$y)
# creating object which could be manipulated in adehabitat package
my.hab <- list()
my.hab$map <- SpatialPixelsDataFrame(...)
my.hab$locs <- SpatialPoints(animal_coords)
Is it even possible to insert such manually fabricated data into such specific type of object, or I need some original tiff with specific CRS?

You could just drop the location somewhere to produce the SpatialPixelsDataFrame, I think this is roughly Iowa:
x <- 93+rep(1:8,each=10)/100
y <- rep(seq(42.01,42.1,by=0.01), 8)
z <- c(1,1,1,1,1,1,1,1,2,2,
1,1,2,2,1,1,1,2,2,2,
1,2,2,2,3,3,3,2,2,2,
2,2,2,1,1,1,3,2,2,1,
2,2,1,1,1,1,3,2,1,1,
2,1,1,1,1,1,3,3,1,1,
2,1,1,1,1,3,3,3,3,1,
1,1,1,1,1,1,1,3,3,3)
xy.df <- data.frame(x,y)
xy.coords <- SpatialPixels(SpatialPoints(xy.df))
llCRS <- CRS("+proj=utm +zone=15 +ellps=WGS84")
xy.sp <- SpatialPoints(xy.coords, proj4string = llCRS)
xyz <- as.data.frame(cbind(x,y,z))
xyz.spdf <- SpatialPixelsDataFrame(xy.coords, xyz)
plot(xyz.spdf)
Your spatialpoints would have to be changed similarly.

Related

How to select one point per raster grid cell?

I have a point shapefile ("search_effort.shp") that is highly clustered and an NDVI raster (resolution in m: 30.94948, 30.77829). I would like to subset my search_effort.shp by selecting 1 point per raster grid cell and create a new search_effort shapefile. I am using R version 4.0.3
I think I could have used Package ‘gridsample’ (in 'raster' v1.3-1), but it was removed from the CRAN repository and I would prefer not to use the archived version. Is there another way to do this in R?
I have also tried sample.grid but I do not know how to specify my raster as the grid, and have tried the following:
# NDVI raster to be used as the reference extent
NDVI_extent <-readGDAL('C:/Model_layers/NDVI.tif')
# Load the file names
layername <- "SearchEffort"
# Read in the shapefile
search_effort <- readOGR(dsn= ".", layer = layername)
plot(search_effort)
# Set the reference extent
r <- raster(NDVI_extent)
# Extract coordinates from the shapefile
search_effort#coords <- search_effort#coords[, 1:2]
#Subset points
sample.grid(search_effort, cell.size = c(30.94948, 30.77829), n = 1)
I get the following error:
"Error in validObject(.Object) : invalid class “GridTopology” object: cellsize has incorrect dimension."
I get the same error regardless of the cell.size I specify.
Example data
library(raster)
r <- raster(res=30)
values(r) <- 1:ncell(r)
x <- runif(1000,-180,180)
y <- runif(1000,-90,90)
xy <- cbind(x, y)
Solution
library(dismo)
s <- gridSample(xy, r, n=1)
Illustration
plot(as(r, "SpatialPolygons"))
points(s, col="red")
points(xy, cex=.1, col="blue")

Extract Raster Pixels Values Using Vector Polygons in R

I have been struggling with this for hours.
I have a shapefile (called "shp") containing 177 polygons i.e. 177 counties. This shapefile is overlaid on a raster. My raster (called "ras") is made of pixels having different pollution values.
Now I would like to extract all pixel values and their number of occurrences for each polygon.
This is exactly what the QGIS function "zonal histogram" is doing. But I would like to do the exact same thing in R.
I tried the extract() function and I managed to get a mean value per county, which is already a first step, but I would like to make a pixels distribution (histogram).
Could someone give me a hand ?
Many thanks,
Marie-Laure
Thanks a lot for your help. Next time I promise I will be careful and explain my issue more in details.
With your help I managed to find a solution.
I also used this website : http://zevross.com/blog/2015/03/30/map-and-analyze-raster-data-in-r/
For information, first I had to uninstall the "tidyr" package because there was a conflict with the extract function.
In case it can help someone, here is the final code :
# Libraries loading
library(raster)
library(rgdal)
library(sp)
# raster layer import
ras=raster("C:/*.tif")
# shapefile layer import
shp<-shapefile("C:/*.shp")
# Extract the values of the pixels raster per county
ext <- extract(ras, shp, method='simple')
# Function to tabulate pixel values by region & return a data frame
tabFunc <- function(indx, extracted, region, regname) {
dat <- as.data.frame(table(extracted[[indx]]))
dat$name <- region[[regname]][[indx]]
return(dat)
}
# run through each county & compute a table of the number
# of raster cells by pixel value. ("CODE" is the county code)
tabs <- lapply(seq(ext), tabFunc, ext, shp, "CODE")
# assemble into one data frame
df <- do.call(rbind, tabs)
# to see the data frame in R
print(df)
# table export
write.csv(df,"C:/*.csv", row.names = FALSE)
Here is a minimal, self-contained, reproducible example (almost literally from ?raster::extract, so not difficult to make)
library(raster)
r <- raster(ncol=36, nrow=18, vals=rep(1:9, 72))
cds1 <- rbind(c(-180,-20), c(-160,5), c(-60, 0), c(-160,-60), c(-180,-20))
cds2 <- rbind(c(80,0), c(100,60), c(120,0), c(120,-55), c(80,0))
polys <- spPolygons(cds1, cds2)
Now you can do
v <- extract(r, polys)
par(mfrow=c(1,2))
z <- lapply(v, hist)
Or more fancy
mains <- c("first", "second")
par(mfrow=c(1,2))
z <- lapply(1:length(v), function(i) hist(v[[i]], main=mains[i]))
Or do you want a barplot
z <- lapply(1:length(v), function(i) barplot(table(v[[i]]), main=mains[i]))

R sample a raster with square polygons

I would like to sample a big raster by creating In small raster 100x100 cells.
I don't know how to do that so any ideas are welcome
My actual lead :
library(raster)
library(spatstat)
library(polyCub)
r <- raster(ncol=1000,nrow=1000) # create empty raster
r[] <- 1:(1000*1000) # Raster for testing
e <- extent(r) # get extend
# coerce to a SpatialPolygons object
p <- as(e, 'SpatialPolygons')
nc <- as.owin.SpatialPolygons(p) #polyCub
pts <- rpoint(50, win = nc)
plot(pts)
Now I need to generate 100x100 cell square around my 50 points and I would like to crop r using those square and stack each small raster individually ...
The answer by #adrian-baddeley basically has the ingredients to do what
you want. If you simply want a list of small im objects that contain
the 100x100 box you simply subset im objects by owin objects to
extract the relevant region. Here is an example (with fewer points to
avoid overplotting)
library(raster)
library(spatstat)
library(maptools)
r <- raster(ncol=1000,nrow=1000) # create empty raster
r[] <- 1:(1000*1000) # Raster for testing
e <- extent(r) # get extend
# coerce to a SpatialPolygons object
p <- as(e, 'SpatialPolygons')
nc <- as.owin.SpatialPolygons(p)
set.seed(42)
pts <- rpoint(7, win = nc)
rim <- as.im.RasterLayer(r)
Box <- owin(c(-50,50) * rim$xstep, c(-50,50) * rim$ystep)
The following is a list of im objects of size 100x100
imlist <- solapply(seq_len(npoints(pts)),
function(i) rim[shift(Box, pts[i])])
Here is a plot of the im objects in the region and the points on top
plot(pts)
for(i in imlist) plot(i, add = TRUE)
plot(pts, pch = 19, add = TRUE)
You can convert to a list of raster layers with
rasterList <- lapply(imlist, as, Class = "RasterLayer")
PS: The following is a list of im objects of the original size with
NA outside the 100x100 box if you need that format instead
imlist <- solapply(seq_len(npoints(pts)),
function(i) rim[shift(Box, pts[i]), drop = FALSE])
If you want to use spatstat then you need to convert the raster object r into an object of class im supported by spatstat. You can do this conversion in the maptools package. Call this image object rim. Then you can do as follows
Box <- owin(c(-50,50) * rim$xstep, c(-50,50) * rim$ystep)
BoxesUnion <- MinkowskiSum(pts, Box)
W <- intersect.owin(as.mask(rim), BoxesUnion)
This would give you the subset of the raster that is covered by the squares.
If you want to keep the squares separate, do something like
M <- as.mask(rim)
BoxList <- solapply(seq_len(npoints(pts)),
function(i) intersect.owin(M, shift(Box, pts[i])))
Then BoxList is a list of the individual sub-rasters.

Spatial interpolation (Kriging), polygon instead of raster output

Is there a (easy) way to convert a SpatialPixelsDataFrame (from krige) to e.g. a SpatialPolygonsDataFrame (vectorgraphic instead of pixelgraphic).
It would be fine to set value ranges and interpolate the raster to a polygon or use another krige method that generates a SpatialPolygonsDataFrame. I'm looking forward to a simple example.
krige example: i.e. in the book https://oscarperpinan.github.io/spacetime-vis/ 8.1.5 Spatial Interpolation, complete source https://github.com/oscarperpinan/spacetime-vis/blob/master/bubble.R
library(gstat)
airGrid <- spsample(NO2sp, type="regular", n=1e5)
gridded(airGrid) <- TRUE
airKrige <- krige(mean ~ 1, NO2sp, airGrid)
spplot(airKrige["var1.pred"],
col.regions=colorRampPalette(airPal)) + ...
Something like this might work:
library(raster)
x <- raster(airKrige["var1.pred"])
y <- cut(x, c(10,20,30,40,50,60,70))
z <- rasterToPolygons(y, dissolve=TRUE)
spplot(z)

Plotting netcdf in R with correct grid

My goal is to plot nitrate (no3) data on a world map, using the correct longitude and latitude for these data.
There are two netcdf files:
1. with the data
2. with the grid information
Summary info on the data:
no3 is an array of length x*y*sigma
no3_df is 'x*y obs. of 3 variables'
x = integer [180]
y = integer [193]
sigma = array[53]
I want to look at sigma ('depth') 20. I therefore did the following:
# Load the needed libraries to handle netcdf files
library(ncdf)
library(akima)
# Open data and grid files
file1 <- open.ncdf(file.choose())
grid <- open.ncdf(file.choose())
# Read relevant variables/parameters from data file1
x <- get.var.ncdf(file1,varid="x")
y <- get.var.ncdf(file1,varid="y")
sigma <- get.var.ncdf(file1,varid="sigma")
no3 <- get.var.ncdf(file1,varid="no3")
sigma_plot <- no3[,,sigma=20]
# Read relevant variables/parameters from grid file
plon <- get.var.ncdf(grid,varid="plon")
plat <- get.var.ncdf(grid,varid="plat")
# Each cell of sigma_plot corresponds to one cell of plon and plat.
A <- array(c(plon,plat,sigma_plot),dim=c(180,193,3))
# Now B is an array containing for each row: (longitude, latitude, value).
B <- apply(A, 3, cbind)
# But it is not a regular grid, so interpolate to a regular grid. akima library
C <- interp(B[,1],B[,2],B[,3],
xo=seq(-180,180,1),yo=seq(-90,90,by=1), # tweak here the resolution
duplicate='mean') # extra y values are duplicates
#########
# PLOTTING
#########
# This one works, but doesn't have a correct longitude and latitude:
filled.contour(x,y,sigma_plot, col=rich.colors(18))
# Try to plot with lon and lat
filled.contour(C, col=rich.colors(30))
Since the filled.contour plot doesn't have correct longitude and latitude, I would like to use ggplot. However, I don't know how to do this...
# And the plotting with ggplot
ggplot(aes(x=plon_datafrm,y=plat_datafrm),data=no3_df) +
geom_raster() +
coord_equal() +
scale_fill_gradient()
This doesn't seem to work. I am net to ggplot so that might be the reason, I would truly appreciate any help.
library(ncdf)
data <- open.ncdf(file1)
no3 <- get.var.ncdf(data,varid="no3")
sigma_plot <- no3[,,20]
grid <- open.ncdf(file2)
plon <- get.var.ncdf(grid,varid="plon")
plat <- get.var.ncdf(grid,varid="plat")
Contrary to what I previously understood, each cell of sigma_plot corresponds to one cell of plon and plat.
A <- array(c(plon,plat,a),dim=c(180,193,3))
B <- apply(A, 3, cbind)
Now B is an array containing for each row: (longitude, latitude, value). But it is not a regular grid, so you need to interpolate a regular grid. Easiest way would be using interp from package akima:
library(akima)
C <- interp(B[,1],B[,2],B[,3],
xo=seq(-180,180,1),yo=seq(-90,90,by=1), #you can tweak here the resolution
duplicate='mean') #for some reasons some entries are duplicates, i don t know how you want to handle it.
image(C) #for instance, or filled.contour if you prefer
library(maptools)
data(wrld_simpl)
plot(wrld_simpl, add=TRUE, col="white") #To add a simple world map on top

Resources