clip raster by SpatialPolygonDataFrame - r

I have a raster, and want to only retain the sea part of the raster, and remove the land part or the raster. If my raster is "ras" and my SpatialpolygonDataFRame is "worldMap", I tried
ras.msk <- rgeos::gDifference(ras,worldMap)
however, I get the following error which I do not understand, but I gather that the function can only be used with two spdf's, not with a raster?
Error in RGEOSUnaryPredFunc(spgeom, byid, "rgeos_isvalid") : rgeos_convert_R2geos: invalid R class RasterLayer, unable to convert.
if I do
r2 <- crop(ras, worldMap)
r3 <- mask(r2, worldMap)
I get the land-part of the raster. How do I get the opposite so that the remaining raster excludes the overlapping spatialpolygondataframe area?
The end result I need is all raster point values at sea to be 1, and the raster point values on land to be 0.
My current code is as follows:
# Make raster layer of study area
ras = raster(ext=extent(-70, -55, -60, -38), res=c(0.01,0.01)) #lat/long xmin, xmax, ymin, ymax #
#give all raster points a "1"
ras[] <- 1
#project the raster
projection(ras) <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
# load land
library(rworldmap)
worldMap <- getMap(resolution = "high")
projection(worldMap) <- CRS(proj4string(ras))
#crop raster by land
ras.msk <- rgeos::gDifference(ras,worldMap)

Need to specify "inverse = T" in the mask function
r2 <- crop(ras, worldMap)
r3 <- mask(r2, worldMap, inverse = T)

Related

How to calculate area of polygon that does not overlap with other polygons in R?

