select points over land area in R - r

I have a point vector for the entire globe at 0.25 degree resolution.
library(terra)
library(rnaturalearth)
# create point data
ref_grid <- terra::ext(-180, 180, -90, 90)
ref_grid <- terra::rast(ref_grid)
res(ref_grid)<- 0.25
values(ref_grid)<-1 #dummy values
projections <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
crs(ref_grid) <- projections
pts <- terra::as.points(ref_grid, values=TRUE, na.rm=TRUE)
# download world shapefile
world_shp <- rnaturalearth::ne_countries()
world_shp <- terra::vect(world_shp)
world_shp <- terra::project(world_shp, projections)
I want to extract those points that fall within a landmass i.e. remove all those points that are in the ocean. So I did this:
e <- terra::extract(world_shp, pts)
But it's been two hours now and this is still running. Is there any faster way to do this?

You should not transform raster data to vector data if you want efficiency. In this case, you can do the following in a second or so:
library(terra)
library(rnaturalearth)
ref_grid <- terra::rast(res=0.25)
world_shp <- rnaturalearth::ne_countries(returnclass="sf") |> vect()
ref_grid <- rasterize(world_shp, ref_grid)
p <- as.points(ref_grid)
(but perhaps, depending on what you do next, the last step should also be avoided)

Related

Shapefile and Raster with same CRS but NO output when clipping

Problem: Plot is empty, no results when clipping raster with shapefile.
I am using a shapefile with original EPSG4326 projection and a MODIS product with original sinusoidal projection. I converted both to the same projection (DesiredCRS) as you can see in the script, however when making a clip of the raster I don't get any results.
library(terra)
library(sf)
library(sp)
library(raster)
# Inputs
HDFfile <- "ModisProductsOriginal/MCD18A1.A2001001.h15v05.061.2020097222704.hdf"
Shapefile <- "Shapefile/Outline_5/Portugal_Outline_5_CAOP2019.shp"
DesiredCRS <- "+proj=longlat +datum=WGS84"
# Feature
Shp <- st_read(Shapefile)
Terceira <- Shp[Shp$DI == '43',1]
Terceira <- st_transform(Terceira, DesiredCRS)
plot(Terceira, axes=TRUE)
Terceira's plot:
Plot Output
# Modis data
SDSs <- sds(HDFfile)
SDS8 <- SDSs[8]
SDS8_template <- rast(ncol=1200, nrow=1200, xmin=-34, xmax=-24, ymin=36, ymax=41, crs=DesiredCRS)
SDS8_reprojected <- project(SDS8, SDS8_template) # Reproject changes pixels?
SDS8_raster <- raster(SDS8_reprojected)
plot(SDS8_raster)
SDS8_raster's plot: Plot Output
# Clip
Clip.step1 <- crop(SDS8_raster, extent(Terceira))
Clip <- mask(Clip.step1, Terceira)
plot(Clip)
Clip.step1's plot: Plot Output
Clip's plot: Plot Output
All images show axes with the same projection. I don't understand what I'm doing wrong... Am I correctly defining the CRS and the extent?
Updated:
Panoply view of original shapefile and original HDF product:
Panoply Output
Plot of the two datasets together by Hijmans: Plot Output
This is but tricky to debug because you mix different packages, and you do not show(object). Anyway, here is a terra approach, showing where it would be useful to see the objects metadata; and a plot that shows the raster and vector data together.
library(terra)
HDFfile <- "MCD18A1.A2001001.h15v05.061.2020097222704.hdf"
Shapefile <- "Portugal_Outline_5_CAOP2019.shp"
DesiredCRS <- "+proj=longlat +datum=WGS84"
Shp <- vect(Shapefile)
Terceira <- Shp[Shp$DI == '43',1]
SDSs <- sds(HDFfile)
SDS8 <- SDSs[8]
Start by projecting the vector data to the original raster data.
TercSin <- project(Terceira, crs(SDS8))
plot(SDS8, 1)
lines(TercSin)
As you saw, that does not work. The reason is that GDAL/PROJ reads from file or assumes the wrong ellipsoid
cat(substr(crs(SDS8),1,230), "\n")
#PROJCRS["unnamed",
# BASEGEOGCRS["Unknown datum based upon the Clarke 1866 ellipsoid",
# DATUM["Not specified (based on Clarke 1866 spheroid)",
# ELLIPSOID["Clarke 1866",6378206.4,294.978698213898,
Or like this
describe("HDF4_EOS:EOS_GRID:\"MCD18A1.A2001001.h15v05.061.2020097222704.hdf\":MODISRAD:GMT_1200_DSR")[1:8]
#[1] "Driver: HDF4Image/HDF4 Dataset"
#[2] "Files: MCD18A1.A2001001.h15v05.061.2020097222704.hdf"
#[3] "Size is 1200, 1200"
#[4] "Coordinate System is:"
#[5] "PROJCRS[\"unnamed\","
#[6] " BASEGEOGCRS[\"Unknown datum based upon the Clarke 1866 ellipsoid\","
#[7] " DATUM[\"Not specified (based on Clarke 1866 spheroid)\","
#[8] " ELLIPSOID[\"Clarke 1866\",6378206.4,294.978698213898,"
As you point out (and see here), MODIS (or at least some products) uses
modcrs <- "+proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m"
So let's try that
TercSin <- project(Terceira, modcrs)
plot(SDS8, 1)
lines(TercSin)
That looks OK. So we need to do
crs(SDS8) <- modcrs
and continue
Terceira <- project(Terceira, DesiredCRS)
Terceira
SDS8_template <- rast(ncol=1200, nrow=1200, xmin=-34, xmax=-24, ymin=36, ymax=41, crs=DesiredCRS)
SDS8_reprojected <- project(SDS8, SDS8_template)
SDS8_reprojected
# Again plot the two datasets together
plot(SDS8_reprojected)
lines(Terceira)
Clip.step1 <- crop(SDS8_reprojected, Terceira)
Clip <- mask(Clip.step1, Terceira)
Clip
plot(Clip)
lines(Terceira)

