I would like to merge some regions in gadm data and then plot the map. So far I have the following:
#install.packages("sp",dependencies=TRUE)
#install.packages("RColorBrewer",dependencies=TRUE)
#install.packages("maptools",dependencies=TRUE)
library(sp)
library(maptools)
#library(RColorBrewer)
# get spatial data
con <- url("http://gadm.org/data/rda/CZE_adm2.RData")
print(load(con))
close(con)
IDs <- gadm$ID_2
IDs[IDs %in% c(11500:11521)] <- "11500"
gadm_new <- unionSpatialPolygons(gadm, IDs)
# plot map
spplot(gadm_new, "NAME_2", col.regions=col, main="Test",colorkey = FALSE, lwd=.4, col="white")
However this results in error:
Error in function (classes, fdef, mtable) :
unable to find an inherited method for function "spplot", for signature "SpatialPolygons"
Now I have no idea what can possibly fix this error.
I'm not sure about what you're trying to do here.
The error is due to the fact that spplot is used to draw spatial objects with attributes, ie with associated data. Your gadm object is of class SpatialPolygonsDataFrame, so it defines polygons and associated data that can be accessed via the slot gadm#data. When you use UnionSpatialPolygons, you only get a SpatialPolygons class object, which can be plotted with plot, but not with spplot :
IDs <- gadm$ID_2
IDs[IDs %in% c(11500:11521)] <- "11500"
gadm_new <- unionSpatialPolygons(gadm, IDs)
plot(gadm_new)
If you want to use spplot, you have to merge your associated data manually, the same way you merged your polygons, and then build back a SpatialPolygonsDataFrame. One way to do it is the following :
gadm_new <- gadm
## Change IDs
gadm_new$ID_2[gadm_new$ID_2 %in% c(11500:11521)] <- "11500"
## Merge Polygons
gadm_new.sp <- unionSpatialPolygons(gadm_new, gadm_new$ID_2)
## Merge data
gadm_new.data <- unique(gadm_new#data[,c("ID_2", "ENGTYPE_2")])
## Rownames of the associated data frame must be the same as polygons IDs
rownames(gadm_new.data) <- gadm_new.data$ID_2
## Build the new SpatialPolygonsDataFrame
gadm_new <- SpatialPolygonsDataFrame(gadm_new.sp, gadm_new.data)
Then you can use spplot to plot a map with an associated attribute :
spplot(gadm_new, "ENGTYPE_2", main="Test", lwd=.4, col="white")
Note that here I only used the ENGTYPE_2 variable of your data, not the NAME_2 variable, as I don't see the point to represent a variable where each value seems unique for each polygon.
Related
I'm reasonably new to R and I am trying to rasterize the output of spdep's localG function.
This code:
neigh2<-dnearneigh(profcurvPts, 0, 2)
list<-nb2listw(neigh2)
gistar<-localG(profcurvPts$layer, list)
girast<-rasterize(gistar, profcurv)
Yields an error unable to find an inherited method for function 'rasterize' for signature '"localG", "RasterLayer"'
I have tried changing the localG class to a data.frame, but it creates a 1 column matrix that still won't rasterize.
To sum it up: what should I do to get a raster of the localG output?
Thanks in advance!
You are trying to call an object of class localG which has no associated method for sp or raster classes. Here is a workflow for rasterizing a local G result.
First, add packages and data. The meuse object is of SpatialPointsDataFrame and meuse.grid starts as SpatialGridDataFrame but is coerced into a rasterLayer object for rasterizing the point data.
library(spdep)
library(raster)
data(meuse)
coordinates(meuse) <- ~x+y
proj4string(meuse) <- CRS("+init=epsg:28992")
data(meuse.grid)
coordinates(meuse.grid) = ~x+y
proj4string(meuse.grid) <- CRS("+init=epsg:28992")
gridded(meuse.grid) = TRUE
meuse.grid <- raster(meuse.grid)
Here we conduct the local G analysis.
nb <- dnearneigh(coordinates(meuse), 0, 500)
G <- localG(meuse$cadmium, nb2listw(nb, style="B"))
This is where we can coerce the localG results, join them to the point data and rasterize the results. You can use as.numeric for coercing from a localG object (basically a list object). Please read the help for raster::rasterize. The x argument requires SpatialPoints or a matrix of coordinates, y is a rasterLayer object to provide the raster dimensions and field represents the attribute that is being rasterized. If you need a background value for the raster that is other than NA then use the background argument.
meuse$G <- as.numeric(G)
spplot(meuse, "G")
Gr <- rasterize(coordinates(meuse), meuse.grid, field = meuse$G, background = NA)
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.
I am trying to iterate thru the process of creating centroids of a list of SpatialPolygonsDataFrames (each with several polygon features within), with the resulting SpatialPoints preserving the attributes (data) of the parent polygons. I have tried the sp::over function, but it seems to be problematic because centroids do not necessarily overlap with parent polygons. Furthermore, I am new to coding/R and do not know how to achieve this in a for loop and/or using an apply function.
So specifically, I need to (1) find a different function that will link the SpatialPolygonsDataFrames with the associated SpatialPoints (centroids); and (2) iterate thru the entire process and merge the SpatialPolygonsDataFrames data with the appropriate SpatialPoints - I do not know how to match the index value of one list to the index value in another while running a loop.
Here is a reproducible example for a single SpatialPolygonsDataFrames object showing that using sp::over doesn't work because some centroids do not end up overlapping parent polygons:
library(maptools) ## For wrld_simpl
library(sp)
## Example SpatialPolygonsDataFrames (SPDF)
data(wrld_simpl) #polygon of world countries
spdf1 <- wrld_simpl[1:25,] #country subset 1
spdf2 <- wrld_simpl[26:36,] #subset 2
spdf3 <- wrld_simpl[36:50,] #subset 3
spdfl[[1]]#data
#plot, so you can see it
plot(spdf1)
plot(spdf2, add=TRUE, col=4)
plot(spdf3, add=TRUE, col=3)
#make list of SPDF objects
spdfl<-list()
spdfl[[1]]<-spdf1
spdfl[[2]]<-spdf2
spdfl[[2]]<-spdf3
#create polygon centroids for each polygon feature (country) within spdfl[[1]]
spdf1c <- gCentroid(spdfl[[1]], byid=TRUE)
plot(spdfl[[1]])
plot(spdf1c, add=TRUE)
#add attributes 'NAME' and 'AREA' to SpatialPoints (centroid) object from SPDF data
spdf.NAME <- over(spdf1c, spdfl[[1]][,"NAME"])
spdf.AREA <- over(spdf1c, spdfl[[1]][,"AREA"])
spdf1c$NAME <- spdf.NAME
spdf1c$AREA <- spdf.AREA
spdf1c#data
#`sp::over` output error = name and area for ATG, ASM, BHS, and SLB are missing
I find SF is a great package for working with spatial data in R. I have fixed a few typos and added the right for loop below.
library(maptools) ## For wrld_simpl
library(sp)
library(sf)
## Example SpatialPolygonsDataFrames (SPDF)
data(wrld_simpl) #polygon of world countries
spdf1 <- wrld_simpl[1:25,] #country subset 1
spdf2 <- wrld_simpl[26:36,] #subset 2
spdf3 <- wrld_simpl[36:50,] #subset 3
spdfl[[1]]#data
#plot, so you can see it
plot(spdf1)
plot(spdf2, add=TRUE, col=4)
plot(spdf3, add=TRUE, col=3)
#make list of SPDF objects
spdfl<-list()
spdfl[[1]]<-spdf1
spdfl[[2]]<-spdf2
spdfl[[3]]<-spdf3
# Empty List for Centroids
centres <-list()
# For Loop
for (i in 1:length(spdfl)) {
centres[[i]] <- spdfl[[i]] %>%
sf::st_as_sf() %>% # translate to SF object
sf::st_centroid() %>% # get centroids
as(.,'Spatial') # If you want to keep as SF objects remove this line
}
#Plot your Spatial Objects
plot(spdfl[[1]])
plot(centres[[1]], add=TRUE)
Here is a solution which uses SF and sp. SF is great as it keeps things as dataframes which can easy to deal with. More information here: https://r-spatial.github.io/sf/
The data
I have two shapefiles marking the boundaries of national and provincial electoral constituencies in Pakistan.
The objective
I am attempting to use R to create a key that will generate a list of which provincial-level constituencies are "contained within" or otherwise intersecting with which national-level constituencies, based on their coordinates in this data. For example, NA-01 corresponds with PA-01, PA-02, PA-03; NA-02 corresponds with PA-04 and PA-05, etc. (The key will ultimately be used to link separate dataframes containing electoral results at the national and provincial level; that part I've figured out.)
I have only basic/intermediate R skills learned largely through trial and error and no experience working with GIS data outside of R.
The attempted solution
The closest solution I could find for this problem comes from this guide to calculating intersection areas in R. However, I have been unable to successfully replicate any of the three proposed approaches (either the questioner's use of a general TRUE/FALSE report on intersections, or the more precise calculations of area of overlap).
The code
# import map files
NA_map <- readOGR(dsn = "./National_Constituency_Boundary", layer = "National_Constituency_Boundary")
PA_map <- readOGR(dsn = "./Provincial_Constituency_Boundary", layer = "Provincial_Constituency_Boundary")
# Both are now SpatialPolygonsDataFrame objects of 273 and 577 elements, respectively.
# If relevant, I used spdpylr to tweak some of data attribute names (for use later when joining to electoral dataframes):
NA_map <- NA_map %>%
rename(constituency_number = NA_Cons,
district_name = District,
province = Province)
PA_map <- PA_map %>%
rename(province = PROVINCE,
district_name = DISTRICT,
constituency_number = PA)
# calculate intersections, take one
Results <- gIntersects(NA_map, PA_map, byid = TRUE)
# this creates a large matrix of 157,521 elements
rownames(Results) <- NA_map#data$constituency_number
colnames(Results) <- PA_map#data$constituency_number
Attempting to add the rowname/colname labels, however, gives me the error message:
Error in dimnames(x) <- dn :
length of 'dimnames' [1] not equal to array extent
Without the rowname/colname labels, I'm unable to read the overlay matrix, and unsure how to filter them so as to produce a list of only TRUE intersections that would help make a NA-PA key.
I also attempted to replicate the other two proposed solutions for calculating exact area of overlap:
# calculate intersections, take two
pi <- intersect(NA_map, PA_map)
# this generates a SpatialPolygons object with 273 elements
areas <- data.frame(area=sapply(pi#polygons, FUN = function(x) {slot(x, 'area')}))
# this calculates the area of intersection but has no other variables
row.names(areas) <- sapply(pi#polygons, FUN=function(x) {slot(x, 'ID')})
This generates the error message:
Error in `row.names<-.data.frame`(`*tmp*`, value = c("2", "1", "4", "5", :
duplicate 'row.names' are not allowed
In addition: Warning message:
non-unique value when setting 'row.names': ‘1’
So that when I attempt to attach areas to attributes info with
attArrea <- spCbind(pi, areas)
I get the error message
Error in spCbind(pi, areas) : row names not identical
Attempting the third proposed method:
# calculate intersections, take three
pi <- st_intersection(NA_map, PA_map)
Produces the error message:
Error in UseMethod("st_intersection") :
no applicable method for 'st_intersection' applied to an object of class "c('SpatialPolygonsDataFrame', 'SpatialPolygons', 'Spatial', 'SpatialPolygonsNULL', 'SpatialVector')"
I understand that my SPDF maps can't be used for this third approach, but wasn't clear from the description what steps would be needed to transform it and attempt this method.
The plea for help
Any suggestions on corrections necessary to use any of these approaches, or pointers towards some other method of figuring this, would be greatly appreciated. Thanks!
Here is some example data
library(raster)
p <- shapefile(system.file("external/lux.shp", package="raster"))
p1 <- aggregate(p, by="NAME_1")
p2 <- p[, 'NAME_2']
So we have p1 with regions, and p2 with lower level divisions.
Now we can do
x <- intersect(p1, p2)
# or x <- union(p1, p2)
data.frame(x)
Which should be (and is) the same as the original
data.frame(p)[, c('NAME_1', 'NAME_2')]
To get the area of the polygons, you can do
x$area <- area(x) / 1000000 # divide to get km2
There are likely to be many "slivers", very small polygons because of slight variations in borders. That might not matter to you.
But another approach could be matching by centroid:
y <- p2
e <- extract(p1, coordinates(p2))
y$NAME_1 <- e$NAME_1
data.frame(y)
Your code isn't self-contained, so I didn't try to replicate the errors you report.
However, getting the 'key' you want is very simple using the sf package (which is intended to supercede rgeos, rgdal and sp in the near future). See here:
library(sf)
# Download shapefiles
national.url <- 'https://data.humdata.org/dataset/5d48a142-1f92-4a65-8ee5-5d22eb85f60f/resource/d85318cb-dcc0-4a59-a0c7-cf0b7123a5fd/download/national-constituency-boundary.zip'
provincial.url <- 'https://data.humdata.org/dataset/137532ad-f4a9-471e-8b5f-d1323df42991/resource/c84c93d7-7730-4b97-8382-4a783932d126/download/provincial-constituency-boundary.zip'
download.file(national.url, destfile = file.path(tempdir(), 'national.zip'))
download.file(provincial.url, destfile = file.path(tempdir(), 'provincial.zip'))
# Unzip shapefiles
unzip(file.path(tempdir(), 'national.zip'), exdir = file.path(tempdir(), 'national'))
unzip(file.path(tempdir(), 'provincial.zip'), exdir = file.path(tempdir(), 'provincial'))
# Read map files
NA_map <- st_read(dsn = file.path(tempdir(), 'national'), layer = "National_Constituency_Boundary")
PA_map <- st_read(dsn = file.path(tempdir(), 'provincial'), layer = "Provincial_Constituency_Boundary")
# Get sparse list representation of intersections
intrs.sgpb <- st_intersects(NA_map, PA_map)
length(intrs.sgpb) # One list element per national constituency
# [1] 273
print(intrs.sgpb[[1]]) # Indices of provnicial constituencies intersecting with first national constituency
# [1] 506 522 554 555 556
print(PA_map$PROVINCE[intrs.sgpb[[1]]])[1] # Name of first province intersecting with first national constituency
# [1] KHYBER PAKHTUNKHWA
I am wondering if this is possible to do this R .
I have one data as SpatialLinesDataFrame and another as spatialPolygonDataFrame. Is it possible to overlay these two data ?
When I try to overlay these I get the following error:
jd <- overlay(res,hello)
Error in function (classes, fdef, mtable) : unable to find an inherited method for function
‘overlay’ for signature ‘"SpatialLinesDataFrame", "SpatialPolygonsDataFrame"’
In the above code res is the SpatialLinesDataFrame and hello is SpatialPolygonDataFrame.
I have an shapefile and then I have data points with x,yand z
coordinates. I want to show the contour lines on the shapefile.
The procedure I used is using akima package to do the interpolation. The
code I used to interpolate is
fld <- interp(x,y,z)
Then I changed this to spatial object by using following code:
res <-ContourLines2SLDF(contourLines(fld))
The above command would store the contourlines as spatial data.
Then I read the shapefile and I plot both shapefile and res as follows:
p1 <-
spplot(hello,sp.layout=list(list("sp.lines",res)),col="blue",lwd=0,fill="grey",colorkey=F)
p1
"hello" is my shapefile and "res" is the object I created as shown above.
The problem is contour stored in "res" extends beyond the shapefile. So I
want to clip that contour with the shapefile and only display the contour
within the shapefile area.
So I am looking for a way to clip the contour layer with the polygon layer.
I have attached the image I got with my code.
In the image you can see the lines out of the shapefile. I also want to know
how can I display the contour levels on the map.
Thank you so much.
Jdbaba
I also want to know what does overlay does exactly. Does it intersect the area of both the data ?
Thank you.
It sounds like you're trying to clip your lines to the polygon extent. Use gIntersection from the rgeos package. Here's a reproducible example:
library(rgeos)
xx <- SpatialPoints(coords=matrix(data=c(0,0), nrow=1))
xx <- gBuffer(spgeom=xx, width=1)
yy <- SpatialLines(list(Lines(Line(matrix(c(-1,1,-1,1), nrow=2)), ID=1)))
zz <- gIntersection(yy, xx)
You can overlay the plot like so:
plot(xx)
plot(zz, add = TRUE, col = "blue")
Noah's answer has worked quite well for me. However, the output of his answer is a SpatialLines object, which cannot be saved as a shape file.
My two cents here is about how you can convert your SpatialLines object into a SpatialLinesDataFrame and save it as a shape file.
res.df <- fortify(res) # create data frame of res, your original SpatialLinesDataFrame
data <- data.frame(id = unique(res.df$id)) # get ids of road segments
rownames(data) <- data$id
# transform SpatialLines object into SpatialLinesDataFrame
zzSpatialLineDF <- SpatialLinesDataFrame(zz, data) # convert zz object keeping road ids
# 5 Save Shape File to your working directory
writeOGR(zzSpatialLineDF, dsn = '.', layer ='zzSpatialLineDF', driver = 'ESRI Shapefile')