convert streamstats() object into sf() object - r

I would like to create a sf() object from the streamstats function delineateWatershed() without first needing to save as shapefiles of jsons. I can delineate the polygon, then save as a shape, and finally import back in as a shapefile. This leaves me with a version of the shape file in a nested folder, which will quickly take up space. Once I have my sf() polygons I plan to merge multiple together and save them as a single shapefile. In the end I will have two copies of the polygons. How can I skip the writeShapefile() then st_read step?
setwd('~/R/GIS/data/') #I need to define the working directory for writeShapefile()
ws <- delineateWatershed(xlocation = -123.9637, ylocation = 40.06269, crs = 4326)
##writeShapefile(watershed = ws, layer = "name of shape file", "name of folder in dir", what='boundary')
writeShapefile(watershed = ws, layer = "shed", "data", what = 'boundary')
ws_sf <- st_read("~/R/GIS/data/shed.shp")

After some some guess and check I came up with a solution, but I would love to see a more elegant one without a loop. I found the list of coords for the polygon. Made a data frame from the list, then used st_polygon. Props to #Gilles for the last part
ws1 <- ws$featurecollection[[2]]$feature$features[[1]]$geometry$coordinates[[1]]
length(ws1)
for (i in 1:length(ws1)){
ws2[i,] <- data.frame(ws1[[i]])
}
ws3 <- st_sf(st_sfc(st_polygon(list(as.matrix(ws2)))), crs = 4326)
mapview(ws3)

Related

How to subsample a file of type SpatialPolygonsDataFrame in R without losing the properties of the shp file

I'm new to programming in R and I want to make an interactive map from two files, one is a .shp that you can download from here: https://www.ine.es/ss/Satellite?L=es_ES&c=Page&cid=1259952026632&p=1259952026632&pagename=ProductosYServicios%2FPYSLayout (just select 2021 year and go and its download), in which there are many polygons. And then I have a csv with store characterization data (it contains 2 LON and LAT fields).
To start doing all this I would like to filter the .shp file for each different value in the NCA field (Ex: 1 map for Basque Country, another for Madrid, another for Barcelona ...).
All this without losing the geometric properties since if I lose them then I can't represent them graphically (or maybe I can and I don't know, if so, let me know and I will be very grateful).
He probado con el siguiente codigo:
# Load the libraries
pacman::p_load(leaflet, leaflet.extras, mapview, rworldxtra, rgdal,raster, sf, tidyverse, readr, ggthemes)
# Load the .shp file in spdf format.
myspdf = readOGR(getwd(), layer = "SECC_CE_20210101")
#Filter
PV = myspdf %>% filter(NCA == "País Vasco") # Dont work
PV2 = myspdf[myspdf$NCA == "País Vasco"] # Dont work
When I load the shp file and save it in the variable myspdf, I can visualize something like this: https://ibb.co/mywDd6p
in which if I do myspdf#data I access the data (where is the NCA field where I want to filter)
So when I try to filter like this:
PV = myspdf %>% filter(NCA == "País Vasco") # Dont work
PV2 = myspdf[myspdf$NCA == "País Vasco"] # Dont work
It returns this to me this: https://ibb.co/VDYdByq, with the rows completely empty, and what I would like to obtain is the same format but with about 1700 rows x 18 columns and with the geometric properties as well.
Another question I have is that when I read the .shp file as sf, one more column is added with the geometry and inside are the coordinates stored in lists, like that: https://ibb.co/M1Fn8K5, I can easily filter it but I don't know how to represent it graphically (leaflet or mapview...) so that You can see the polygons of NCA = 'Basque Country', could someone give me an example with this? I would be enormously grateful
Ok! I guess I will do the all workflow!
library(sf)
library(tmap)
library(mapview)
# lets get some shops
shop <- data.frame(X = c(-4.758628, -4.758244, -4.756829, -4.759394, -4.753698,
-4.735330, -4.864548, -4.863816, -4.784694, -4.738924),
Y = c(43.42144, 43.42244, 43.42063, 43.42170, 43.41899,
43.41181, 43.42327, 43.42370, 43.42422, 43.40150),
name = LETTERS[1:10])
# Here I save them
write.csv(shop, "shop.csv")
# because I want to show you how to import
shop <- read.csv("shop.csv")
# and convert to en sf object
shop_sf <- sf::st_as_sf(shop, coords = c("X", "Y"))
# and add a CRS
shop_sf <- sf::st_set_crs(shop_sf, 4326)
# now I have downloaded data from your link
# I import it in R
spain_seccionado <- sf::st_read("España_Seccionado2021/SECC_CE_20210101.shp")
# Rq CRS is ETRS89 / UTM 30, will need to transform that
# here I am just exploring a bit the data set
names(spain_seccionado)
unique(spain_seccionado$NCA)
# I just keep Asturias, You have plenty of different way of doing that
# this is what you tried to do here: PV = myspdf %>% filter(NCA == "País Vasco")
# but on an sp object not an sf one
Asturias <- spain_seccionado[spain_seccionado$NCA == "Principado de Asturias",]
asturias_4326 <- sf::st_transform(Asturias, 4326)
# Now both data set are in the same CRS
# a quick plot just to see if everything is correct
plot(asturias_4326$geometry)
plot(shop_sf, col = "red", add = TRUE, pch = 5)
# An interactive map quick and dirty you will need to improve it !
tmap_mode("view")
llanes_shop <- tmap::tm_shape(asturias_4326) +
tmap::tm_borders() +
tmap::tm_shape(shop_sf) +
tmap::tm_symbols(shape = 24) +
tmap::tm_layout()
llanes_shop