Extracting matrix from NetCDF and converting it to raster - issues with rows - R

I have the following matrix obtained from a NetCDF file that I am trying to convert to a raster. I know that the matrix has a WGS84 projection.
I found one issue that is fixed in the code below - the spacing between the latitudes lat in NetCDF and consequently in derived matrix clim_ncdf was not equal. Still, however, the raster EI_adj is not exactly projected as it should be after conversion from matrix and all spaces are shifted southward.
This problem drives me crazy - does anyone have an idea how to fix it?
Source files (NetCDF and world admin boundaries) can be downloaded from here.
library(raster)
library(ncdf4)
library(lattice)
# Choose variable name
dname <- c("GI")
clim_ncdf <- nc_open("NetCDF_GI.nc")
lon <- ncvar_get(clim_ncdf,"Longitude")
head(lon)
lat <- ncvar_get(clim_ncdf,"Latitude")
# Latitudes have spacing of 0.5 except in two instances:
lat[55:60]
lat[58:59] # problematic ones
# Create a new latitude vector with equal spacing for corrected matrix
nlat <- seq(min(lat),max(lat),0.5)
EI1 <- ncvar_get(clim_ncdf,dname[1])
# This needs to be rotated
rotate <- function(x) t(apply(x, 2, rev))
EI <- rotate(rotate(rotate(EI1)))
# Now adjust EI for the problematic lats:
rows_m_reps <- rep(1,nrow(EI))
rows_m_reps[58] <- 2
rows_m_reps[59] <- 10
# Replicating corresponding rows so we can now have equal latitude distancing
EI_adj <- EI[rep(1:nrow(EI), rows_m_reps), ]
EIr_adj <- raster(EI_adj,xmn=min(lon), xmx=max(lon),ymn=min(nlat),ymx=max(nlat),
crs = "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0")
plot(EIr_adj)
# Add admin layer
library(rgdal)
world_admin <- readOGR("Countries_WGS84.shp")
plot(world_admin, add = TRUE)
Your data
library(ncdf4)
library(raster)
library(maptools)
data(wrld_simpl)
clim_ncdf <- nc_open("NetCDF_GI.nc")
lon <- ncvar_get(clim_ncdf,"Longitude")
lat <- ncvar_get(clim_ncdf,"Latitude")
v <- ncvar_get(clim_ncdf, "GI")
These are all the latitudes.
lat2 <- seq(min(lat),max(lat),0.5)
Create a RasterLayer and a corresponding matrix with NAs
e <- extent(min(lon)-0.25, max(lon)+0.25, min(lat)-0.25, max(lat)+0.25)
r <- raster(nrow=length(lat2), ncol=length(lon), ext=e)
m <- matrix(NA, nrow=length(lat2), ncol=length(lon))
Now rotate and assign the values to the correct rows for matrix m
vv <- t(v[,ncol(v):1])
i <- rowFromY(r, rev(as.vector(lat)))
m[i,] <- vv
And assign m to the RasterLayer
values(r) <- m
image(r)
lines(wrld_simpl)

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)

