Issue with making environmental raster layers identical for Maxent - r

I have nine raster layers (.tif) and each needs to have the same extent, resolution and CRS in order to work in Maxent.
I have tried converting each layer to the same CRS and translating them to .asc format in QGIS.
After that I tried to resample the layers in R to match one of the layers, but this resulted in errors, such as that the extents do not overlap.
My question is how do I match all these layers in order to proceed with Maxent and also to use the 'stack' function in R?
Here is the zip-file with the rasters: https://drive.google.com/file/d/1lle95SPdQ7FyQSbFoFvmAzyuO2HUt7-L/view?usp=sharing

So the initial problem is to set the crs using the 'crs' function from the raster package (I haven't used the new terra package yet). Then you need to reproject into the same crs. The next step is to resample the rasters so they all have the same cell resolution and size. Last you can put them in a stack. I was in a rush, so I didn't comment very well, but let me know if you have questions. The last point is the bedrock file. You'll need to use QGIS or another program to georeference it first. Try to find a map with a known projection that looks similar to it.
library(raster)
ls = list.files(".",pattern ="tif")
ls = ls[-which(ls == "bedrock.tif")]
r = lapply(ls,raster)
names(r) = ls
wgs84 = "+proj=longlat +datum=WGS84 +no_defs"
ETRS = "+proj=laea +lat_0=52 +lon_0=10 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +units=m +no_defs"
crs(r$wc2.1_2.5m_bio_1.tif) = wgs84
crs(r$wc2.1_2.5m_bio_12.tif) = wgs84
crs(r$wc2.1_2.5m_elev.tif) = wgs84
crs(r$SBPC1.tif) = ETRS
crs(r$SBPC2.tif) = ETRS
crs(r$SPPC1.tif) = ETRS
crs(r$SPPC2.tif) = ETRS
crs(r$U2018_CLC2018_V2020_20u1.tif) = ETRS
# aggregate for faster processing -- you'll want to change this, but my machine couldn't process it
ra <- lapply(r,aggregate,fact=10, fun=max)
# not all need to be reprojected - this is me being lazy
rp = lapply(ra,projectRaster, crs = ETRS)
# resample rasters to match
sapply(rp,area)
rpr = lapply(rp,resample, y = rp$SBPC1.tif)
sapply(rpr,area)
rs = stack(rpr)
plot(rs)

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?

Issues plotting spatial point data using tmap

I have created a class Large SpatialPointDataFrame from a csv file, and I am trying to plot the data points using tmap. When I plotted the SpatialPointDataFrame using plot(), everything looked fine. However, when I tried to plot it using tmap, it only shows one single point plus it is not where it should be, btw, the point that got shown is the last item in the data frame.
I'm thinking there might be something wrong with my projecton? CRS(Using SVY21 or EPSG:3414) properties of the SpatialPointDataFrame:
crs: +init=epsg:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs
This is how I converted the dataframe to a spatialpointdataframe, where listing is the original dataframe read from a csv file.
coords <- listing[ , c("latitude", "longitude")]
crs <- CRS("+init=epsg:3414")
listing_sp <- SpatialPointsDataFrame(coords = coords, listing, proj4string = crs)
Any suggestions on how I should debug?
In your code, where you have crs <- CRS("+init=epsg:3414"), you are assigning a projection but your source data has not yet been transformed to that projection. If your source data is in lat/lon it's meant to be used with the WGS84 projection (epsg code 4326).
Once you create your spatialPointDataFrame using the projection matching your coordinates, you simply have to reproject using spTransform. To reproject to SVY21, you still need to transform. Can't test without some reproducible data but it should look like this.
coords <- listing[ , c("latitude", "longitude")]
crs <- CRS("+init=epsg:4326")
listing_sp <- SpatialPointsDataFrame(coords = coords, listing, proj4string = crs)
listing_sp_svy21 <- spTransform(listing_sp, CRS("+init=epsg:3414"))

R - transition function for modelling surface water flow with gdistance

I am trying to model overland (surface) water flow from specified origin points to a single downslope goal point using the gdistance shortestPath function. I need help with defining the appropriate transitionFunction for this, as I need to make sure the least cost path only allows water to flow along the path to elevation cells of equal or lesser value than the previous cell. The transitionFunction in the example below selects the minimum elevation cell but, based on the transitionFunction I have defined, this value may still be greater than the previous cell value.
I realize that, when the above is defined as I want it, the path may terminate before reaching the goal point. This is fine, although I would ideally like to be able to preserve the path from the origin to wherever it terminates if possible.
Also, if anyone knows of a different R package capable of modelling this kind of thing, please let me know.
library(gdistance)
library(raster)
library(elevatr)
library(sp)
#load example DEM raster
data(lake)
elevation <- get_elev_raster(lake, z = 9)
#remove negative elevation values from raster
elevation[elevation < 0] <- NA
#create origin and goal points with same projection as elevation raster
origin <- SpatialPoints(cbind(1790000, 640000), proj4string = CRS("+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs +ellps=GRS80 +towgs84=0,0,0"))
goal <- SpatialPoints(cbind(1820000, 540000), proj4string = CRS("+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs +ellps=GRS80 +towgs84=0,0,0"))
#create df data and convert to SpatialPointsDataFrame
odf <- data.frame("flowreg" = 1)
gdf <- data.frame("flowreg" = 2)
origindf <- SpatialPointsDataFrame(origin, odf)
goaldf <- SpatialPointsDataFrame(goal, gdf)
trCost1 <- transition(elevation, transitionFunction=function(x) 1/min(x), directions=8)
trCost1gc <- geoCorrection(trCost1, type="c")
plot(raster(trCost1))
sPath1 <- shortestPath(trCost1, origin, goal,
output="SpatialLines")
plot(elevation)
plot(origindf, add = TRUE, col='red', cex = 5)
plot(goaldf, add = TRUE, col='green', cex = 5)
lines(sPath1)
I have found the GRASS GIS (accessed in R using rgrass7) r.drain function OR raster::flowPath achieve what I am trying to do in the above question.

Create Distance to Shore (km) Variable from Lat Lon data?

I have a data-frame with 3k + data points spread throughout the northern Gulf of Mexico (here I only provide 6). I am trying to create a new variable for is distance to shore (km). I have a shape-file (gulf.shape) which I would like to use but I'm not clear on how.
Here is some data
require(maptools)
require(sp)
library(rgdal)
library(lubridate)
df <- data.frame(Lat = c(26.84853, 28.38329, 28.00364,
29.53840, 29.32030, 26.81622, 25.28146),
Lon = c(-96.55716, -94.29307, -91.21581,
-88.42556, -84.20031, -83.89737, -82.95665))
and I load the shapefile (provided here).
gulf.shape <- "Shape\\stateshigh.shp"
gulf.shape <- maptools::readShapePoly(gulf.shape)
and a quick plot to visualize what I have.
plot(df$Lon, df$Lat,
xlim = c(-97.5, -80.7), ylim = c(25, 30.5),
xlab ="Latitude", ylab = "Longitude",
pch = 20, col="red", cex=1.5)
par(new=T)
sp::plot(gulf.shape, add= T,
xlim = c(-97.5, -80.7), ylim = c(25, 30.5),
xlab ="Latitude", ylab = "Longitude",
col = "gray")
I found a stack overflow post (here), which allowed me to get an answer using the code below. The shape file they use is available here.
require(rgdal) # for readOGR(...); loads package sp as well
require(rgeos) # for gDistance(...)
require(parallel) # for detect cores
require(foreach) # for foreach(...)
require(snow) # for makeCluster(...)
require(doSNOW) # for resisterDoSNOW(...)
wgs.84 <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
mollweide <- "+proj=moll +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"
sp.points <- SpatialPoints(df[,c("Lon","Lat")], proj4string=CRS(wgs.84))
coast <- rgdal::readOGR(dsn=".",layer="ne_10m_coastline",p4s=wgs.84);str(coast)
coast.moll <- spTransform(coast,CRS(mollweide))
point.moll <- spTransform(sp.points,CRS(mollweide))
no_cores <- detectCores()
cl <- makeCluster(no_cores,type="SOCK") # create a 4-processor cluster
registerDoSNOW(cl) # register the cluster
get.dist.parallel <- function(n) {
foreach(i=1:n, .combine=c, .packages="rgeos", .inorder=TRUE,
.export=c("point.moll","coast.moll")) %dopar% gDistance(point.moll[i],coast.moll)
}
df$Dis.to.SHORE <- get.dist.parallel(length(sp.points))
df$Dis.to.SHORE <- df$Dis.to.SHORE/1000
df
plot(coast)
points(sp.points,pch=20,col="red")
However, I do not understand the CRS code used in wgs.84 and mollweide and this makes me uneasy about using the data generated with this code. I would also like to use just the gulf.shape file and not the whole world, since there was some suggestion in the previously mentioned stack overflow post that this would be better.
So my questions are:
Are the values I'm getting for distance to shore reasonably accurate (i.e. within 5 - 10m)?
How can I modify the code to utilize the gulf.shape file rather than the whole world?
Can anyone explain the CRS code or point me toward a good reference?
Note that I use parallel computing to speed things up since I have more than 6 data points in reality.
I'll try to answer your 3rd question.
CRS (Coordinate Reference System) is quite important in mapping as it defines the coordinate system of your points. Here's a helpful overview.
https://www.nceas.ucsb.edu/~frazier/RSpatialGuides/OverviewCoordinateReferenceSystems.pdf
For your particular situation, when you change to a different shapefile, you'll need to (1) find out what the CRS is for your shapefile (gulf.shape). Usually, it's in the .prj file or metadata that comes with the shapefile. (2) pick a CRS that's suitable for your goal. You are calculating distance, so an equidistant projection likely is most helpful to you. (3) transform the original crs to the target crs before calculating the distance.
The code you cited was also doing this. The world shapefile came with wgs84 crs; the chosen target crs was mollweide; and it converted wgs84 to mollweide using the spTransform() function.
On another note, related to your 1st question, the accuracy of your calculation is related to the crs you use, but is also related to the scale of your shapefile, and precision of your points (lat/long).

Using R to change raster projection

I'm trying to change raster projection using R and the raster package. The input raster projection is Lambert Azimuthal; the parameters are here:
Coordinate System:
Lambert_Azimuthal_Equal_Area
False_Easting: 4321000,000000
False_Northing: 3210000,000000
Central_Meridian: 10,000000
Latitude_Of_Origin: 52,000000
GCS_ETRS_1989
Datum: D_ETRS_1989
Prime Meridian: 0
PROJCS
["ETRS_1989_LAEA",
GEOGCS ["GCS_ETRS_1989",
DATUM ["D_ETRS_1989",
SPHEROID ["GRS_1980",6378137.0,298.257222101]],
PRIMEM["Greenwich",0.0],
UNIT["Degree",0.0174532925199433]],
PROJECTION["Lambert_Azimuthal_Equal_Area"],
PARAMETER["False_Easting",4321000.0],
PARAMETER["False_Northing",3210000.0],
PARAMETER["Central_Meridian",10.0],
PARAMETER["Latitude_Of_Origin",52.0],
UNIT["Meter",1.0]]
I need to convert them to simple rasters in ESRI ASCII format, using longitude and latitude coordinates, with a Mercator-style projection, with a cell size of 0.1 degrees (I hope I explain myself well enough, because I don't have enough GIS skills, sorry). What I need are rasters in format .ASC where each value of the raster corresponds to a single cell of size N x N, where N is in degrees (e.g. 0.1 degrees), and the raster coordinates are in longitude/latitude.
I tried to use raster library in R, and follow examples found for the projectRaster function. But after many attempts using many several parameters, I wasn't be able to make it correctly. I think I'm not using the correct parameters for projection, datum, or something like this.
Here's what I tried. I load the raster in R, then I set its projection using:
>crs(r)<-"+proj=laea +lat_1=52 +lon_0=-10 +ellps=GRS80"
Then I define the output projection and I try the conversion and save:
>newproj <- "+proj=lonlat +lat_1=52 +lon_0=-10 +ellps=WGS84"
>pr2 <- projectRaster(r, crs=newproj, res=0.1)
>writeRaster(pr2, "newraster.asc", overwrite=TRUE)
No error messages, but resulting raster is not correctly projected (country borders don’t match, countries are slightly distorted).
Thanks for any help!
Given the description of the projection you provide, this seems wrong:
crs(r) <- "+proj=laea +lat_1=52 +lon_0=-10 +ellps=GRS80"
As you do not include the false northing and easting parameters; and lat_1 should probably be lat_0. This may be better:
crs(r) <- "+proj=laea +lat_0=52 +lon_0=10 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +units=m"
This also looks odd:
newproj <- "+proj=lonlat +lat_1=52 +lon_0=-10 +ellps=WGS84"
How about
newproj <- "+proj=longlat +datum=WGS84"

Resources