Plotting points extracted from a dataframe in a Raster layer - r

I would like to plot points from a data frame into a raster layer that I have. For every point, I would like the value of the cell to be 1 (all the other cell on the initial raster layer have a value of zero).
My dataframe (data) looks like this (first three rows only)
Year<-c(2020, 2019, 2018)
Lat<-c(48.3,48.79,48.4)
Long<-c(-123.62, -123.36, -123.29)
I managed to plot those points with the following code
points = st_as_sf(data, coords = c("Long", "Lat"), crs = 4326)
plot(st_geometry(points), pch=16, col="navy")
And got this graph:
Graph points plotted
I now want to plot those points into a raster layer that I have for the area.
The parameters of my raster layer are as follow:
class : RasterLayer
dimensions : 44, 41, 1804 (nrow, ncol, ncell)
resolution : 0.2916667, 0.2916667 (x, y)
extent : -133.2625, -121.3042, 41.3875, 54.22083 (xmin, xmax, ymin, ymax)
crs : NA
names : Blank_Map
Every cell of this raster as a value of 0, which is what I need. Now, I would like to add the points from my dataframe to this raster layer, using of value 1 for every cell where those data points are. I would also like to save the whole thing as a new raster layer (which would then have 0 and 1 values).
Could anybody help me achieve this?
I have been trying for days, but nothing seems to work
any help is appreciated!

1. Please find below a reprex providing a possible solution using raster and sf libraries.
library(raster)
library(sf)
# Create from scratch the raster with 0 values
raster0 <- raster(nrows = 44, ncols = 41,
xmn = -133.2625, xmx = -121.3042,
ymn = 41.3875, ymx = 54.22083,
vals=0)
# Convert points 'sf' object into 'sp' object
points_sp <- as(points, "Spatial")
# Extract the cells of raster0 matching the points geometry of the 'sp' object
cells_ID <- extract(raster0, points_sp, cellnumbers=TRUE)[,"cells"]
# Copy raster0 (as you want the final result in another raster)
raster01 <- raster0
# Replace 0 values to 1 for cells matching points geometry in the 'raster01'
raster01[cells_ID] <- 1
# Visualization of the final result
plot(raster01)
Created on 2021-12-07 by the reprex package (v2.0.1)
2. Please find below a reprex providing another solution using terra and sf libraries
library(terra)
library(sf)
# Create from scratch the 'SpatRaster' with 0 values
raster0 <- rast(nrows=44, ncols=41,
nlyrs=1,
xmin=-133.2625, xmax=-121.3042,
ymin=41.3875, ymax=54.22083,
vals = 0)
# Convert points 'sf' object into 'SpatVector' object
points <- vect(points)
# Extract the cells of raster0 matching the points geometry of the 'sp' object
cells_ID <- terra::extract(raster0, points, cells = TRUE)
# Copy raster0 (as you want the final result in another raster)
raster01 <- raster0
# Replace 0 values to 1 for cells matching points geometry in the 'raster01'
raster01[cells_ID[,"cell"]] <- 1
# Visualization of the final result
plot(raster01)
Created on 2021-12-07 by the reprex package (v2.0.1)

Related

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)

Looping dataframe values into a raster through time

I have a raster N showing the overall distribution of a species.
The raster cells have a value of 1 where the species is present, and a value of 0 otherwise.
I also have a data frame DF showing the relative biomass of this same species over time:
Biomass<-c(0.9, 1.2, 1.3)
Year<-c(1975, 1976, 1977)
DF<-c(Biomass, Year)
I would like to create (and save) a new raster for each year of my time series through a loop, where all my raster cells originally equal to 1 N[N==1] are replaced by the biomass value found in DF for that specific year.
For example, all the cells originally equaling 1 would be replaced by 0.9 and the raster would be saved as N-1975.
The idea would be to create a loop, but I cannot find anything on looping values of a dataframe into a raster.
I would like to end up with one raster per year "N-1975", "N-1976"...
Thank you !
What spatial information are you working with? If you have a simple xy coordinate system you can use rasterfromXYZ(df) to give you a raster layer for each column of your data frame, as long as your first two columns are x and y coordinates respectively. If you're using some other projection then you can specify it in the function: (https://rdrr.io/cran/raster/man/rasterFromXYZ.html)
#make som random data
x<-c(1,4,3,2,4)
y<-c(4,3,1,1,4)
#best to avoid only numbers as col names
X1975<- rnorm(5, 4,1)
X1976<- rnorm(5,5,1)
#make df
df<- cbind(x,y,X1975,X1976)
#make raster
biomass_raster <- rasterFromXYZ(df)
biomass_raster
#returns
class : RasterBrick
dimensions : 4, 4, 16, 2 (nrow, ncol, ncell, nlayers)
resolution : 1, 1 (x, y)
extent : 0.5, 4.5, 0.5, 4.5 (xmin, xmax, ymin, ymax)
crs : NA
source : memory
names : X1975, X1976
min values : 1.290337, 4.523350
max values : 4.413451, 6.512719
#plot all layers: plot(biomass_raster)
#access specific layer by calling biomass_raster$X1975
I ended up finding how to solve this issue, so I will post it here in case anybody runs into the same problem :)
N_loop <- N
years <- 1975:2020
for(i in seq(length(years))){
N_loop[N == 1] <- DF$Biomass[i]
writeRaster(N_loop, paste0("N", years[i], ".asc"), overwrite = TRUE)
}