Spatial polygons with messed up shape

I am new to spatial data. My goal is to get the gpx files from openstreetmap and plot polygons of Hungary's boundaries. I could successfully plot the boundaries under Járások but there are some boundaries under Kistérségek which are messed up, containing loops between points.
Image
Reproducable example for a specific boundary
library(XML)
library(magrittr)
library(sp)
parsed <- xmlParse("http://osmrm.openstreetmap.de/gpx.jsp?relation=1368104") %>% xmlToList()
coord <- do.call(rbind, parsed$rte)
name <- coord[1, 1]
coord <- coord[-(1:2), ]
coord <- apply(coord, 2, as.numeric)
poly <- Polygons(list(Polygon(coord)), name)
sp <- SpatialPolygons(list(poly), proj4string = CRS("+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"))
plot(sp)
Result
Is the error because I missed something, or is it simply an issue with openstreetmap data? Any help is appreciated.

Gadm map with points layer in R

I have already asked about plotting points dependent on region, but now my question is about overlaying points given by coordinations over gadm map. I want to show different meteostations, using data based on this site or here is data used in code I've tried using such code:
require(ggplot2)
library(maptools)
library(rgdal)
library(RColorBrewer)
library(gpclib)
library(rgeos)
library(PBSmapping)
gpclibPermit()
rus<-load("C://RUS_adm1.RData")
proj4.str <- CRS("+init=epsg:3413 +lon_0=105")
gadm.prj <- spTransform(gadm, proj4.str)
rus<-gadm.prj
met <- read.csv2('C:\\meteo.txt')
cds <- data.frame(
Longitude=met$Long,
Latitude=met$Lat)
k<-as.matrix(cds)
popSP <- SpatialPointsDataFrame(coords=k,met["Elevation"], proj4string=proj4.str)
spplot(popSP, sp.layout=list('sp.polygons', gadm.prj))
, following advice from already mentioneed question, but it ends up with plotting points w/o gadm layer , I guess it's because of non-mentioning regions
Sorry, if question is dumb, but I will be grateful for any help
Here is the answer. Thanks to flowla
Edited code a little bit, I could plot different plot according to elevation.
library(rgdal)
library(raster)
rus <- load("C://RUS_adm1.RData")
popSP <- met <- read.csv2("C://meteo.txt")
for (i in c(3, 4))
popSP[, i] <- popSP[, i] / 1000
coordinates(popSP) <- ~ Long + Lat
projection(popSP) <- projection(gadm)
# Reprojection to EPSG:3413 (see http://www.spatialreference.org/ref/epsg/3413/)
proj4.str <- CRS("+proj=stere +lat_0=90 +lat_ts=70 +lon_0=105 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs")
gadm.prj <- spTransform(gadm, proj4.str)
popSP.prj <- spTransform(popSP, proj4.str)
col_no <- as.factor(as.numeric(cut(popSP.prj$Elevation,
c(0,2500,5000,10000,15000,20000,100000))))
levels(col_no) <- c("<2500", "2500-5000","5000-10000", "10000-15000","15000-20000",">20000" )
color = rainbow(6)
popSP.prj$col_no<-col_no
spplot(popSP.prj, "col_no", sp.layout=list('sp.polygons',cols="ID_0", gadm.prj), col.regions=color, main="Meteostations in Russia", key.space="right")

Resources