Defining polygon object by identifying lines in R - r

I have a dataset contains lines and I have imported them into R. I want to take a close look at the coordinates of them and define the identical first and last coordinate of each point if there is some -->(looking for polygon). Therefore, I am using Slot which makes me able to have a close look at the details of the desired object.
My final goal is to define the number of identical point coordinates(First and last) for each line in order to discover the number of the potential polygon in my data.
recapping my difficulty is the following question:
How many of lines objects have potential to be a polygon?
To do so, I have done several steps:
In the first step, I read my data into R.
The second step, I have used slot to have a close look at the coordinate of each point(Sequence of points represent line object).
the third step: I have tried to define the number of identical points but I have faced with an error says CRDs not found
at the following, you can tack a look at the codes
enter library(maptools)
#Read data directly from National Geophysical Data Center (NGDC) coastline
#extractor.
shorelinedat="http://www.asdar-book.org/RC1/datasets/auckland_mapgen.dat"
#Assign CRS
llCRS <- CRS("+proj=longlat +ellps=WGS84")
#Read data from mapgen into a SpatialLines object.
auck_shore <- MapGen2SL("auckland_mapgen.dat", llCRS)
#Required code to identify the lines.
lns <- slot(auck_shore, "lines")
table(sapply(lns, function(x) length(slot(x, "Lines"))))
Here is the code in which I faced with the error
#identifying the number of identical coordinates
islands_auck <- sapply(lns, function(x) {
+ crds <- slot(slot(x, "Lines")[[1]], "coords")
+ identical(crds[1, ], crds[nrow(crds), ])
+ })
This is the error
Error in +crds <- slot(slot(x, "Lines")[[1]], "coords") :
object 'crds' not found
I would appreciate if anyone can give a hint.

This is just a guess, are those +s actually in your code? If I try to assign to a variable with a + before it (as you do in the code example you posted), I get the same error you got:
+ crds <- 5
Error in +crds <- 5 : object 'crds' not found
When you run a multi-line block of code, R inserts + in the console to show continuing lines, but that's just a visual effect and they are illegal in your actual code.

The problem I had was related to the syntax in the final code which I modified them in below
islands_auck <- sapply(lns, function(x) {
crds <- slot(slot(x, "Lines")[[1]], "coords")
identical(crds[1, ], crds[nrow(crds), ])
})
table(islands_auck)
so the final result will be
islands_auck
FALSE TRUE
16 64
16 lines without equal first and last coordinate (Closed polygon)
64 lines with closed polygon

Related

R sf: Points of LinearRing do not form a closed linestring