Convert a spatial point to raster in R

How to convert a single spatial point to a raster object.
I want to create a raster of 0.1 resolution within the domain xmin = 150 xmx=180,ymin=25,ymax=35 and put the values of a datapoint dt point in the raster.
Here is the data and code.
dt<-data.frame(lon=71.85,lat =31.12,val=3)
dt
ras_dom<-raster(xmn=150, xmx=180, ymn=25, ymx=35,
crs="+proj=longlat +datum=WGS84 +no_defs ",
resolution=c(0.1,0.1), vals=NA)
ras_dom
I want to put the value (or values) from dt in the ras_dom so that I have a raster with values for given grids and NA for others.
library(raster)
coordinates(dt) <- ~ lon + lat # Convert data frame to spatial object
result <- rasterize(dt, ras_dom, "val", update = TRUE) # put point in raster
result # The resulting raster with the point added
Because dt in the example is outside the raster, result does not contain it.

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)

Finding the boundary points in a raster data file

So, I have with me the center point and the zoom level.
I have to plot some points on the map.
The map is stored in a raster data file, and is displayed on the R's widget.
The issue is that when a point is received, I need to check whether it falls inside the data of this raster file or not.
If the point is in the raster file, then I can safely plot it.
If not, then I need to load another raster file which contains that point, and then plot the point.
The raster package of R has a function named as.data.frame which loads the raster data into the data frame.
Is it possible, then, to figure out which points (lats and lons) are at the four corners?
Am I on the right track?
If your data is of RasterLayer class then extent will give you the extent of the raster
and xmin, 'min, ymax and xmax to access the various slots.
eg
# create a dummy raster
r1 <- raster(nrows=108, ncols=21, xmn=0, xmx=10)
r1[] <-1
extent(r1)
## class : Extent
## xmin : 0
## xmax : 10
## ymin : -90
## ymax : 90
You can access the various slots using
xmin(r1)
## [1] 0
xmax(r1)
##[1] 10
ymin(r1)
## [1] -90
ymax(r1)
## [1] 90
If your data is a SpatialGridDataFrame then bbox will return the bounding box
.grid <- as(r1,'SpatialGridDataFrame')
bbox(.grid)
## min max
## s1 0 10
## 2 -90 90
Does my xy coordinate lie within the raster boundary
you can use cellFromXY to find the cell id, and it will return NA if it is outside the extext
eg
# some data
.points <- rbind(c(1,1),c(-4,1))
# the first point lies within the raster, the second not
# cell from XY will tell you this.
cellFromXY(r1,.points)
## [1] 1116 NA
EDIT for ggmap
if you have a map acquired by get_map, it is a ggmap object, and will not work with the package raster without some help from you .
you can obtain the bounding box as the bb attribute.
hdf <- get_map()
attr(hdf,'bb')
## ll.lat ll.lon ur.lat ur.lon
## 1 29.38048 -95.80204 30.14344 -94.92313
A helper function that will create a RasterStack from a ggmap object
ggmap_rasterlayer <- function(map){
map_bbox <- attr(map, 'bb')
.extent <- extent(as.numeric(map_bbox[c(2,4,1,3)]))
my_map <- raster(.extent, nrow= nrow(map), ncol = ncol(map))
rgb_cols <- setNames(as.data.frame(t(col2rgb(map))), c('red','green','blue'))
red <- my_map
values(red) <- rgb_cols[['red']]
green <- my_map
values(green) <- rgb_cols[['green']]
blue <- my_map
values(blue) <- rgb_cols[['blue']]
stack(red,green,blue)
}
my_map <- ggmap_rasterlayer(hdf)

Resources