Reattach attribute table to Spatial Polygon to make Spatial Polygon Dataframe - r

I have built a web app using Shiny and Leaflet, but it renders very slowly because the Spatial Polygon DataFrame (merge.proj) that is being added to the map is 20,000 polygons. I may try to allow the user to view only certain neighborhoods at a time as a fix, but first I thought I'd simplify polygons to see how much that sped up the process.
My understanding is that simplifying polygons reduces # of vertices etc and gives you a Spatial Polygon, which loses the attribute table. I was hoping to then reattach the attribute table and re-create a Spatial Polygon Dataframe that is hopefully reduced in size.
However, the code is erroring and all the help I can find online just shows how to do this when making the Spatial Polygon and dataframe from scratch, and I'm having trouble applying what they did to my data (see here). The error says that my polygon IDs and row.names don't match, but they both originally came from the same Spatial Polygon Dataframe so I'm confused. And I'm not sure how to manually manipulate things so they match.
I am pasting below the error and the code I currently have. Any suggestions would be greatly appreciated!
# For faster plotting, simplify polygons
merge.simplify <- gSimplify(merge.proj,0.1,topologyPreserve = T)
# Create a dataframe
merge.df <- data.frame(merge.proj#data)
# Do coercion to SPDF
merge.spdf <- SpatialPolygonsDataFrame(merge.simplify, merge.df)
ERROR: Error in SpatialPolygonsDataFrame(merge.simplify, merge.df) :
row.names of data and Polygons IDs do not match

Related

Unable to create a multilinestring using st_intersection that is good enough to use border_segment from the SpatialRDD package

I’ve been following the following tutorial https://axlehner.github.io/SpatialRDD/articles/spatialrdd_vignette.html#assign-treatment for SpatialRDD using my own dataset and maps. I’ve run into a problem when attempting to use border_segment. In the tutorial the author has a cut off line he uses which describes a spatial discontinuity. In my own project I am trying to create such a cut off line using historical boundaries and by taking the intersection. I’ve been using two neighboring polygons and taking the intersection of their boundaries using st_intersection to create this cut off. However, once I reach the point where I need to use border_segment it does not work as intended.
If for instance I want 2 border segments to be created using my region, points in that region, and my cut off line, it appears border_segment creates 2 segments for each line segment of my cut off line (the cut off line I created using the intersection of boundaries). Furthermore, comparing the cut off line from the tutorial (can be loaded into R using SpatialRDD::data("cut_off.sf")) to the one I create, the one in the tutorial has one big matrix describing the geometry, while the one I create is described by many 2x2 matrices. I think this is where the problem might be stemming from, but I have no idea how to fix it. I think by finding a solution it would help to understand how to create better geographical objects using just R.
I’ve created a reproducible example to illustrate the issue:
library(SpatialRDD)
library(sf)
library(tmap)
library(spData) #loading various maps
#getting worldmap
data("world")
#changing to a localised projection system
world <- st_transform(world, "EPSG:3035")
#getting just Germany
germany <- world[world$name_long == "Germany",]
#getting just Poland
poland <- world[world$name_long == "Poland",]
#taking the union of Germany and Poland to later distribute random points in them
union <- st_union(germany, poland)
#taking the intersection of their borders, which will act as a cut off line
cut_off <- st_intersection(germany, poland)
#creating random points for exercise to work (similar code to what is done in tutorial)
set.seed(1088) # set a seed
points_samp <- sf::st_sample(union, 1000)
points_samp <- sf::st_sf(points_samp) # make it an sf object
#using border_segment to sort points into 2 border regions
points_samp$segment2 <- border_segment(points_samp, cut_off, 2)
#mapping the points in their respective border segments
tm_shape(points_samp) + tm_dots("segment2", size = 0.1) + tm_shape(cut_off) + tm_lines()
As you will see when plotting the points after creating the border segments, that there will be many border segments even though I indicated for border_segment to create only two.
I’m fairly new to R and geospatial manipulation, so maybe there is a simple solution, but I’ve searched everywhere and haven’t been able to find one. This is the first time after using stack overflow for years that I’ve had to actually post. Please let me know if you need any other information or if I was not clear enough at some point!

Why is R only extracting a shapefile field values for certain points?

Apologies if this belongs in GIS stackexchange, I'm happy to be redirected there, but I have a feeling it's something in my code that is the problem.
I have a shapefile of the Terrestrial Ecoregions of the World that contains fields such as Ecoregion Name, Biome, and, Realm, that I want to extract for a range of ~50,000 lat/long points. An example of the data would be
ID
ddlat
ddlong
221784
6.133
37.700
221814
26.450
74.700
221826
-17.716
-63.633
221827
47.933
8.083
221830
-24.283
131.600
My code (sample from within a much larger script) currently looks like the following:
teow <- shapefile("~/wwf_terr_ecos.shp")
teowlltest <- read.csv(file="~/teow_csv.csv",stringsAsFactors=FALSE)
teowlltest <- na.omit(teowlltest)
teowlltestSPT <- SpatialPoints(teowlltest, proj4string = CRS(proj4string(teow)))
overteow <- over(teowlltestSPT, teow)
bindtest <- cbind(teowlltest,overteow)
My problem is that the code works ... but only for 15 of the latlong points. I'm not expecting a 100% success rate, as I know the shapefile isn't perfect in coastline areas etc, but when mapped, far more than 15 points lie within the TEOW shapefile. The 15 that are being extracted are also incorrect when compared to maps of the biomes/realms etc. How do I get it to extract the field data for all the points and do it correctly? I've tried renaming/reorganising the csv (for example Y,X or Latitude, Longitude instead of ddlat, ddlong, and placing longitude as the first field), and subsetting the data, but only the same 15 keep extracting. I can't separate the Lat/Long information from the ID either, so I'm hoping that's not the problem here, but I can't see why it would be, if some of the points extract fine. Any help will be much appreciated, and I'm happy to answer any questions/supply more information if needed. Thanks!
Example output currently:
Showing that some have extracted (but not correctly) and all the others have just refused. Duplicate lat/longs removed for brevity.

Convert Spatial Lines to Spatial Polygons

Is there an easy way to convert a Spatial Lines into a Spatial Polygon object within R?
Reproducible Example
I have put together a reusable dataset here, which is downloaded from OpenStreetMaps through the overpass package. This extracts the locations of a few airports in South England:
devtools::install_github("hrbrmstr/overpass")
library(overpass)
library(raster)
library(sp)
# Write Query
query_airport <- '
(node["aeroway"="aerodrome"](50.8, -1.6,51.1, -1.1);
way["aeroway"="aerodrome"](50.8, -1.6,51.1, -1.1);
relation["aeroway"="aerodrome"](50.8, -1.6,51.1, -1.1);
);
out body;
>;
out skel qt;
'
# Run query
shp_airports <- overpass::overpass_query(query_airport, quiet = TRUE)
crs(shp_airports) <- CRS("+init=epsg:4326") # Add coordinates
shp_airports <- shp_airports[,1]
# Plot Results
plot(shp_airports, axes = T)
However, the data is of the class "SpatialLinesDataFrame". This really messes things up if you want to do any form of spatial joins or intersections, as it only acknowledges the edge of the region.
Potential Leads
I was exploring the use of SpatialLines2PolySet within the maptools package, but in my time exploring I produced nothing but error codes, so I didn't think there would be any worth including these within the question. There is some guidance about these functions here: https://rdrr.io/rforge/maptools/man/SpatialLines2PolySet.html
Notes
I have searched the web and SO to see find similar questions and struggled to find any questions directly referring to this. A lot seem to reference converting SpatialPoints -> SpatialLineDataFrames , but not SpatialLineDataFrames -> SpatialPolygonDataFrames. This question is similar but lacks any answers (or a reproducible dataset): Close a spatial line into a polygon using a shapefile
In addition, it seems strange that this would be difficult as it is something which can be done so easily in ArcGIS using the "Feature to Polygon" tool. This function requires no additional arguments specified and it works perfectly.
A way to solve the problem would be to use the library sf. After your query
library(sp)
library(raster)
library(sf)
sf_airports <- st_as_sf(shp_airports)
sf_airports_polygons <- st_polygonize(sf_airports)
shp_airports <- as(sf_airports_polygons, "Spatial") # If you want sp
class(shp_airports)

Nearest line to points using R

I'm trying to do some GIS work using R. Specifically, I have a spatialpointsdataframe (called 'points') and a spatiallinesdataframe (called 'lines). I want to know the closest line to each point. I do this:
# make a new field to hold the line ID
points#data$nearest_line <- as.character('')
# Loop through data. For each point, get ID of nearest line and store it
for (i in 1:nrow(points)){
points#data[i,"nearest_line"] <-
lines[which.min(gDistance(points[i,], lines, byid= TRUE)),]#data$line_id
}
This works fine. My issue is the size of my data. I've 4.5m points, and about 100,000 lines. It's been running for about a day so far, and has only done 200,000 of the 4.5m points (despite a fairly powerful computer).
Is there something I can do to speed this up? For example if I was doing this in PostGIS I would add a spatial index, but this doesn't seem to be an option in R.
Or maybe I'm approaching this totally wrong?