I am trying to calculate the centroids of a set of polygons.
My dataset, geodata, contains five columns including one geometry column of class sfc_GEOMETRY, with 45759 rows.
When I run sf::st_centroid(geodata), I get the following message
Error in CPL_geos_op("centroid", x, numeric(0), integer(0), numeric(0), : Evaluation error: IllegalArgumentException: Points of LinearRing do not form a closed linestring.
In addition: Warning messages:
1: In st_centroid.sf(geodata) :
st_centroid assumes attributes are constant over geometries of x
2: In st_centroid.sfc(st_geometry(x), of_largest_polygon = of_largest_polygon) :
st_centroid does not give correct centroids for longitude/latitude data
Should I run a loop to detect which geometry is not closed?
Is this a problem with the class of my geometry? Should it be sfc_MULTIPOLYGON?
Possible solution:
I was encountering this problem when reading in a list of files through a loop. The loop would read in the files and then rbind them together into geodata, and then calculate the centroid:
for(i in 1:length(list)){
file <- st_read(list[i])
geodata <- rbind(geodata, file) #geodata is here a void sf object
}
geocent <- st_centroid(geodata)
When I calculated the centroids within the loop (for each file in the list), the error disappeared.
for(i in 1:length(list)){
file <- st_read(list[i])
file <- st_centroid(file)
geocent <- rbind(geodata, file) #geodata is here a void sf object
}
Hence, I think the problem lay in the binding operation.
Perhaps I had not defined my void sf object in the right manner.
Perhaps rbind was not the appropriate function, or I should have specified its parameters.
There's no need to run a loop to find which geometry is bad. The st_is_valid() function should tell you which row(s) have the problem.
It looks like one of your geometries might be made up of an incorrect number of points.
More info about finding and fixing the problem at r-spatial: https://www.r-spatial.org/r/2017/03/19/invalid.html

R extract() doesn´t accept my coordinates

First of all, I´m new to programing so this might be a simple question but i cant find the solution anywhere.
I´ve been using this code to extract values from a set of stacked rasters:
raster.files <- list.files()
raster.list <- list()
raster.files <-list.files(".",pattern ="asc")
for(i in 1: length(raster.files)){
raster.list[i] <- raster(raster.files[i])}
stacking <- stack(raster.list)
coord <- read.csv2("...")
extract.data <- extract(stacking,coord,method="simple")
I already used this code several times without any problem, until now. Every time I run the extract line I get this error:
Error in .doCellFromXY(object#ncols, object#nrows, object#extent#xmin, :
Not compatible with requested type: [type=character; target=double].
The coord file consists in a data.frame with 2 columns(X and Y respectively).
I´ve managed to found a way to bypass this error, its not technically a solution because I can´t understand why R was treating my data as text instead in first place.
Basically I separated the X and Y columns and treated them individually and then binded them again in a new data.frame:
coord_matrix_x<-as.numeric(as.matrix(coord[1]))
coord_matrix_y<-as.numeric(as.matrix(coord[2]))
coord2 <- cbind(coord_matrix_x, coord_matrix_y)
coord2<-as.data.frame(coord2)
coordinates(coord2)<-c("coord_matrix_x","coord_matrix_y")
It´s far form the most elegant way to do it, but it just works.

Spatial Polygon sampling error in R

I have a shape file of 200 counties. How should I sample in order to subset counties from the existing 200? I have tried using the below R code:
library(maptools)
TXcounties <- readShapePoly("C:/Users/Rvg296/Downloads/TXCountiesShapeFiles/TXCounties.shp")
idx <- sample(1:250, 25, replace = FALSE)
df.TXcounties <- as.data.frame(TXcounties)
SpatialPolygonsDataFrame(idx, df.TXcounties).
But this is throwing an error like:
Error in SpatialPolygonsDataFrame(idx, df.TXcounties) : trying to get slot "polygons" from an object of a basic class ("integer") with no slots
The problem is that you are using idx, an integer vector, as the first argument for SpatialPolygonsDataFrame(), but this function needs a spatial polygons object as its first argument. In any case, you should be able to do the whole thing a lot more easily with something like this:
result <- TXcounties[idx,]

Creating SpatialLinesDataFrame from SpatialLines object and basic df

Using leaflet, I'm trying to plot some lines and set their color based on a 'speed' variable. My data start at an encoded polyline level (i.e. a series of lat/long points, encoded as an alphanumeric string) with a single speed value for each EPL.
I'm able to decode the polylines to get lat/long series of (thanks to Max, here) and I'm able to create segments from those series of points and format them as a SpatialLines object (thanks to Kyle Walker, here).
My problem: I can plot the lines properly using leaflet, but I can't join the SpatialLines object to the base data to create a SpatialLinesDataFrame, and so I can't code the line color based on the speed var. I suspect the issue is that the IDs I'm assigning SL segments aren't matching to those present in the base df.
The objects I've tried to join, with SpatialLinesDataFrame():
"sl_object", a SpatialLines object with ~140 observations, one for each segment; I'm using Kyle's code, linked above, with one key change - instead of creating an arbitrary iterative ID value for each segment, I'm pulling the associated ID from my base data. (Or at least I'm trying to.) So, I've replaced:
id <- paste0("line", as.character(p))
with
lguy <- data.frame(paths[[p]][1])
id <- unique(lguy[,1])
"speed_object", a df with ~140 observations of a single speed var and row.names set to the same id var that I thought I created in the SL object above. (The number of observations will never exceed but may be smaller than the number of segments in the SL object.)
My joining code:
splndf <- SpatialLinesDataFrame(sl = sl_object, data = speed_object)
And the result:
row.names of data and Lines IDs do not match
Thanks, all. I'm posting this in part because I've seen some similar questions - including some referring specifically to changing the ID output of Kyle's great tool - and haven't been able to find a good answer.
EDIT: Including data samples.
From sl_obj, a single segment:
print(sl_obj)
Slot "ID":
[1] "4763655"
[[151]]
An object of class "Lines"
Slot "Lines":
[[1]]
An object of class "Line"
Slot "coords":
lon lat
1955 -74.05228 40.60397
1956 -74.05021 40.60465
1957 -74.04182 40.60737
1958 -74.03997 40.60795
1959 -74.03919 40.60821
And the corresponding record from speed_obj:
row.names speed
... ...
4763657 44.74
4763655 34.8 # this one matches the ID above
4616250 57.79
... ...
To get rid of this error message, either make the row.names of data and Lines IDs match by preparing sl_object and/or speed_object, or, in case you are certain that they should be matched in the order they appear, use
splndf <- SpatialLinesDataFrame(sl = sl_object, data = speed_object, match.ID = FALSE)
This is documented in ?SpatialLinesDataFrame.
All right, I figured it out. The error wasn't liking the fact that my speed_obj wasn't the same length as my sl_obj, as mentioned here. ("data =
object of class data.frame; the number of rows in data should equal the number of Lines elements in sl)
Resolution: used a quick loop to pull out all of the unique lines IDs, then performed a left join against that list of uniques to create an exhaustive speed_obj (with NAs, which seem to be OK).
ids <- data.frame()
for (i in (1:length(sl_obj))) {
id <- data.frame(sl_obj#lines[[i]]#ID)
ids <- rbind(ids, id)
}
colnames(ids)[1] <- "linkId"
speed_full <- join(ids, speed_obj)
speed_full_short <- data.frame(speed_obj[,c(-1)])
row.names(speed_full_short) <- speed_full$linkId
splndf <- SpatialLinesDataFrame(sl_obj, data = speed_full_short, match.ID = T)
Works fine now!
I may have deciphered the issue.
When I am pulling in my spatial lines data and I check the class it reads as
"Spatial Lines Data Frame" even though I know it's a simple linear shapefile, I'm using readOGR to bring the data in and I believe this is where the conversion is occurring. With that in mind the speed assignment is relatively easy.
sl_object$speed <- speed_object[ match( sl_object$ID , row.names( speed_object ) ) , "speed" ]
This should do the trick, as I'm willing to bet your class(sl_object) is "Spatial Lines Data Frame".
EDIT: I had received the same error as OP, driving me to check class()
I am under the impression that the error that was populated for you is because you were trying to coerce a data frame into a data frame and R wasn't a fan of that.

Loop polygon clipping with gIntersection

Question
I am trying to perform a number of polygon clips using the gIntersection function with R in a loop. I can obtain the correct clips and re-enter data manually (so I can turn the resulting SpatialPolygons object back into a SpatialPolygonsDataFrame object). What I can't do is get this working in a loop with for() or apply().
At the moment this isn't a problem. I have 9 English regions (with London), so it's not a huge challenge to set each clip up manually. But, I want to eventually clip LSOAs in LADs, which essentially means setting up >400 clips.
So, my question is, how do I turn my manual clips into a working loop?
Minimal Reproducible Example
To keep things simple, let's use the English regions (n = 9). For each of the 9 regions, I'm going to clip the counties. The following code loads the appropriate shapefiles and reprojects them as British National Grid:
require(rgdal)
require(rgeos)
# English counties shapefile (~ 10MB zipped)
download.file(
"https://dl.dropboxusercontent.com/s/6o0mi28pjo1kh9k/england-counties.zip",
"ec", method = "wget")
unzip("ec")
ec <- readOGR("england-counties", "england_ct_2011")
proj4string(ec) <- CRS("+init=epsg:27700")
# English regions (~6MB zipped)
download.file(
"https://dl.dropboxusercontent.com/s/p69m0vk2fh4xe3o/england-regions-2011.zip",
"er", method = "wget")
unzip("er")
er <- readOGR("england-regions-2011", "England_gor_2011")
proj4string(er) <- CRS("+init=epsg:27700")
You should be left with two objects, er (English regions) and ec (English counties). Both are SpatialPolygonsDataFrame objects.
Taking the first region - East of England E12000006 - let's clip the counties and turn the result back in to a SpatialPolygonsDataFrame object:
ee <- gIntersection(ec, er[er$CODE == "E12000006", ],
byid = T, drop_not_poly = T)
row.names(ee) <- as.character(gsub(" 0", "", row.names(ee)))
# gIntersection adds ' 0' to each row.name?
ee <- SpatialPolygonsDataFrame(ee, ec#data[row.names(ee), ])
A plot of ee confirms this worked:
As you can see, this is a nice workflow for just a few shapes, but I really want to loop through all regions and, ultimately, many more polygons.
What I've Tried
I'm not very good with apply() loops, so what I've tried so far is a for() loop (which I know is relatively slow, but still quicker than typing everything out!):
regions <- as.character(er$CODE) # length = 9 as expected
for(i in 1:length(regions)){
as.name(paste0(regions[i], "c")) <-
gIntersection(ec, er[er$CODE == regions[1], ], byid = T, drop_not_poly = T)
}
Rather than the expected behaviour I get the following error:
Error in as.name(paste0(regions[1], "c")) <- gIntersection(ec, er[er$CODE == :
could not find function "as.name<-"
I also tried wrapping the object name in an eval() but get the following error:
Error in eval(as.name(paste0(regions[1], "c"))) <- gIntersection(ec, er[er$CODE == :
could not find function "eval<-"
What am I missing?
In addition to the gIntersection, I would like to re-create a SpatialPolygonsDataFrame object if possible. I've tried the following code, having done one gIntersection manually, but again it doesn't work:
for(i in 1:length(regions)){
row.names(as.name(paste0(regions[i], "c"))) <- as.character(gsub(" 0", "",
row.names(as.name(paste0(regions[i], "c")))))
}
I get the following error:
Error in `rownames<-`(x, value) :
attempt to set 'rownames' on an object with no dimensions
I'm also not sure how to increment the " 0", as this increases by one for each new region (" 1", " 2", etc.)
Again, setting the first example up manually I also can't perform the final SpatialPolygonsDataFrame step:
for(i in 1:length(regions)){
as.name(regions[i]) <- SpatialPolygonsDataFrame(regions[i],
ec#data[row.names(regions[i], )])
}
For this I get the following error:
Error in stopifnot(length(Sr#polygons) == nrow(data)) :
trying to get slot "polygons" from an object of a basic class ("character") with no
slots
Where I've looked
The following SO examples are related by do not seem to help, or at least I can't see how I would make them apply to this example:
rgeos gIntersection in loop takes too long to clip path network
How to clip WorldMap with polygon in R?
https://gis.stackexchange.com/questions/33278/no-intersection-found-between-polygons-i-know-intersect
Thanks for taking the time to read this.
Does this help?
ee <- lapply(regions, function(x)
gIntersection(ec, er[er$CODE == x, ], byid = TRUE, drop_not_poly = TRUE))
This gives you a list of SpatialPolygonsDataFrames, one for each region. Which you can access in the usual way, e.g.
ee[[1]]
plot(ee[[1]]) # to plot the first region with counties
Edit
Your orignial code should work with a sligh modification (see blow).
res <- list()
for (i in 1:length(regions)) {
ee <- gIntersection(ec, er[er$CODE == regions[i], ],
byid = TRUE, drop_not_poly = TRUE)
row.names(ee) <- as.character(gsub(paste0(" ", i-1), "", row.names(ee)))
ee <- SpatialPolygonsDataFrame(ee, ec#data[row.names(ee), ])
res[[i]] <- ee
}
If that solves the problem, then the problem was, that row names of ee always incremented by one and you did not account for this.

Resources