in R, save a shapefile - r

I would like to save a shapefile after a manipulation.
First, I read my object
map<-readOGR("C:/MAPS","33SEE250GC_SIR")
After this, I subset my shapefile:
test <- fortify(map, region="CD_GEOCODI")
test<- subset(test, -43.41<long & long < -43.1 & - 23.05<lat & lat< -22.79)
I get the corresponding id's of this subset
ids<- unique(test$id)
map2<- map[map$CD_GEOCODI %in% ids ,]
When I plot the map2, it is all right. But, when I try to save this shapefile, somethinh is wrong
writeOGR(map2, dsn = "C:/MAPS" , layer = "nameofmynewmap")
Error in match(driver, drvs$name) :
argument "driver" is missing, with no default
I don't know how to get the drive. Some solution?

The problem is that your map2object is no longer a shapefile and therefore you cannot save it as a shapefile. The fortify command converts the data slot of the shape file (map#data) to data.frame object to be used for mapping purposes. ggplot2 cannot handle objects of class sp (spatial polygon i.e. shape files). I'm assuming you want to save this 'reduced' or 'subsetted' data. What you need to do is the following:
library(rgdal)
library(dplyr)
map <- readOGR("C:/MAPS","33SEE250GC_SIR")
map <- subset(world, LON>-43.41 | LON < -43.1 & LAT>- 23.05 | LAT< -22.79)
writeOGR(map, ".", "filename",
driver = "ESRI Shapefile") #also you were missing the driver argument

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

How to create a subset of a shp file, with all its properties

I am new to programming in R and with .shp files.
I am trying to take a subsample / subset of a .shp file that is so big, you can download this file from here: https://www.ine.es/ss/Satellite?L=es_ES&c=Page&cid=1259952026632&p=1259952026632&pagename=ProductosYServicios%2FPYSLayout (select the year 2021 and then go ahead).
I have tried several things but none of them work, neither is it worth passing it to sf because it would simply add one more column called geometry with the coordinates listed and that is not enough for me to put it later in the leaflet package.
I have tried this here but it doesn't work for me:
myspdf = readOGR(getwd(), layer = "SECC_CE_20210101") #It works
PV2 = myspdf[myspdf#data$NCA == 'País Vasco', ] #Dont work
PV2 = myspdf[,myspdf#data$NCA == 'País Vasco'] #Dont work
What I intend is to create a sample of myspdf (with data, polygons, plotorder, bbox and proj4string) but I don't want it from all the NCA values ​​(myspdf#data$NCA), I only want those in which data$NCA are 'País Vasco'
In short, I would like to have a sample for each value of the different NCA column.
Is that possible? someone can help me on this? thank you very much.
I have tried this too but the same thing as before appears to me, all 18 variables appear and all are empty:
Pais_V = subset(myspdf, NCA == 'País Vasco')
dim(Pais_V)
Here's one approach:
library(rgdal)
dlshape=function(shploc, shpfile) {
temp=tempfile()
download.file(shploc, temp)
unzip(temp)
shp.data <- sapply(".", function(f) {
fp <- file.path(temp, f)
return(readOGR(dsn=".",shpfile))
})
}
setwd("C:/temp")
x = dlshape(shploc="https://www2.census.gov/geo/tiger/GENZ2020/shp/cb_2020_us_aitsn_500k.zip", "cb_2020_us_aitsn_500k")
x<-x$. # extract the shapefile
mycats<-c("00","T2","T3","28")
x2<-subset(x, x$LSAD %in% mycats) # subset using the list `mycats`
mypal=colorFactor("Dark2",domain=x2$LSAD)
library(leaflet)
leaflet(x2) %>% addPolygons(weight=.2, color=mypal(x2$LSAD))
dlshape function courtesy of #yokota
Here's another option. This uses the package sf.
myspdf <- st_read("./_data/España_Seccionado2021/SECC_CE_20210101.shp",
as_tibble = T)
Now you can filter this data any way that you filter a data frame. It will still work as spatial data, as well.
Using tidyverse (well, technically dplyr):
myspdf %>% filter(NCA == "País Vasco")
This takes it from 36,334 observations to 1714 observations.
The base R method you tried to use with readOGR will work, as well.
myspdf[myspdf$NCA == "País Vasco",]

Use "st_transform()" to transform coordinates to another projection - when creating cartogram

I have a shapefile of population estimates of different administrative levels on Nigeria and I want to create a cartogram out of it.
I used the cartogram package and tried the following
library(cartogram)
admin_lvl2_cartogram <- cartogram(admin_level2_shape, "mean", itermax=5)
However this gives me an error stating "Error: Using an unprojected map. This function does not give correct centroids and distances for longitude/latitude data:
Use "st_transform()" to transform coordinates to another projection." I'm not sure how to resolve this
To recreate the initial data
Download the data using the wopr package
library(wopr)
catalogue <- getCatalogue()
# Select files from the catalogue by subsetting the data frame
selection <- subset(catalogue,
country == 'NGA' &
category == 'Population' &
version == 'v1.2')
# Download selected files
downloadData(selection)
Manually unzip the downloaded zip file (NGA_population_v1_2_admin.zip) and read in the data
library(rgdal)
library(here)
admin_level2_shape <- readOGR(here::here("wopr/NGA/population/v1.2/NGA_population_v1_2_admin/NGA_population_v1_2_admin_level2_boundaries.shp"))
The function spTransform in the sp package is probably easiest because the readOGR call returns a spatial polygon defined in that package.
Here's a full example that transforms to a suitable projection for Nigeria, "+init=epsg:26331". You'll probably have to Google to find the exact one for your needs.
#devtools::install_github('wpgp/wopr')
library(wopr)
library(cartogram)
library(rgdal)
library(sp)
library(here)
catalogue <- getCatalogue()
# Select files from the catalogue by subsetting the data frame
selection <- subset(catalogue, country == 'NGA' & category == 'Population' & version == 'v1.2')
# Download selected files
downloadData(selection)
unzip(here::here("wopr/NGA/population/v1.2/NGA_population_v1_2_admin.zip"),
overwrite = T,
exdir = here::here("wopr/NGA/population/v1.2"))
admin_level2_shape <- readOGR(here::here("wopr/NGA/population/v1.2/NGA_population_v1_2_admin/NGA_population_v1_2_admin_level2_boundaries.shp"))
transformed <- spTransform(admin_level2_shape, CRS("+init=epsg:26331"))
admin_lvl2_cartogram <- cartogram(transformed, "mean", itermax=5)
I confess I don't know anything about the specific packages so I don't know if what is produced is correct, but at least it transforms.

R: From GeoJson to DataFrame?

I've a GeoJson file for Peru and it's states (Departamentos in Spanish).
I can plot Peru's states using leaflet, but as the GeoJson file has not all the data I need, I'm thinking of converting it to a data.frame adding the columns of data I need then return it to GeoJson format for plotting.
Data: You can donwload the GeoJson data of Perú from here:
This is the data I'm using and I need to add it a Sales Column with a row for every state ("NOMBDEP" - 24 in total)
library(leaflet)
library(jsonlite)
library(dplyr)
states <- geojsonio::geojson_read("https://raw.githubusercontent.com/juaneladio/peru-geojson/master/peru_departamental_simple.geojson", what = "sp")
I thought of using "jsonlite" package to transform "GeoJson" to a data frame, but getting this error:
library(jsonlite)
states <- fromJSON(states)
Error: Argument 'txt' must be a JSON string, URL or file.
I was expecting that after having a data frame I could be able to do something like:
states$sales #sales is a vector with the sales for every department
states <- toJson(states)
You can use library(geojsonsf) to go to and from GeoJSON and sf
library(geojsonsf)
library(sf) ## for sf print methods
states <- geojsonsf::geojson_sf("https://raw.githubusercontent.com/juaneladio/peru-geojson/master/peru_departamental_simple.geojson")
states$myNewValue <- 1:nrow(states)
geo <- geojsonsf::sf_geojson(states)
substr(geo, 1, 200)
# [1] "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"COUNT\":84,\"FIRST_IDDP\":\"01\",\"HECTARES\":3930646.567,\"NOMBDEP\":\"AMAZONAS\",\"myNewValue\":1},\"geometry\":{\"type\":\"Polygon\",\"coordinat"
.
You can see myNewValue is in the GeoJSON
You don't need to convert back and forth, you can just add another column to the states SPDF:
states <- geojsonio::geojson_read("https://raw.githubusercontent.com/juaneladio/peru-geojson/master/peru_departamental_simple.geojson", what = "sp")
states$sales <- abs(rnorm(nrow(states), sd=1000))
plot(states, col=states$sales)
Yields this image:

How to import OSM polygons data from PostGIS to R?

I am new to the world of spatial analysis using R. Using this link I have downloaded OSM data in .osm.pbf format. Then I used osm2pgsql tool to get data in PostgreSQL (PostGIS extension). Now I have several tables in my database and I want to access the polygons table in R and then perform spatial analysis on the polygon vector data. I have been searching around allot but am not able to import required data in R. I found this tutorial quite similar to what I am looking for but its in Python. I want to access polygon data from PostGIS using R.
Therefore, essentially I would like to know interaction of R with PostGIS. Can anybody recommend me any book on this topic? Since I couldn't find a blog or tutorial so far that works for me on my Windows 10 64-bit machine.
Thanks for your time and looking forward for the suggestions.
I have still not found a way to get required data form PostGIS using rgdal package available in R. Probably it is because of my OS issues. (I am not exactly sure as I am not an expert). But I have found an alternative to rgdal and it has done exactly what I wanted it to do. The code is as following:
library(RPostgreSQL)
library(rgeos)
library(sp)
# Load data from the PostGIS server
conn = dbConnect(
dbDriver("PostgreSQL"), dbname="dbNAME", host="localhost", port=5432,
user="username", password="pw"
)
strSQL = "SELECT osm_id, name, area, highway, railway, place, ST_AsText(way) AS wkt_geometry FROM table"
df = dbGetQuery(conn, strSQL)
#Geomtery column as R list
geo_col = df$wkt_geometry
polygon_list = suppressWarnings(lapply(geo_col, function(x){
x <- gsub("POLYGON\\(\\(", "", x)
x <- gsub("\\)", "", x)
x <- strsplit(x, ",")[[1]]
#Now each polygon has been parsed by removing POLYGON(( from the start and )) from the end
#Now for each POLYGON its xValues and yValues are to be extracted to for Polygon object
xy <- strsplit(x, " ")
v_xy = suppressWarnings(sapply(xy, function(p){
xValue = p[1]
yValue = p[2]
vec = c(xValue, yValue)
}))
#Now we have all x values in first column of v_xy and all y values in second column of v_xy
#Let us make the Polygon object now
p_xvalues = as.numeric(v_xy[1, ])
p_yvalues = as.numeric(v_xy[2, ])
p_object <- Polygon(cbind(p_xvalues, p_yvalues))
}))
#Now we have all of the polygons in polygon object format
#Let us join it with main data frame, i.e. df
df$object_polygon <- polygon_list
#View(df)
#Now Let us form SpatialPolygons() object out of it
Ps_list = list()
for (i in seq(nrow(df))) {
Ps_list[[i]] <- Polygons(polygon_list[i], ID=df[i,][1])
}
SPs = SpatialPolygons(Ps_list)
#Now FINALY its the time to form SpatialPolygonsDataFrame
row.names(df) = df$osm_id
SPDF = SpatialPolygonsDataFrame(Sr = SPs, data = df[, 1:6], match.ID = TRUE)
Therefore, essentially I had to write a parser to get the required data which readOGR() does it one line.
I dont know R, but very familiar with postgis. Postgis is just SQL functions, if you can use Select you can access postgis,
So if you want access polygon just create new function in postgres.
But if you want display polygons you need check with R what function are available, i usually use Openlayer javascript api to show my results in the webpage.

Resources