Raster not cropping to shapefile - r

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)

Related

clip raster by SpatialPolygonDataFrame

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)

How to replace values that correspond to polygons by NA?

I have a raster and a shapefile:
library(cartography)
library(sf)
library(raster)
r <- raster(matrix(rnorm(10*12), nrow=10), xmn = -180, xmx= 180, ymn = -90, ymx= 90)
mtq <- st_read(system.file("gpkg/mtq.gpkg", package="cartography"), quiet = TRUE)
I would like to intersect the raster r with the shapefile mtq and make the corresponding pixels to the all polygons as NA (replace the values of the pixels in the raster by NA) and return the raster.
You are likely looking for mask; it lives in both oldish {raster} and shiny new {terra}.
Note that I had to rewrite your r object a bit, as it was not quite compatible with the Martinique vector object from {cartography}.
Edit: if, as seems to be indicated in the comments, you are looking for replacing with NAs the values inside the polygon (and not outside) my answer is still raster::mask(), only with a little tweaking of the masking object (you need the inverse of the polygon over the extent of your raster).
library(cartography)
library(sf)
library(raster)
mtq <- st_read(system.file("gpkg/mtq.gpkg", package="cartography"), quiet = TRUE) %>%
dplyr::summarise() # dissolve internal boundaries
r <- raster(matrix(rnorm(10*12), nrow=10),
xmn = st_bbox(mtq)["xmin"],
xmx= st_bbox(mtq)["xmax"],
ymn = st_bbox(mtq)["ymin"],
ymx= st_bbox(mtq)["ymax"],
crs = st_crs(mtq))
plot(r) # original raster - full extent + range
# the masking object:
mask <- st_bbox(r) %>% # take extent of your raster...
st_as_sfc() %>% # make it a sf object
st_set_crs(st_crs(mtq)) %>% # in CRS of your polygon
st_difference(mtq) %>% # intersect with the polygon object
st_as_sf() # interpret as sf (and not sfc) object
result <- r %>%
mask(mask)
plot(result)
plot(st_geometry(mtq), add = T)

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)

How can I add a lat-long grid to a projected map?