Points not added to the map plot

I need to add some points to the map using simple points function. The issue is that points don't add to the map. It's simple command, I follow some tutorial where adding points to the map works this way but not in my case. Plot function plots Texas choropleth properly but next line (points) doesn't add points to the map at all:
library(rgdal)
library(rgeos)
library(sp)
companies <- read.csv('geoloc_data_comp.csv', header = T, dec = ',', sep = ';')
states <- readOGR('.', 'states')
plot(states[states#data$stat_name == 'texas',])
points(companies$coords.x1, companies$coords.x2, pch = 21)
First you shoud start to avoid rgeos/rgdal because they will stop being maintains. See : https://github.com/r-spatial/evolution
sf is replacing them:
library(sp)
library(sf)
library(spData) #used because I wanted US states
# list of data in spData you have one with US states
data(package = "spData")
if you want to read shapefile or other GIS format check sf::st_read() (instead of readOGR())
# one way with sf
plot(us_states$geometry[us_states$NAME == "Texas"])
# if you want do use the sp way
us_sp <- as(us_states, "Spatial") # convert to sp
plot(us_sp[us_sp#data$NAME == "Texas",])
with sf you have the geometry in one column (see "geometry") instead of having an R S4 with nested lists (see #data and #polygones).
Before getting some points we need to check in which CRS our data are. If you do not know CRS I like this website : https://ihatecoordinatesystems.com/
You also have information in the us_states documentation: https://www.rdocumentation.org/packages/spData/versions/2.0.1/topics/us_states
Then you can use:
sp::proj4string(us_sp)
sf::st_crs(us_states)
# This is EPSG 4269 or NAD83
If you want to use points() they need to be in this coordinates system (I suspect this explain your trouble ie different CRS).
You didn't provide data points so I produced some:
library(osmdata)
#this will just download node matching the key/value place=city
some_city_in_texas <- osmdata::opq(osmdata::getbb("Texas US"),
nodes_only = TRUE) %>%
osmdata::add_osm_feature(key = "place", value = "city") %>%
osmdata::osmdata_sf() #keep them in sf format
# osmdata_sp() also exist
The class osmdata is a bit complicated but here you just need to know that some_city_in_texas$osm_points provide us with points (to test points()). Now we can check their CRS:
sf::st_crs(some_city_in_texas$osm_points)
As you can see we are in an other CRS so we need to transform it. (you will probably need to do it).
city_in_texas <- sf::st_transform(some_city_in_texas$osm_points,
4269)
sf use simple feature standard to store localization and points() want two vectors x&y. You should also check that (common cause of error): R use x/y (long/lat) and not lat/long.
Here we convert city_in_texas to just coords. (if you need to do the reverse, ie converting data frame with X/Y, into an sf object look at sf::st_as_sf())
coords_city <- sf::st_coordinates(city_in_texas)
Finally this works fine now:
plot(us_states$geometry[us_states$NAME == "Texas"])
points(coords_city, pch = 21)
Good ressources are https://r-spatial.org/ and https://geocompr.robinlovelace.net/

How to convert SpatialPointDataFrame to normal dataframe in r?

I could load shp file in r:
setwd("something")
shp = readOGR(dsn = ".", layer = "shp_name")
Now, I want to convert that to a normal dataframe. What should I do?
I found the answer. It's just works like in general:
shp_df = as.data.frame(shp, xy = T)
You don’t always have to complicate things...

Convert SpatialCollections to SpatialPolygonsDataFrame in R

I am struggling to convert an object of class SpatialCollections to a SpatialPolygonsDataFrame object.
My input files are both shapefiles and SpatialPolygonsDataFrame objects. They can be accessed here.
I do an intersection of both objects:
SPDF_A <- shapefile("SPDF_A")
SPDF_B <- shapefile("SPDF_B")
intersection <- gIntersection(gBuffer(SPDF_A, width=0), gBuffer(SPDF_B, width=0))
The result is:
> intersection
class : SpatialCollections
Setting gBuffer(... , byid=T) or gBuffer(... , byid=F) seems to make no difference.
I use gIntersection and gBuffer(... , width=0) insetead of intersect in order to avoid geometrical problems (Self-intersection).
This is part of a larger loop. I need to get the intersection as SpatialPolygonsDataFrame because it will be saved as shp file in a following step.
writeOGR(intersection, ".", layer=paste0("Int_SPDF_A-SPDF_B"), driver="ESRI Shapefile")
This is not possible from a SpatialCollections object. In order to convert this to a SpatialPolygonsDataFrame I tried:
intersection <- as(intersection ,"SpatialPolygonsDataFrame")
intersection <- SpatialPolygonsDataFrame(intersection)
intersection <- readOGR(intersection, layer = "intersection")
Nothing works. Does anybody have a solution? Thanks a lot!
First of all, according to the documentation SpatialCollections is kind of a container format that can "hold SpatialPoints, SpatialLines, SpatialRings, and SpatialPolygons (without attributes)". If you need the data frame part of your SpatialPolygonsDataFrame ("attribute table" in GIS language), you'll have to work around that somehow. If, on the other hand, you're only interested in the spatial information (the polygons without the data attached to them) try the following:
str(intersection, max.level = 3)
suggests that the #polyobj is nothing but a SpatialPolygons object. Hence
mySpoly <- intersection#polyobj
should do the trick and
class(mySpoly)
suggests that we indeed now have a SpatialPolygons.
You need to convert that to a SpatialPolygonsDataFrame before exporting:
mySpolyData <- as(mySpoly, "SpatialPolygonsDataFrame")
writeOGR(mySpolyData, ".", layer=paste0("Int_SPDF_A-SPDF_B"), driver="ESRI Shapefile")

How to convert .shp file into .csv in R?

I want to to convert two .shp files into one database that would allow me to draw the maps together.
Also, is there a way to convert .shp files into .csv files? I want to be able to personalize and add some data which is easier for me under a .csv format. What I have in mind if to add overlay yield data and precipitation data on the maps.
Here are the shapefiles for Morocco, and Western Sahara.
Code to plot the two files:
# This is code for mapping of CGE_Morocco results
# Loading administrative coordinates for Morocco maps
library(sp)
library(maptools)
library(mapdata)
# Loading shape files
Mor <- readShapeSpatial("F:/Purdue University/RA_Position/PhD_ResearchandDissert/PhD_Draft/Country-CGE/MAR_adm1.shp")
Sah <- readShapeSpatial("F:/Purdue University/RA_Position/PhD_ResearchandDissert/PhD_Draft/Country-CGE/ESH_adm1.shp")
# Ploting the maps (raw)
png("Morocco.png")
Morocco <- readShapePoly("F:/Purdue University/RA_Position/PhD_ResearchandDissert/PhD_Draft/Country-CGE/MAR_adm1.shp")
plot(Morocco)
dev.off()
png("WesternSahara.png")
WesternSahara <- readShapePoly("F:/Purdue University/RA_Position/PhD_ResearchandDissert/PhD_Draft/Country-CGE/ESH_adm1.shp")
plot(WesternSahara)
dev.off()
After looking into suggestions from #AriBFriedman and #PaulHiemstra and subsequently figuring out how to merge .shp files, I have managed to produce the following map using the following code and data (For .shp data, cf. links above)
code:
# Merging Mor and Sah .shp files into one .shp file
MoroccoData <- rbind(Mor#data,Sah#data) # First, 'stack' the attribute list rows using rbind()
MoroccoPolys <- c(Mor#polygons,Sah#polygons) # Next, combine the two polygon lists into a single list using c()
summary(MoroccoData)
summary(MoroccoPolys)
offset <- length(MoroccoPolys) # Next, generate a new polygon ID for the new SpatialPolygonDataFrame object
browser()
for (i in 1: offset)
{
sNew = as.character(i)
MoroccoPolys[[i]]#ID = sNew
}
ID <- c(as.character(1:length(MoroccoPolys))) # Create an identical ID field and append it to the merged Data component
MoroccoDataWithID <- cbind(ID,MoroccoData)
MoroccoPolysSP <- SpatialPolygons(MoroccoPolys,proj4string=CRS(proj4string(Sah))) # Promote the merged list to a SpatialPolygons data object
Morocco <- SpatialPolygonsDataFrame(MoroccoPolysSP,data = MoroccoDataWithID,match.ID = FALSE) # Combine the merged Data and Polygon components into a new SpatialPolygonsDataFrame.
Morocco#data$id <- rownames(Morocco#data)
Morocco.fort <- fortify(Morocco, region='id')
Morocco.fort <- Morocco.fort[order(Morocco.fort$order), ]
MoroccoMap <- ggplot(data=Morocco.fort, aes(long, lat, group=group)) +
geom_polygon(colour='black',fill='white') +
theme_bw()
Results:
New Question:
1- How to eliminate the boundaries data that cuts though the map in half?
2- How to combine different regions within a .shp file?
Thanks you all.
P.S: the community in stackoverflow.com is wonderful and very helpful, and especially toward beginners like :) Just thought of emphasizing it.
Once you have loaded your shapefiles into Spatial{Lines/Polygons}DataFrames (classes from the sp-package), you can use the fortify generic function to transform them to flat data.frame format. The specific functions for the fortify generic are included in the ggplot2 package, so you'll need to load that first. A code example:
library(ggplot2)
polygon_dataframe = fortify(polygon_spdf)
where polygon_spdf is a SpatialPolygonsDataFrame. A similar approach works for SpatialLinesDataFrame's.
The difference between my solution and that of #AriBFriedman is that mine includes the x and y coordinates of the polygons/lines, in addition to the data associated to those polgons/lines. I really like visualising my spatial data with the ggplot2 package.
Once you have your data in a normal data.frame you can simply use write.csv to generate a csv file on disk.
I think you mean you want the associated data.frame from each?
If so, it can be accessed with the # slot access function. The slot is called data:
write.csv( WesternSahara#data, file="/home/wherever/myWesternSahara.csv")
Then when you read it back in with read.csv, you can try assigning:
myEdits <- read.csv("/home/wherever/myWesternSahara_modified.csv")
WesternSahara#data <- myEdits
You may need to do some massaging of row names and so forth to get it to accept the new data.frame as valid. I'd probably try to merge the existing data.frame with a csv you read in in R, rather than making edits destructively....

Resources