R raster function will not accept crs in WKT format - r

I'm trying to generate a raster and assign it a CRS projection. However, my CRS is in the new WKT format, and the raster() function is requiring me to provide a proj4string. Here's my code so far:
library(sf)
library(raster)
crs_dem <- st_crs(
'PROJCS["NAD_1983_2011_StatePlane_California_II_FIPS_0402",
GEOGCS["GCS_NAD_1983_2011",
DATUM["D_NAD_1983_2011",
SPHEROID["GRS_1980",6378137.0,298.257222101]],
PRIMEM["Greenwich",0.0],
UNIT["Degree",0.0174532925199433]],
PROJECTION["Lambert_Conformal_Conic"],
PARAMETER["False_Easting",2000000.0],
PARAMETER["False_Northing",500000.0],
PARAMETER["Central_Meridian",-122.0],
PARAMETER["Standard_Parallel_1",38.33333333333334],
PARAMETER["Standard_Parallel_2",39.83333333333334],
PARAMETER["Latitude_Of_Origin",37.66666666666666],
UNIT["Meter",1.0]]')
ext <- extent(1895000, 1935000, 579500, 616500)
grid <- raster(ext, resolution = c(40,40), crs = crs(dem))
The code above generates a raster with crs = NA. I've also tried assigning it with crs(grid)<- and projection(grid)<- with no luck. How can I get my specific CRS file to associate with this raster??

#slamballais's answer did the trick! I also found another (slightly less clean) method through trial and error last night, so here are both solutions.
Option 1:
test <- sp::CRS(crs_dem$input)
grid <- raster(ext, resolution = c(40,40), crs = test)
Option 2:
library(dplyr)
aoi <- ext %>%
as('SpatialPolygons') %>%
st_as_sf %>%
st_set_crs(crs_dem)
grid <- raster(ext, resolution = c(40,40), crs = projection(aoi))

raster expects text, so if you have a wkt format crs, you can use that directly. There is no need to create a more complex object.
crs_dem <- 'PROJCS["NAD_1983_2011_StatePlane_California_II_FIPS_0402",
GEOGCS["GCS_NAD_1983_2011", DATUM["D_NAD_1983_2011", SPHEROID["GRS_1980",6378137.0,298.257222101]],
PRIMEM["Greenwich",0.0], UNIT["Degree",0.0174532925199433]],
PROJECTION["Lambert_Conformal_Conic"], PARAMETER["False_Easting",2000000.0],
PARAMETER["False_Northing",500000.0], PARAMETER["Central_Meridian",-122.0],
PARAMETER["Standard_Parallel_1",38.33333333333334], PARAMETER["Standard_Parallel_2",39.83333333333334],
PARAMETER["Latitude_Of_Origin",37.66666666666666], UNIT["Meter",1.0]]'
library(raster)
r <- raster(crs=crs_dem)
or, if you start with an sf object
r <- raster(crs=crs_dem$input)

Related

R: Convert sf polygon defined using lat/long to UTM

