Dealing with NA values using extract function in R - r

I am trying to calculate average annual temperatures for grid cells of 11x11km (except if the cell is coastal, the size is smaller) using the CRU database. The CRS of both vector and raster are the same. However, 332 out of 1363 cells show NA values after the extraction. I want to fill in the NA values before using the dataset for further analysis. Any idea of how I could deal with these missing values? I have looked at several possible solutions on this forum (and others). Unfortunately, none of them don’t seem to apply to my case.
Below are the details of my workflow:
# load the temperature dataset
temp <- brick("/CRU/cru_ts4.02.1901.2017.tmp.dat.nc", varname="tmp")
# set CRS for temp
utm = "+proj=utm +zone=49 +datum=WGS84 +towgs84=0,0,0"
tempro = projectRaster(temp, crs = utm, method = "bilinear")
# load the grid cells (in polygons) & set its CRS
fish <- st_read("/CRU/fish11.shp")
fishpro <- st_transform(fish, "+proj=utm +zone=49 +datum=WGS84 +towgs84=0,0,0")
# extract the temperature dataset
tempgrid <- extract(tempro, fishpro, fun='mean', na.rm=TRUE, df=TRUE, weights = TRUE, small = TRUE,
method='bilinear')
write.csv(tempgrid, file="temp.csv")
whereas the map is:
temperature

I do not think there is a simple answer to your question. Apparently the polygons are not over land; but we cannot tell as we do not have your data. It could also be that the UTM zone chosen is not appropriate.
I can say that what you are doing is wrong. If you need to transform the data; you should transform the vector data, not the raster data (even if that should not affect the NA problem much, if at all).
library(raster)
temp <- brick("/CRU/cru_ts4.02.1901.2017.tmp.dat.nc", varname="tmp")
fish <- st_read("/CRU/fish11.shp")
fishpro <- st_transform(fish, "+proj=longlat +datum=WGS84")
tempgrid <- extract(temp, fishpro, fun='mean', na.rm=TRUE, df=TRUE, small = TRUE)
You could also make a map to see what is going on (and perhaps include that as an image in your quesiton.
x <- crop(temp[[1]], extent(fishpro)+1)
plot(x)
lines(fishpro)

Related

The points of occurrence (gbif) and the maps don't coincide when i use worldclim data

i'm new in the R world and i'm trying to do a species distribution model, but when i plot my result, the points stay out from my map, i tried to change CRS but i didn't solve my problem, now i'll go to show you my code
library(dismo)
library(raster)
library(dplyr)
library(rnaturalearth)
Here i downloaded my species from gbif
gbif("Miniopterus", "schreibersii" , download=F)
minio<- gbif("Miniopterus", "schreibersii" , download=T) #you need 2 min approximately
i saw the basis of record and then i selected 2 different types
table(minio$basisOfRecord)
#Filter data minio----
minio<- minio%>%
filter(!is.na(lat))%>%
filter(!is.na(lon))%>%
filter(year>1980)%>%
filter(basisOfRecord %in% c("HUMAN_OBSERVATION", "OBSERVATION"))
class(minio)
nrow(minio)
i selected only longitude and latitude
miniogeo<-minio%>%
select(lon,lat)
head(miniogeo)
miniogeo$species<-1
head(miniogeo)
nrow(miniogeo)
And i created the coordinates and set the crs
coordinates(miniogeo) <-c("lon","lat")
crs(miniogeo) <- "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"
proj4string(miniogeo) <- CRS("+init=epsg:4326")
Here start problems for me, i tried a lot of type of function for create a map but this is the most efficient (the most efficient of those functions I have found). I need to have a zoom of spain and portugal, and i need to exclude "Africa".
Europe <- ne_countries(scale="medium", type="map_units", returnclass="sf", continent="Europe")
Worldclim<-raster::getData('worldclim', var='bio', res=2.5)
Europe <- Europe %>%
dplyr::select(geometry,name_long) %>%
filter(name_long!='Russian Federation')
plot(Worldclim[[1]]) #or plot(worldclim$bio1)
plot(st_geometry(Europe))
points(miniogeo, cex=0.1)
envData<-crop(Worldclim, Europe)
EuropePred <- mask(envData, Europe) #we create a new raster without NA value
And here i plotted my points but, as you can see, my points went out of my map
plot(EuropePred[[1]]) #example
points(miniogeo, cex=0.2)
then i tried to do a zoom to Spain and Portugal.
extSpnPrt<-extent(c(-11,10,35,56))
miniogeo<-crop(miniogeo,extSpnPrt)
SpainPort<-crop(EuropePred,extSpnPrt)
plot(SpainPort$bio2)
points(miniogeo, cex=0.1)
There is someone that can understand my problem? i'm really really sorry, i tried a lot of time for undestand better but my level in R is so basics for now.
I say thank you to all that dedicate the time for read this. I hope you have a good day
This is the result of my map with only geometry and with worldclim data
enter image description here
One way to create a SpatialPointsDataFrame from your data.frame minio is:
coordinates(minio) <- ~ lon + lat
crs(minio) <- "+proj=longlat"
This is NOT correct:
coordinates(minio) <- c("lon", "lat")
Result:
plot(minio, cex=.5, col="red")
lines(as(Europe, "Spatial"))

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.

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)