I have a SpatialPoints object with the coordinates for several points of interest.
I also have several shapefiles (polygons) with information about the presence of slums. The polygons with info about slums in each of these shapefiles can overlap (they provide somewhat the same information about the presence of slums, but come from different sources).
For each of the points in my SpatialPoints object, I have used the function spCircle to create a circular polygon around each point. What I need to do next is to check what percentage of the area of the circular polygon contains slums. If any of the shapefiles indicates that the slum is present, I will consider that there is a slum in the area.
I have created the following image to help explain my issue. The circles represent the polygon around a single point. For this single point, each of the four shapefiles indicates that the slum is present in somewhat different areas (sometimes they overlap, and sometimes they do not). I want to be able to find the red area (where none of the shapefiles indicate the presence of the slum, and then calculate the percentage of the circle that has slums.
The following code is an attempt to do that:
# Create data with coordinates
lat = c(-22.868879628748203,-22.88511,-22.82166,-22.89692,-22.67945)
long = c(-43.237195000177564,-43.34278,-43.04717,-43.35168,-43.59667)
data_points = cbind.data.frame(lat,long)
coordinates(data_points) = c("lat","long")
proj4string(data_points) = CRS("+init=epsg:4326")
# Transform projection of points to UTM
utmStr <- "+proj=utm +zone=%d +datum=NAD83 +units=m +no_defs +ellps=GRS80"
crs <- CRS(sprintf(utmStr, 23))
data_points = spTransform(data_points, crs)
# Create a list with circular polygons around each point (radius = 2000 meters)
circular_grid = list()
for (i in 1:length(data_points)){
spc = spCircle(radius = 2000, centerPoint = c(x=as.numeric(data_points#coords[i,1]), y=as.numeric(data_points#coords[i,2])), spID=i,
spUnits = CRS("+proj=utm +zone=23 +datum=NAD83 +units=m +no_defs"))
circular_grid[[i]] = spc
}
# For each circle, check the percentage that overlaps with several different shapefiles:
# I first use gUnion to merge all the shapefiles with info about slums together
allShapes = gUnion(shape1,shape2)
allShapes = gUnion(allShapes, shape3)
allShapes = gUnion(allShapes, shape4)
allShapes = gUnion(allShapes, shape5)
allShapes = gUnion(allShapes, shape6)
allShapes = as(allShapes, "SpatialPolygonsDataFrame")
allShapes = spTransform(allShapes, CRS("+proj=utm +zone=23 +datum=NAD83 +units=m +no_defs"))
# I am unable to reproduce the object "allShapes" (I do not know how),
# but this is its information
# class : SpatialPolygonsDataFrame
# features : 1
# extent : 633347.1, 724692.1, -2547787, -2513212 (xmin, xmax, ymin, ymax)
# crs : +proj=utm +zone=23 +datum=NAD83 +units=m +no_defs
# variables : 1
# names : dummy
# value : 0
# Next, to get the intersection, I tried the following:
intersection_circle_shape = list()
for (i in 1:length(circular_grid)){
circle = circular_grid[[i]][["spCircle"]]
inter = intersect(circle, allShapes)
intersection_circle_shape[[i]] = inter
}
# The list "intersection_circle_shape" is empty because the command
# "intersect" says that there is no intersection, but I know there is.
Any ideas?

Counting number of points on a raster layer in R

I've got a map with certain number of points on it. I want to (1) calculate the number of points that fall within the raster layer, and (2) extract these points to a data frame.
This is what I've done:
# Packages
library(raster)
library(ggplot2)
library(maptools)
library(tidyverse)
library(dplyr)
library(sp)
# Transform tree ring kml to dataframe
zz<-getKMLcoordinates('treering.kml', ignoreAltitude=TRUE)
l<-as.data.frame(zz)
l<-t(l)
tree <-SpatialPointsDataFrame(l, l,
proj4string = CRS(" +proj=longlat +ellps=WGS84 +datum=WGS84
+no_defs +towgs84=0,0,0"))
# Get world map
data(wrld_simpl)
# Transform World to raster
r <- raster(wrld_simpl, res = 1)
wrld_r <- rasterize(wrld_simpl, r)
# Import permafrost layer to raster
dist1<-raster("PZI.flt")
# Set CRS
dist1 <- projectRaster(from = dist1, crs = CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs
+towgs84=0,0,0"))
# Change colours
micolor <- rev(rainbow(12, alpha = 0.35))
transp <- rainbow(12, alpha = 0)
micolor[1:3] <- transp[1]
# Plot all
plot(wrld_r, col = "lightgrey")
plot(dist1, add=TRUE, legend = F, col = micolor)
plot(tree, add=T, pch = 20, col='black', cex=0.2)
I want to calculate and extract black points located on the colorful parts of this map
First raster::projectRaster does not "set" the projection but, rather reprojects the raster given a transformation and resampling. Given the computational requirements of this it is much faster to reproject the point data using sp::spTransform. Once your data is in the same projection space, you can use raster::extract to extract the raster values. Values out side the raster or in nodata (NA) areas will be assigned NA values. You can drop these observations using a simple NA index with which.
It looks like your data may have a constant value outside of the permafrost. Once you identify what this value is (eg., 0) you can remove these points as well. Here is a worked example. First we add packages and create some example data that is similar to yours.
library(sp)
library(raster)
dist1 <- raster(nrow=20, ncol=20)
dist1[] <- sample(1:10, ncell(dist1), replace=TRUE)
dist1[200:400] <- 0
trees <- sampleRandom(dist1, 100, sp=TRUE)
plot(dist1)
plot(trees,pch=20,col="red",add=TRUE)
Now, we extract the raster values and look at the dimensions of the point object (please note that I do not have to use the sp=TRUE argument in the raster::extract function).
trees#data <- data.frame(trees#data, dist1 = extract(dist1, trees))
dim(trees)
Now we create a row index indicating which rows contain zeros, make sure that we have identified rows (using an if statement) and then remove them. Looking at the object dimensions again, we can see how many points were removed from the original point data.
( idx <- which(trees$dist1 %in% 0) )
if(length(idx) > 0) trees <- trees[-idx,]
dim(trees)

Draw polygon from raster after occurrence modeling

I want to draw polygons for species occurrence using the same methods BIEN uses, so I can use both my polygons and theirs. They use Maxent to model species occurrence when they have more then occurrence points.
So, this is, for example, a BIEN polygon:
library(BIEN)
Mormolyca_ringens<- BIEN_ranges_load_species(species = "Mormolyca ringens")
#And this is a polygon, yes. A SpatialPolygonsDataFrame.
plot(wrld_simpl, xlim=c(-100,-40), ylim=c(-30,30), axes=TRUE,col="light yellow", bg="light blue")
plot(Mormolyca_ringens, col="green", add=TRUE)
Mormolyca ringens polygon
Ok, then I'm trying to draw my polygons because BIEN lacks some for species I need.
# first, you need to download the Maxent software here: http://biodiversityinformatics.amnh.org/open_source/maxent/
#and paste the "maxent.jar" file in the ’java’ folder of the ’dismo’ package, which is here:
system.file("java", package="dismo")
#You have to do this **before** loading the libraries
#install.packages("rJava")
library(rJava)
#If you get the message that cannot load this library, it's possible that your version of java is not 64bit.
#Go to Oracle and install Java for windows 64bit.
#If library still doesn't load: Look in your computer for the path where the java's jre file is and paste in the code below
Sys.setenv(JAVA_HOME="your\\path\\for\\jre") #mine is "C:\\Program Files\\Java\\jre1.8.0_144", for example
library(rJava)
library(dismo)
library(maptools)
#Giving credits: I wrote the following code based on this tutorial: https://cran.r-project.org/web/packages/dismo/vignettes/sdm.pdf
#Preparing the example data - the map
data(wrld_simpl)
ext = extent(-90, -32, -33, 23)
#Preparing the example data - presence data for Bradypus variegatus
file <- paste(system.file(package="dismo"), "/ex/bradypus.csv", sep="")
bradypus <- read.table(file, header=TRUE, sep=',')
bradypus <- bradypus[,-1] #don't need th first col
#Getting the predictors (the variables)
files <- list.files(path=paste(system.file(package="dismo"),
'/ex', sep=''), pattern='grd', full.names=TRUE )
predictors <- stack(files)
#making a training and a testing set.
group <- kfold(bradypus, 5)
pres_train <- bradypus[group != 1, ]
pres_test <- bradypus[group == 1, ]
#Creating the background
backg <- randomPoints(predictors, n=1000, ext=ext, extf = 1.25)
colnames(backg) = c('lon', 'lat')
group <- kfold(backg, 5)
backg_train <- backg[group != 1, ]
backg_test <- backg[group == 1, ]
# Running maxent
xm <- maxent(predictors, pres_train, factors='biome')
plot(xm)
#A response plot:
response(xm)
# Evaluating and predicting
e <- evaluate(pres_test, backg_test, xm, predictors)
px <- predict(predictors, xm, ext=ext, progress='text', overwrite=TRUE)
#Checking result of the prediction
par(mfrow=c(1,2))
plot(px, main='Maxent, raw values')
plot(wrld_simpl, add=TRUE, border='dark grey')
tr <- threshold(e, 'spec_sens')
plot(px > tr, main='presence/absence')
plot(wrld_simpl, add=TRUE, border='dark grey')
points(pres_train, pch='+')
At this point, I have the following image:
Prediction for example's occurrence
And I'm trying to make a polygon from this raster with this code:
predic_pol<-rasterToPolygons(px )
And also:
px_rec<-reclassify(px, rcl=0.5, include.lowest=FALSE)
px_pol<-rasterToPolygons(px_rec)
But i keep getting a pixels version of my extent
Can you please give me a hint so I can extract a polygon out of this raster, like the BIEN's one? (Also I'm new to modeling and to R... any tips are welcome)
EDIT: this is the px console output:
> px
class : RasterLayer
dimensions : 172, 176, 30272 (nrow, ncol, ncell)
resolution : 0.5, 0.5 (x, y)
extent : -120, -32, -56, 30 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
data source : C:\Users\thai\Documents\ORCHIDACEAE\Ecologicos\w2\predictions\Trigonidiumobtusum_prediction.grd
names : layer
values : 6.705387e-06, 0.9999983 (min, max)
Thank you in advance
Edit 2: Solution
Thanks to #Val I got to this:
#Getting only the values>tr to make the polygon
#"tr" is what gives me the green raster instear of the multicolour one
pol <- rasterToPolygons(px>tr,function(x) x == 1,dissolve=T)
#Ploting
plot(wrld_simpl, xlim=c(-120,-20), ylim=c(-60,10), axes=TRUE,col="light yellow", bg="light blue")
plot(pol, add=T, col="green")
And now I have what I wanted! Thank you!
(The polygon is not the same in the figures only because I used a different data set I had at my environment at the moment I got #Val 's answer)
Bonus question:
Do you know how to smooth the edges so I get a non pixelized polygon?
I don't know BIEN, so I din't really look at this part of your example. I just generalized your problem/question down to the following:
You have a binary raster (with 0 for absence and 1 for presence) and you want to convert all areas with 1 to a polygon.
As for your px raster, it's a bit odd that your values are not 0 and 1 but more basically 0 and basically 1. But if that's a problem, that can be an easy fix.
So I tried to recreate your example with just the area of Brasil:
library(raster)
library(rgeos)
# get Brasil borders
shp <- getData(country = 'BRA',level=0)
#create binary raster
r <- raster(extent(shp),resolution=c(0.5,0.5))
r[] <- NA # values have to be NA for the buffering
# take centroid of Brasil as center of species presence
cent <- gCentroid(shp)
# set to 1
r[cellFromXY(r,cent)] <- 1
# buffer presence
r <- buffer(r,width=1000000)
# set rest 0
r[is.na(r)] <- 0
# mask by borders
r <- mask(r,shp)
This is close enough to your raster I guess:
So now to the conversion to the polygon:
pol <- rasterToPolygons(r,function(x) x == 1,dissolve=T)
I use a function to only get pixels with value 1. Also I dissolve the polygons to not have single pixel polygons but rather an area. See rasterToPolygons for other options.
And now plot the borders and the new polygon together:
plot(shp)
plot(pol,col='red',add=T)
And there you have it, a polygon of the distribution. This is the console output:
> pol
class : SpatialPolygonsDataFrame
features : 1
extent : -62.98971, -43.48971, -20.23512, -1.735122 (xmin, xmax, ymin, ymax)
coord. ref. : NA
variables : 1
names : layer
min values : 1
max values : 1
Hope that helps!
Edit: Bonus answer
You have to be clear, that the pixelized boundaries of your polygon(s) represent an accurate representation of your data. So any change to that means a loss of precision. Now, depending on your purpose, that might not matter.
There's multiple ways to achieve it, either at the raster side with disaggregating and smoothing/filtering etc. or at the polygon side, where you can apply specific filters to the polygons like this.
If it's purely aesthetic, you can try gSimplify from the rgeos package:
# adjust tol for smoothness
pol_sm <- gSimplify(pol,tol=0.5)
plot(pol)
lines(pol_sm,col='red',lwd=2)

Creating a raster file from a kernel smooth with differing x,y resolutions

I have a set of GPS data which I am attempting to kernel smooth using the bkde2d in the 'kernsmooth' package. I have used the Hpi bandwidth estimator in the 'ks' package to determine my bandwidth however when I run the kernel smooth and convert the resulting list into a raster the resulting product appears to have differing x, y resolutions and is therefore impossible to export as an ascii. It is also impossible to read this raster into a GIS tool when exporting as a GRD file as it appears to be corrupt, presumably due to having differing resolutions.
Here is some sample code from my run. My data is projected in UTM30, WGS84:
bnd=Hpi(x=cbind(GPS$lon, GPS$lat))
coord <- cbind(GPS$lon, GPS$lat)
est <- bkde2D(coord, bandwidth=bnd, gridsize = c(4000L, 4000L))
est.raster = raster(list(x=est$x1,y=est$x2,z=est$fhat))
projection(est.raster) <- CRS("+proj=utm +ellps=WGS84 +datum=WGS84 +zone=30 +north +units=km")`
xmin(est.raster) <- min(GPS$lon)
xmax(est.raster) <- max(GPS$lon)
ymin(est.raster) <- min(GPS$lat)
ymax(est.raster) <- max(GPS$lat)
writeRaster(est.raster, "kerntest", format='ascii')
The resulting raster layer looks like this:
class : RasterLayer
dimensions : 4000, 4000, 1.6e+07 (nrow, ncol, ncell)
resolution : 0.03242282, 0.03011303 (x, y)
extent : 415.2883, 544.9796, 6371.946, 6492.398 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +ellps=WGS84 +datum=WGS84 +zone=30 +units=km +towgs84=0,0,0
data source : in memory
names : layer
values : 0, 0.005935748 (min, max)
However when I attempt to export it I get the error message:
Error in .startAsciiWriting(x, filename, ...) :
x has unequal horizontal and vertical resolutions. Such data cannot be stored in arc-ascii format
My question is why are my resolutions different and how should I resolve this issue?
You can resample the raster to a new raster with equal x and y resolutions. You may lose some information this way. Alternatively you could make sure your gridsize in bkde2D would divide the x and y extents equally.
est.raster <- raster::resample(est.raster, raster(ext=extent(c(415.2883, 544.9796, 6371.946, 6492.398)),resolution=0.03,crs=projection(est.raster))
There are several issues with your example (including that we cannot reproduce it!). It should be something like this:
library(ks)
library(KernSmooth)
library(raster)
set.seed(0)
GPS <- data.frame(lon=runif(100), lat=runif(100)*2)
#bnd <- Hpi(GPS)
est <- bkde2D(GPS, bandwidth=0.1, gridsize = c(400L, 400L))
names(est) <- c('x', 'y', 'z')
est.raster <- raster(est)
# do not change the extent!
projection(est.raster) <- "+proj=utm +zone=30 +north +units=km +datum=WGS84"
writeRaster(est.raster, "kerntest", format='ascii')
There is nothing wrong with this object. But the file format you chose to use cannot save these data. Use another format! E.g.:
writeRaster(est.raster, "kerntest.tif")
You could also try to force bkde2D to produce a raster with square cells, using range.x
est <- bkde2D(GPS, bandwidth=0.1, gridsize = c(400L, 800L), range.x=list(c(1/800,1-1/800), c(1/800,2-1/800)))
names(est) <- c('x', 'y', 'z')
est.raster <- raster(est)
projection(est.raster) <- "+proj=utm +zone=30 +north +units=km +datum=WGS84"
writeRaster(est.raster, "kerntest", format='ascii')

Raster not cropping to shapefile

I'm attempting to merge some states from a shapefile, and produce a raster that I can use downstream. I have gotten the states merged, however when I am creating an empty raster to rasterize with the crop function seems to fail. I'm pretty new to the GIS features in R and really appreciate the help.
Shapefile is from http://www.arcgis.com/home/item.html?id=f7f805eb65eb4ab787a0a3e1116ca7e5
library(maptools)
library(shapefiles)
library(raster)
usa.states <- readOGR(dsn = "states_21basic/", layer = "states")
head(usa.states)
Co=usa.states[usa.states#data$STATE_NAME== "Colorado",]
Nm=usa.states[usa.states#data$STATE_NAME== "New Mexico",]
Az=usa.states[usa.states#data$STATE_NAME== "Arizona",]
Ut=usa.states[usa.states#data$STATE_NAME== "Utah",]
Corners= spRbind(spRbind(spRbind(Co,Ut),Nm),Az)
CRS="+proj=longlat +datum=WGS84"
Corners=spTransform(Corners, CRS(CRS))
> extent(Corners)
class : Extent
xmin : -114.8218
xmax : -102.0372
ymin : 31.33563
ymax : 42.0023
cor.ext=extent(Corners)
r<-raster(ncol=ncol(Corners), nrow=nrow(Corners), crs=CRS)
Corners.crop= crop(r,cor.ext, snap="out")
When I then call the extent of the 'Corners.crop' however I receive:
> extent(Corners.crop)
class : Extent
xmin : -180
xmax : -36
ymin : 0
ymax : 45
I'm confused to what I'm missing to get this to work.
I am also looking to have a 1Km resolution and am curious if it would be better to change the resolution on the empty raster or after I rasterize shape.
library(rgdal)
library(raster)
library(rgeos)
usa.states <- readOGR("states.shp", layer = "states")
# Here we subset once
Corners <- usa.states[usa.states$STATE_NAME %in% c("Colorado", "New Mexico","Arizona","Utah"),]
# Dissolve polygons into one
Corners <- gUnaryUnion(Corners)
# Create a 20x20 raster using the extent of Corners
# The number of rows and columns can be change to increase/reduce the resolution
r <- raster(extent(Corners), ncol=20, nrow=20, crs=CRS(proj4string(Corners)))
# Rasterize
Corners.crop <- rasterize(Corners, r)

Resources