Issue with coordinate projection for detecting spatial autocorrelation in R

We have a dataset that contains latitude and longitude coordinates, as well as attribute information, each in its own separate column, stored as numeric. These coordinates have been geocoded based on the geographic coordinate system WGS 1984.
We know that we have significant spatial autocorrelation in our data, which we are hoping to visualize in a bubble plot using the “sp” package. We are modeling our example off of others online, such as here: https://beckmw.wordpress.com/2013/01/07/breaking-the-rules-with-spatial-correlation/ . However, when we try to use the coordinates command within "sp", we keep getting an error message:
Code example:
coords <- data.frame(lead$X, lead$Y)
coordinates(coords) <- c("lead6.X","lead6.Y")
Error in if (nchar(projargs) == 0) projargs <- as.character(NA) missing value where TRUE/FALSE needed
We can't load our direct code because it's sensitive and hosted on a virtual environment without access to the internet. Does anyone have ideas for why this might be happening? We've looked into the proj4 package but can't figure out how to specify a projection system (or is that even the error that we are getting?). If anyone knows of any other packages in R or ways to visualize spatial autocorrelation, those would be much appreciated too.
Your code is a bit "strange": seems you are trying to build a dataset containing only coordinates. AFAIU, you may need something in this line :
data <- data.frame(lead$X, lead$Y, lead$Z)
,with lead$Z corresponding to a generic "variable" you want to inspect, then
coordinates(data) <- c('X','Y')`
proj4string(data) <- "+init=epsg:4326"
, which should give you a proper "SpatialPointsDataframe" with lat-lon WGS84 geographic coordinates (the first line could be also dropped, and you'll keep all variables in the data of the spatialpointsdataframe).
HTH

Resources