I have the following polygon, defined using degrees latitude/longitude:
## Define latitude/longitude
lats <- c(64.25086, 64.24937, 63.24105, 63.22868)
lons <- c(-140.9985, -136.9171, -137.0050, -141.0260)
df <- data.frame(lon = lons, lat = lats)
polygon <- df %>%
## EPSG 3578; Yukon Albers projection
st_as_sf(coords = c('lon', 'lat'), crs = 3578) %>%
summarise(geometry = st_combine(geometry)) %>%
st_cast('POLYGON')
When I plot it on a map using Tmap, it appears in the Pacific Ocean off the coast of British Columbia, rather than in the middle of the Yukon:
library(sf)
library(sp)
library(tmap)
library(dplyr)
library(magrittr)
library(leaflet)
m <- tm_shape(data$study_boundary) + tm_borders(col = 'black',
lwd = 5,
zindex = 1000)
m
I am guessing that the problem is in using lat/long rather than UTMs because I have other polygons defined using UTMs that do appear where they (and the polygon defined above) are supposed to be. I found several other posts going the other way (UTM to lat/long) using spTransform, but I haven't been able to go lat/long to UTM with spTransform. I tried the code below:
poly_utm <- st_transform(polygon, crs = "+proj=utm+7")
But that didn't work either.
Thanks!
This (which I've improved by removing the pipe):
st_as_sf(df, coords = c('lon', 'lat'), crs = 3578)
creates a spatial points data frame using the numbers in the data frame for the coordinates, and the crs code of 3578 as the label for what those numbers represent. It does not change the numbers.
It looks like those numbers are actually lat-long coordinates, which means they are probable crs code 4326, the lat-long system used for GPS, also known as WGS 84. But it might not be. But probably is. Do check. So anyway, you should do:
df_unprojected = st_as_sf(df, coords = c('lon', 'lat'), crs = 4326)
df_projected = st_transform(df_unprojected, 3578)
The st_transform function does the actual change of the coordinate numbers and assigns the new CRS code to the spatial data metadata. That should give you a set of points you can then plot and check they are in the right place before you throw it into summarise and st_cast.

How can I clip a shapefile to my raster using R?

I am trying to mask a raster to a shapefile boundary, but I am getting an error. How can I correctly perform this mask?
The raw data can be found here, entitled "data_for_question.txt." It is formatted so that users can copy and paste (from the web app) the text directly into an R window and generate a data frame. Otherwise, if one doesn't want to generate the data, the output raster (example_raster.tif) and shapefile (field_boundary.shp) can both also be found in the same link.
Here is what I have tried:
#Import necessary libraries
library(pacman)
p_load(sf,
spatstat,
maptools,
tidyverse,
ggplot2,
gstat,
sp,
rgdal,
raster,
spdep)
#Read shapefile
shp <- st_read("field_boundary.shp")
#Generate data to run interpolation on and project it to the desired CRS
data_sp <- SpatialPointsDataFrame(coords,
data[, c("OM", "data2")],
proj4string = CRS('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'))
#Perform an IDW interpolation:
grd <- SpatialPixels(SpatialPoints(makegrid(data_sp, n=10000)), proj4string = proj4string(data_sp)) #Generate grid for interpolation
plot(grd)
interp <- idw(formula = OM ~ 1, data_sp, grd, idp = 0.5, nmax = 12)
plot(interp) #Makes for a very pretty picture!
#Convert to raster
rast <- raster(interp)
plot(rast)
shp <- st_transform(shp, crs(rast))
#Crop and mask the raster
crop_rast <- crop(rast, shp)
crop_om <- mask(crop_rast, mask = shp)
The error occurs here:
Error in h(simpleError(msg, call)) :
error in evaluating the argument 'x' in selecting a method for function 'addAttrToGeom': sp supports Z dimension only for POINT and MULTIPOINT.
use `st_zm(...)` to coerce to XY dimensions

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)

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.

How to calculate centroid of polygon using sf::st_centroid?

I am trying to manipulate some Brazilian Census data in R using the new "sf" package. I am able to import the data, but I get an error when I try to create the centroids of the original polygons
library(sf)
#Donwload data
filepath <- 'ftp://geoftp.ibge.gov.br/organizacao_do_territorio/malhas_territoriais/malhas_de_setores_censitarios__divisoes_intramunicipais/censo_2010/setores_censitarios_shp/ac/ac_setores_censitarios.zip'
download.file(filepath,'ac_setores_censitarios.zip')
unzip('ac_setores_censitarios.zip')
d <- st_read('12SEE250GC_SIR.shp',stringsAsFactors = F)
Now I try to create a new geometry column containing the centroid of column "geometry", but get an error:
d$centroid <- st_centroid(d$geometry)
Warning message:
In st_centroid.sfc(d$geometry) :
st_centroid does not give correct centroids for longitude/latitude data
How can I solve this?
All the GEOS functions underlying sf need projected coordinates to work properly, so you should run st_centroid on appropriately projected data. I don't know much about Brazil's available CRS's, but EPSG:29101 appears to work fine:
library(tidyverse)
d$centroids <- st_transform(d, 29101) %>%
st_centroid() %>%
# this is the crs from d, which has no EPSG code:
st_transform(., '+proj=longlat +ellps=GRS80 +no_defs') %>%
# since you want the centroids in a second geometry col:
st_geometry()
# check with
plot(st_geometry(d))
plot(d[, 'centroids'], add = T, col = 'red', pch = 19)

Resources