Failing to assign projection to sp object SpatialPointsDataFrame - r

I have a SpatialPointsDataFrame called johnny, created from a vanilla dataframe by assigning coordinates. These coordinates are in coordinate system EPSG 4326 (the standard GPS geographic coordinate system), but johnny does not know that. So ,I am trying to assign EPSG 4326 to johnny, essentially as in this earlier question data projection in R using package SP . I, too, am using sp. My ultimate goal is to project johnny to projected_johnny. However, I can't seem to assign the existing projection correctly first. Who sees my mistake?
library(sp)
x <- seq(80,90,by=1)
y <- seq(40,50,by=1)
value <- seq(10,20,by=1)
johnny <- data.frame(cbind(x,y,value))
coordinates(johnny) <- ~x+y
class(johnny)
[1] "SpatialPointsDataFrame"
attr(,"package")
[1] "sp"
proj4string(johnny) <- CRS("+init=epsg:4326")
Error in if (is.na(get("has_proj_def.dat", envir = .RGDAL_CACHE))) { :
argument is of length zero
I have considered and rejected the following possible solutions after trying them out:
Adding library rdgal directly
using CRS("+proj=longlat +datum=WGS84") instead of CRS("+init=epsg:4326")
I am using R 3.6.0 and sp 1.3-1. The rgdal version loaded via sp is 1.5-15. Any ideas are welcome. This should be such a simple action...

I looked over your code and guessed what you are probably trying to accomplish. But the way you are going about things is more different than it needs to be. There is a simple way to accomplished this. By far, the easiest way to accomplish this is by using those tools found in the R, sf package. Know that the sf package is a newer package than the sp package. And the sf package provides easy to use tools for accomplishing these tasks.
The code below is somewhat different from your code. A two column matrix was used instead of your three column data frame.
The simple feature geometry points were created from the matrix. Then the simple feature column object was created from the geometry points. Then the plot was created.
Code:
# Create matrix
x <- seq(80,90,by=1)
y <- seq(40,50,by=1)
# value <- seq(10,20,by=1)
#johnny <- data.frame(cbind(x,y))
jm <- matrix(data = c(x,y), nrow = 11, ncol = 2)
# coordinates(johnny) <- ~x+y
# class(johnny)
# johnny
Create sf multipoint geometry:
jm.sfg <- st_multipoint(jm)
jm.sfg
Create sf column object:
jm.sfc <- st_sfc(jm.sfg, crs = 4326)
jm.sfc
Plot
plot(jm.sfc, axes = TRUE)
The plot can be viewed from link below.

Related

R - terra::distance() equivalent of raster::gridDistance(..., origin = x, omit = y)

UPDATE - this question relates to terra 1.4-1, and is now obsolete with terra 1.5-12 (or earlier?).
I am looking for the terra equivalent of raster::gridDistance(..., origin = my_origin, omit = my_omit).
I found what looks to be an old webpage on terra::gridDistance, from terra v0.2-8 here, but from what I can gather terra::distance is the current replacement for raster::gridDistance (list of terra's replacement functions here).
However, I don't know to implement omit = my_omit (or equivalent) in terra::distance. From the documentation page it looks like any non-NA is deemed the origin, but there is no reference to omit, or the option to change the origin to a specific value (unlike the raster::gridDistance example below).
This is the example from raster::gridDistance:
library(raster)
# world lon/lat raster
r <- raster(ncol=10,nrow=10, vals=1)
r[48] <- 2 # this will be the origin
r[66:68] <- 3 # this will be the area that can't be traversed
plot(r)
d <- gridDistance(r,origin=2,omit=3)
plot(d)
Can anyone reproduce this example using terra::distance?
I can do what I need to do using raster, but I'm still learning how to handle spatial raster data properly and am making an effort to learn the new terra package.
Thanks to #lovalery for pointing this out in the comments.
In the original question I was using terra 1.4-1. As of January 2022, terra 1.5-12 has been released (Jan 13th 2022), and it now includes a terra::gridDistance() function which is very similar to the raster::gridDistance() function.
For the sake of completeness, this is the example from ?terra::gridDistance:
#world lon/lat raster
r <- rast(ncol=10,nrow=10, vals=1)
r[48] <- 2
r[66:68] <- 3
d <- gridDistance(r,origin=2,omit=3)
plot(d)
#UTM small area
crs(r) <- "+proj=utm +zone=15 +ellps=GRS80 +datum=NAD83 +units=m +no_defs"
d <- gridDistance(r,origin=2,omit=3)
plot(d)

Intersect in R - miss one polygon

1. The problem
I'm trying to extract the intersection of two polygons shapes in R. The first is the watershed polygon "ws_polygon_2", and the second is the Voronoi polygons of 5 rain gauges which was constructed from the Excel sheet "DATA.xlsx", both available here: link.
The code is the following:
#[1] Montagem da tabela de coordenadas dos postos pluviométricos
library(sp)
library(readxl)
dados_precipitacao_1985 <- read_excel(path="C:/Users/.../DATA.xlsx")
coordinates(dados_precipitacao_1985) <- ~ x + y
proj4string(dados_precipitacao_1985) <- CRS("+proj=longlat +datum=WGS84")
d_prec <- spTransform(dados_precipitacao_1985, CRSobj = "+init=epsg:3857")
#[2] Coleta dos dados espaciais da bacia hidrográfica
library(rgdal)
bacia_Caio_Prado <- readOGR(dsn="C:/Users/...", layer="ws_polygon_2")
bacia_WGS <- spTransform(bacia_Caio_Prado, CRSobj = "+proj=longlat +datum=WGS84")
bacia_UTM <- spTransform(bacia_Caio_Prado, CRSobj = "+init=epsg:3857")
#[3] Poligonos de Thiessen - 1 INTERPOLAÇÃO
library(dismo)
library(rgeos)
library(raster)
library(mapview)
limits_voronoi_WGS <- c(-40.00,-38.90,-5.00,-4.50)
v_WGS <- voronoi(dados_precipitacao_1985, ext=limits_voronoi_WGS)
bc <- aggregate(bacia_WGS)
u_WGS_1 <- gIntersection(spgeom1 = v_WGS, spgeom2 = bc,byid=TRUE)
u_WGS_2 <- intersect(bc, v_WGS)
When I apply the intersect function, the variable returned u_WGS_2 is a spatial polygon data frame with only 4 features, instead of 5. The Voronoi object v_WGS has 5 features as well.
By other hand, when I apply the gIntesection function, I get 5 features. However, the u_WGS_1 object is a spatial polygon only and I loss the rainfall data.
I'd like to know if I am committing any mistake or if there is any way to get the 5 features aggregated with the rainfall data in a spatial polygon data frame through the intersect function.
My objective is to transform this spatial polygon data frame with the rainfall data for each Voronoi polygon in a raster through the rasterize function later to compare with other interpolating results and satellite data.
Look these results. The first one is when I get the SPDF (Spatial Polygon Data Frame) I want, but missing the 5º feature. The second is the one I get with all the features I want, but missing the rainfall data.
spplot(u_WGS_2, 'JAN')
plot(u_WGS_1)
2. What I've tried
I look into the ws_polygon_2 shape searching for any other unwanted polygon who would pollute the shape and guide to this results. The shape is composed by only one polygon feature, the correct watershed feature.
I tried to use the aggregate function, as above, and as I saw in this tutorial. But I got the same result.
I tried to create a SPDF with de u_WGS_1 and the d_precSpatial Point Data Frame object. Actually, I'm working on it. And if it is the correct answer to my trouble, please help me with some code.
Thank you!
This is not an issue when using st_intersection() from sf, which retains the data from both data sets. Mind that dismo::voronoi() is compatible with sp objects only, so the precipitation data needs to be available in that format, at least temporarily. If you do not feel comfortable with sf and prefer to continue working with Spatial* objects after the actual intersection, simply invoke the as() method upon the output sf object as shown below.
library(sf)
#[1] Montagem da tabela de coordenadas dos postos pluviométricos
dados_precipitacao_1985 <- readxl::read_excel(path="data/DATA.xlsx")
dados_precipitacao_1985 <- st_as_sf(dados_precipitacao_1985, coords = c("x", "y"), crs = 4326)
dados_precipitacao_1985_sp <- as(dados_precipitacao_1985, "Spatial")
#[2] Coleta dos dados espaciais da bacia hidrográfica
bacia_Caio_Prado <- st_read(dsn="data/SHAPE_CORRIGIDO", layer="ws_polygon_2")
#[3] Poligonos de Thiessen - 1 INTERPOLAÇÃO
limits_voronoi_WGS <- c(-40.00,-38.90,-5.00,-4.50)
v_WGS <- dismo::voronoi(dados_precipitacao_1985_sp, ext=limits_voronoi_WGS)
v_WGS_sf <- st_as_sf(v_WGS)
u_WGS_3 <- st_intersection(bacia_Caio_Prado, v_WGS_sf)
plot(u_WGS_3[, 6], key.pos = 1)
The missing polygon is removed because it is invalid
library(raster)
bacia <- shapefile("SHAPE_CORRIGIDO/ws_polygon_2.shp")
rgeos::gIsValid(bacia)
#[1] FALSE
#Warning message:
#In RGEOSUnaryPredFunc(spgeom, byid, "rgeos_isvalid") :
# Ring Self-intersection at or near point -39.070555560000003 -4.8419444399999998
The self-intersection is here:
zoom(bacia, ext=extent(-39.07828, -39.06074, -4.85128, -4.83396))
points(cbind( -39.070555560000003, -4.8419444399999998))
Invalid polygons are removed as they are assumed to have been produced by intersect. In this case, the invalid data was already there and should have been retained. I will see if I can fix that.

unwanted subgeometries when converting raster to polygons

I am converting many rasters to polygon. But in quite a few cases, I am seeing unexpected subgeometries, and I can't seem to get rid of them.
This is with R v3.3.3 and raster package v2.5-8.
Here is an example that should reproduce the problem I am having.
You can download the raster that I use here.
# first, read in raster and coarsen to something more manageable
library(raster)
library(rgeos)
env <- raster('adefi.tif')
env2 <-aggregate(env, 8)
# Reclassify such that cells are either 1 or NA
env2[!is.na(env2)] <- 1
# this is what the raster now looks like:
plot(env2)
# Now I convert to polygon, choosing to dissolve
p <- rasterToPolygons(env2, dissolve=T)
plot(p)
# I find that I can't get rid of these subgeometries
p <- gUnaryUnion(p) # identical result
gIsValid(p) # returns TRUE
I'm not sure where the problem is... Is it in how the raster package converts to cell polygons? Or is it how the rgeos package dissolves those cell polygons together?
Is there a work-around?
It looks like a projection issue. This works for me:
library(raster)
library(rgeos)
env <- raster(file.path(fp, "adefi.tif"))
env2 <- aggregate(env, 8)
env2[is.na(env2) == F] <- 1
# Project Raster
proj_env2 <- projectRaster(env2, crs = CRS("+init=epsg:3577"))
p <- rasterToPolygons(proj_env2, dissolve = T)
plot(p)
Not sure why the need for reprojection since epsg:3577 looks to be the same as the original projection, but I usually confirm projection using proj4string() or spTransform() to make sure everything will line up.

Dealing with unordered XY points to create a polygon shapefile in R

I've inherited a geodatabase of polygons of lakes for which I am trying to create sampling grids on each lake. My current strategy is to export spatial data to CSV, use R to run a loop to create the grids on each lake, and then write to a new shapefile. However, here is my problem, when exporting to a CSV the WKT strings get messed up and put onto different lines. Okay, no problem, I moved on to exporting just the geometry to CSV so that I get X-Y values. When I simply plot the points they look perfect (using plot(y~x)), but the points are not in order. So, when I transform the data to a SpatialPolygon in the sp package in R using the following sequence:
XY-points -> Polygon -> Polygons -> SpatialPolygon
and then plot the SpatialPolygon I get this:
I know this is an artifact of incorrectly ordered points, because when I order the points by X and then by Y and run the same procedure here is what I get:
This is what the correct plotting is supposed to look like (X-Y data plotted with open circles):
Here is a short reproducible example of what I am trying to deal with:
library(sp)
# correct polygon
data <- data.frame(x=c(1:10, 10:1), y=c(5:1, 1:10, 10:6))
# plot(y~x, data=data)
correct.data.points <- rbind(data, data[1,]) # to close the ring for a polygon
correct.data.coords <- as.matrix(cbind(correct.data.points))
correct.data.poly <- Polygon(correct.data.coords, hole=F)
correct.data.poly <- Polygons(list(correct.data.poly), ID=0)
correct.data.poly.sp <- SpatialPolygons(list(correct.data.poly))
plot(correct.data.poly.sp)
# incorrect polygon
scr.data <- data[c(sample(1:20)),]
# plot(y~x, data=scr.data)
scr.data.points <- rbind(scr.data, scr.data[1,]) # to close the ring for a polygon
scr.data.coords <- as.matrix(cbind(scr.data.points))
scr.data.poly <- Polygon(scr.data.coords, hole=F)
scr.data.poly <- Polygons(list(scr.data.poly), ID=0)
scr.data.poly.sp <- SpatialPolygons(list(scr.data.poly))
plot(scr.data.poly.sp)
Any thoughts? Thanks for any help or insight anyone can provide. Also, for reference I am using QGIS 2.6.0 and the MMQGIS Python plugin to do the geometry exporting.

How to create a KML file using R

I have written a R script to get some map point data (Latitude and Longitude values). I am able to plot them in R and visualize them. But now I want to generate a KML file from this data and view using Google Earth. So that I can share it with colleagues and they can see it on Google Earth too.
What is the best method / package to do this ?
Check the writeOGR function in the rgdal package. Here is a simple example:
library("sp")
library("rgdal")
data(meuse)
coordinates(meuse) <- c("x", "y")
proj4string(meuse) <- CRS("+init=epsg:28992")
meuse_ll <- spTransform(meuse, CRS("+proj=longlat +datum=WGS84"))
writeOGR(meuse_ll["zinc"], "meuse.kml", layer="zinc", driver="KML")
The objects exported are SpatialPointsDataFrame, SpatialLinesDataFrame, or SpatialPolygonsDataFrame objects as defined in the sp package.
R> class(meuse)
[1] "SpatialPointsDataFrame"
attr(,"package")
[1] "sp"
For writing with the KML driver, note that the geometries should be in geographical coordinates with datum WGS84.
I think is worth mentioning the plotKML package as well.
Edit 2022-05-16: Seems that plotKML is no longer on CRAN, but you can use an older package version from the CRAN archive. See Installing a Package Removed from CRAN.
However, for easy sharing among colleagues I found interesting the mapview package based on leaflet package. One can save a map as HTML document with various options for a background map; no need of Google Earth and the HTML map will run on your browser.
Some examples:
library(sp)
library(rgdal)
library(raster)
library(plotKML)
library(mapview)
# A SpatialPointsDataFrame example
data(meuse)
coordinates(meuse) <- ~x+y
proj4string(meuse) <- CRS("+init=epsg:28992") # CRS Amersfoort (Netherlands)
# make a KML file from SpatialPointsDataFrame object
# will get a warning like "Reprojecting to +proj=longlat +datum=WGS84 ..."
# as it is expected to work with geographical coordinates with datum=WGS84,
# but seems that it takes care of the reprojecting.
plotKML::kml(meuse,
file.name = "meuse_cadium.kml",
points_names = meuse$cadmium,
colour = "#FF0000",
alpha = 0.6,
size = 1,
shape = "http://maps.google.com/mapfiles/kml/pal2/icon18.png")
# Or, an easy to make interactive map with mapView()
mapView(meuse)
# A RasterLayer example
data(meuse.grid)
gridded(meuse.grid) <- ~x+y
proj4string(meuse.grid) <- CRS("+init=epsg:28992")
dist_rst <- raster(meuse.grid["dist"])
# make a KML file from RasterLayer object
plotKML::kml(dist_rst,
file.name = "dist_rst.kml",
colour_scale = SAGA_pal[[1]])
# Or, easy to make interactive map with mapView() - display raster and add the points
mapView(dist_rst, legend=TRUE) + meuse
# However, note that for bigger raster datasets mapView() might reduce from resolution
More examples with plotKML here.
For mapview, an intro can be found here.
If you're willing to step outside R, there is a free program called DNRGarmin can take a comma separated file as a .txt and convert it to .kml for import into google earth.
You can find it here:
http://www.dnr.state.mn.us/mis/gis/tools/arcview/extensions/DNRGarmin/DNRGarmin.html
so in R:
my.geo.data <- all.my.data[ c("unique.id", "lats", "longs")]
write.csv( my.geo.data, file = "myGeoData.txt")
open DNRGarmin,
File -> Load From -> File -> myGeoData.txt Then,
File -> Save to -> File -> myGeoData.kml
#rcs's advice re: WGS84 applies for this answer too.
Good luck
If you/your collegues know QGIS, this is a very good way to display data in Google Earth. QGIS has the feature of showing Google Earth as a base map and then you can open your spatial data and it will be displayed on the base map. Of course it requires your data to be correctly projected as rcs says.
Here you need to export your points as a shape file using the maptools package and Spatial Points package:
library(maptools)
library(sp)
## define projection
myProjection <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
## your points in format dataframe
coordinates.df <- as.data.frame(MyCoordinates)
## the number of points you have as dataframe
number <- as.data.frame(NumberOfPoints)
## convert points to Spatial Points Dataframe
myPoints.spdf <- SpatialPointsDataFrame(coordinates.df, number, proj4string = CRS(myProjection))
## save shapefile
writeSpatialShape(myPoints.spdf, "MyPointsName")
Your points can now be opened in QGIS and be displayed in Google Earth. In QGIS your data can also easily be saved as kmz file if necessary.

Resources