EDIT: question really pertains to how one can add lat/long gridlines to a projected map. I changed title to match.
I have some layers in geographic coords. I want to plot them in LCC projection, but have a geographic (lat/long) grid. From mapproj I can use map.grid() to add a grid, with the limits set by the lim argument. It takes a vector or a range object:
a vector of 4 numbers specifying limits: c(lon.low, lon.high, lat.low,
lat.high). lim can also be a list with a component named range, such
as the result of map, from which limits are taken.
I construct my map by clipping a large vector layer with a clipping polygon:
myPoly <- readOGR(dsn=".", layer="myPolygon") # just a shapefile in geographic coords
library(raster) # To convert an 'extent' object to a SpatialPolygons object
cp <- as(extent(146, 149, -39, -37.5), "SpatialPolygons")
proj4string(cp) <- CRS(proj4string(myPoly)) # copy from shapefile
# Transform and plot:
lcc <- CRS("+init=epsg:3111")
myPoly.proj <- spTransform(myPoly, lcc)
cp.proj <- spTransform(cp, lcc) # transform the clip box
myPoly.proj.clip <- gIntersection(myPoly.proj, cp.proj, byid=TRUE)
plot(myPoly.proj.clip)
# Then finally, add a lat/long grid:
map.grid(lim=as.vector(cp.proj#bbox), labels=TRUE)
That last line is not correct, as the #bbox returned is xmin, ymin, xmax, ymax, but needs to be in xmin, xmax, ymin, ymax. There must be a simple solution to all this, but as usual I am lost in the vortex. I could manually create a limits vector, but really?
EDIT: the OP points out rgdal::llgridlines which is a better solution.
You are using context from sp/rgdal which uses a different system to that of mapproj/maps.
Try this (untested):
library(rgdal)
gl <- gridlines(myPoly)
cp.gl <- spTransform(gl, lcc)
plot(cp.gl, add = TRUE)
See ?gridlines for more on using this with labels. I find it works well as long as you stay away from circumpolar maps.

How to create a raster brick with rasters of different extents?

I am new in R so this question is very basic but I have been struggling with it and could not find a solution that worked. I want to create a raster brick from some landsat images of the same area.
They were downloaded in HDF-EOS format, and I used the Modis Reprojection Tool to convert them to .tif.
The resulting rasters have the same projection, but differ in their extent, resolution and origin.
I tried several approaches, summarized here below:
defining a subset extent manually and subsetting all the rasters. Then trying to make a brick with the subset rasters
Resampling the rasters, to give them the same number of columns and rows. Ideally that would ensure the raster cells are aligned and can be put into a raster brick. This option created a brick where rasters had no values, they were empty.
I am wondering what is the concept I should follow to correct the extent. Would it be correct (and efficient) to create an empty raster that I would fill in later with the values of the imported landsat image? Can you see where I am making a mistake?
In case it is relevant, I am working on a Mac OSX Version 10.9.1, and using rgdal version 0.8-14
Any help will be very appreciated!
Thankyou
I add here the code I have been using:
# .tif files have been creating using the Modis Reprojection Tool. Input
# files used for this Tool was LANDSAT HDF-EOS imagery.
library(raster)
library(rgdal)
setwd()=getwd()
# Download the files from dropbox:
dl_from_dropbox <- function(x, key) {
require(RCurl)
bin <- getBinaryURL(paste0("https://dl.dropboxusercontent.com/s/", key, "/", x),
ssl.verifypeer = FALSE)
con <- file(x, open = "wb")
writeBin(bin, con)
close(con)
message(noquote(paste(x, "read into", getwd())))
}
dl_from_dropbox("lndsr.LT52210611985245CUB00-vi.NDVI.tif", "qb1bap9rghwivwy")
dl_from_dropbox("lndsr.LT52210611985309CUB00-vi.NDVI.tif", "sbhcffotirwnnc6")
dl_from_dropbox("lndsr.LT52210611987283CUB00-vi.NDVI.tif", "2zrkoo00ngigfzm")
# Create three rasters
tif1 <- "lndsr.LT52210611985245CUB00-vi.NDVI.tif"
tif2 <- "lndsr.LT52210611985309CUB00-vi.NDVI.tif"
tif3 <- "lndsr.LT52210611987283CUB00-vi.NDVI.tif"
r1 <- raster(tif1, values=TRUE)
r2 <- raster(tif2, band=1, values=TRUE)
r3 <- raster(tif3, band=1, values=TRUE)
### Display their properties
# projection is identical for the three rasters
projection(r1)
# "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
projection(r2)
projection(r3)
# Extents are different
extent(r1)
# class : Extent
# xmin : -45.85728
# xmax : -43.76855
# ymin : -2.388705
# ymax : -0.5181549
extent(r2)
# class : Extent
# xmin : -45.87077
# xmax : -43.78204
# ymin : -2.388727
# ymax : -0.5208711
extent(r3)
# class : Extent
# xmin : -45.81952
# xmax : -43.7173
# ymin : -2.405129
# ymax : -0.5154312
# origin differs for all
origin(r1)
# 5.644590e-05 -8.588605e-05
origin(r2)
# 0.0001122091 -0.0001045107
origin(r3)
# 6.949976e-05 -5.895945e-05
# resolution differs for r2
res(r1)
# 0.0002696872 0.0002696872
res(r2)
# 0.0002696875 0.0002696875
res(r3)
# 0.0002696872 0.0002696872
## Try different approaches to create a raster brick
# a- define a subset extent, and subset all the rasters
plot(r1, main="layer1 NDVI")
de <- drawExtent(show=TRUE, col="red")
de
# class : Extent
# xmin : -45.36159
# xmax : -45.30108
# ymin : -2.002435
# ymax : -1.949501
e <- extent(-45.36159,-45.30108,-2.002435,-1.949501)
# Crop each raster with this extent
r1c <- crop(r1,e)
r2c <- crop(r2,e)
r3c <- crop(r3,e)
# Make raster brick
rb_a <- brick(r1c,r2c,r3c)
# Error in compareRaster(x) : different extent
# b- Resample each raster
s <- raster(nrow=6926, ncol=7735) # smallest nrow and ncol among r1,r2 and r3
r1_res <- resample(r1,s, method="ngb")
r2_res <- resample(r2,s, method="ngb")
r3_res <- resample(r3,s, method="ngb")
# Resampling gives for the three rasters the following message:
# Warning message:
# In .local(x, y, ...) :
# you are resampling y a raster with a much larger cell size,
# perhaps you should use "aggregate" first
# Make raster brick
rb_c <- brick(r1, r2, r3)
# Error in compareRaster(x) : different extent
here are some things to help you out. Since I don't have your .tif files just some hints. Have you checked the extent on your raster s? It's the size of the world, with just those columns its cells are extremely large. So you have to add an extent to your raster before resampling it. From your info I did something like this:
# create an extent that includes all your data
e<-extent(-46, -43, -2, -0.6)
# create a raster with that extent, and the number of rows and colums to achive a
# similar resolution as you had before, you might have to do some math here....
# as crs, use the same crs as in your rasters before, from the crs slot
s<-raster(e, nrows=7000, ncols=7800, crs=r1#crs)
# use this raster to reproject your original raster (since your using the same crs,
# resample should work fine
r1<-resample(r1, s, method="ngb")
Happy Holidays,
Ben
PS a better way to find your desired extent & resolution:
# dummy extent from your rasters, instead use lapply(raster list, extent)
a<-extent(-45.85728, -43.76855, -2.388705, -0.5181549)
b<-extent(-45.87077, -43.78204, -2.388727, -0.5208711)
c<-extent(-45.81952 ,-43.7173 , -2.405129 ,-0.5154312)
extent_list<-list(a, b, c)
# make a matrix out of it, each column represents a raster, rows the values
extent_list<-lapply(extent_list, as.matrix)
matrix_extent<-matrix(unlist(extent_list), ncol=length(extent_list)
rownames(matrix_extent)<-c("xmin", "ymin", "xmax", "ymax")
# create an extent with the extrem values of your extent
best_extent<-extent(min(matrix_extent[1,]), max(matrix_extent[3,]),
min(matrix_extent[2,]), max(matrix_extent[4,]))
# the range of your extent in degrees
ranges<-apply(as.matrix(best_extent), 1, diff)
# the resolution of your raster (pick one) or add a desired resolution
reso<-res(r1)
# deviding the range by your desired resolution gives you the number of rows and columns
nrow_ncol<-ranges/reso
# create your raster with the following
s<-raster(best_extent, nrows=nrow_ncol[2], ncols=nrow_ncol[1], crs=r1#crs)

Resources