Create square grids and export them as shapefile or table

I would like to use the Google Earth Engine in order to extract data for certain countries. I need the data in the form of square grids, so I would like to create those square grids for a certain country, add them to the shapefile and then import the shapefile into the Earth Engine. I already found some code to create the square grids (Create a grid inside a shapefile), but now I have two problems.
First, I need to export the square grids so that I can import them to the Earth Engine. I'm very open to alternatives to the shapefile.
Second, the subsequent code works for some countries (like France), but not for others (like Thailand).
library(raster)
shp = getData(country = "FRA", level = 0)
shp = spTransform(shp, CRSobj = "+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0")
plot(shp)
cs = c(10000, 10000)
grdpts = makegrid(shp, cellsize = cs)
spgrd = SpatialPoints(grdpts, proj4string = CRS(proj4string(shp)))
spgrdWithin = SpatialPixels(spgrd[shp,])
plot(spgrdWithin, add = T)
Replacing "FRA" by "THA" in line 2 leads to an error in spTransform.
That fails because you are using utm zone 32. You need to use the zone based on the longitude of the country. You can see them here
You can automate finding a zone with ceiling((longitude+180)/6)
library(raster)
s <- getData(country = "FRA", level = 0)
Get the centroid. In this case you can do
centr <- coordinates(s)
If there are multiple polygons, you can do something like this
centr <- apply(coordinates(s), 2, mean)
Compute the UTM zone. (note that you had 32 for France, which is not good)
zone <- ceiling((centr[1] + 180)/6)
zone
#[1] 31
And then use it like this
crs <- paste0("+proj=utm +datum=WGS84 +unit=m +zone=", zone)
st <- spTransform(s, crs)
For Thailand you would get
s <- getData(country = "THA", level = 0)
centr <- apply(coordinates(s), 2, mean)
zone <- ceiling((centr[1] + 180)/6)
zone
#[1] 47
However, this is not an approach that would work for all countries. UTM zones are 6 degrees wide, and many countries span multiple zones (Russia takes the cake with 28 zones). So depending on your goals, you may want to use another coordinate reference system (crs).
After that, an alternative way to get square polygons is to create a RasterLayer with the extent of s, and a resolution of choice. But I doubt that this is the best way to get data out of GEE. I would suggest uploading the country outline instead.
r <- raster(st, res=10000)
r <- rasterize(st, r, 1)
x <- as(r, "SpatialPolygons")
# write to file
shapefile(x, "test.shp")
# view
plot(x)

Create topographic map in R

I am trying to create a script that will generate a 2d topographic or contour map for a given set of coordinates. My goal is something similar to what is produced by
contour(volcano)
but for any location set by the user. This has proved surprisingly challenging! I have tried:
library(elevatr)
library(tidyr)
# Generate a data frame of lat/long coordinates.
ex.df <- data.frame(x=seq(from=-73, to=-71, length.out=10),
y=seq(from=41, to=45, length.out=10))
# Specify projection.
prj_dd <- "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"
# Use elevatr package to get elevation data for each point.
df.sp <- get_elev_point(ex.df, prj = prj_dd, src = "epqs")
# Convert from spatial to regular data frame, remove extra column.
# Use tidyr to convert to lat x lon table with elevation as fill.
# Sorry for the terrible code, I know this is sloppy.
df <- as.data.frame(df.sp)
df$elev_units <- NULL
df.w <- df %>% spread(y, elevation)
df.w <- as.matrix(df.w)
This creates a matrix similar to the volcano dataset but filled with NAs except for the 10 lat/lon pairs with elevation data. contour can handle NAs, but the result of contour(df.w) has only a single tiny line on it. I'm not sure where to go from here. Do I simply need more points? Thanks in advance for any help--I'm pretty new to R and I think I've bitten off more than I can chew with this project.
Sorry for delay in responding. I suppose I need to check SO for elevatr questions!
I would use elevatr::get_elev_raster(), which returns a raster object which can be plotted directly with raster::contour().
Code example below grabs a smaller area and at a pretty coarse resolution. Resultant contour looks decent though.
library(elevatr)
library(raster)
# Generate a data frame of lat/long coordinates.
ex.df <- data.frame(x=seq(from=-73, to=-72.5, length.out=10),
y=seq(from=41, to=41.5, length.out=10))
# Specify projection.
prj_dd <- "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"
# Use elevatr package to get elevation data for each point.
elev <- get_elev_raster(ex.df, prj = prj_dd, z = 10, clip = "bbox")
raster::contour(elev)
If it is a requirement to use graphic::contour(), you'll need to convert the raster object to a matrix first with raster::as.matrix(elev). That flips the coords though and I haven't spent enough time to try and get that part figured out... Hopefully the raster solution works for you.

Resources