0
votes

The following code will create SpatialLines that connect all x/y points in a dataset. However, each of those x/y points has a unique ID. I need to retain both the startpoint and the endpoint IDs of the x/y as "attributes" (the ArcGIS term) of each of the SpatialLines that connect them.

Help would be appreciated.

I have a dataset of XY values that looks like this

x<-c(2,4,6,3,7,9,1)
y<-c(6,4,8,2,9,6,1)
id<-c("a","b","c","d","e","f","g")
dataset<-data.frame(cbind(x,y,id))
dataset$x<-as.numeric(as.character(dataset$x)) #converting from factor to numeric
dataset$y<-as.numeric(as.character(dataset$y))

plot(dataset$x,dataset$y)

Replicate the dataframe to cover for all possible combinations

dataset<-do.call(rbind, replicate(7, dataset, simplify=FALSE))

Now, create a matrix with all the same destination points, mixed:

nm=matrix(ncol=3)
for (i in 1:7){
  nm<-rbind(nm,do.call(rbind,replicate(7,as.matrix(dataset[i,]),simplify=FALSE)))
}
nm<-nm[-1,]

Rename the columns of matrix, so they make sense, and bind the existing data frame with the new matrix

colnames(nm)<-c("x2","y2","id.dest")
newds<-cbind(dataset,as.data.frame(nm))

Remove duplicated trajectories:

newds1<-newds[-which(newds$id==newds$id.dest),]

converting destination x & y to numeric from factor

newds1$x2<-as.numeric(as.character(newds1$x2)) #converting from factor to numeric
newds1$y2<-as.numeric(as.character(newds1$y2))

plotting the destination points . . .same as the origin points

plot(newds1$x, newds1$y) 
plot(newds1$x2, newds1$y2, col="red") 
####*

converting the begin and end points to spatial lines

raw list to store Lines objects

l <- vector("list", nrow(newds1)) #

this l is now an empty vector w/ number of rows defined by length (nrow) of newds1

splitting origin and destination coordinates so I can run this script

 origins<-data.frame(cbind(newds1$x, newds1$y))
    destinations<-data.frame(cbind(newds1$x2, newds1$y2))

    library(sp)
    for (i in seq_along(l)) {
      l[[i]] <- Lines(list(Line(rbind(origins[i, ], destinations[i,]))), as.character(i))
    }

    l.spatial<-SpatialLines(l)
    plot(l.spatial, add=T) 

The object newds1 contains both the startpoint and endpoint. However, the final SpatialLines that are created from those start and endpoints (l.spatial) do not contain a reference to the start and endpoints. I would like those SpatialLines to contain two "attribute" columns that refer to the IDs of the start and endpoints. I think this is a matter of binding newds1 (a dataframe) onto l.spatial (spatial lines), but the code I'm running doesn't seem to do it.

Attempting to spatially bind the start and end IDs to l.spatial

row.names(newds1)<-1:length(newds1$id) #renaming rows in the dataframe so they match the spatial object

id<-newds1$id
newds2<-spCbind(l.spatial, id)

I get

"Error in (function (classes, fdef, mtable)  : 
  unable to find an inherited method for function ‘spCbind’ for signature ‘"SpatialLines", "factor"’"
1
You can't, without keeping your own index into the geometry.Maybe use the trip package? Happy to discuss optionsmdsumner
Now I see what you are doing, I'll answermdsumner

1 Answers

1
votes

In short:

newds2 <- SpatialLinesDataFrame(l.spatial, newds1, match.ID = FALSE)  
## or you can use the rownames of newds1 in the lines loop)

There are 42 distinct lines, made by matching every coordinate to each other coordinate once.

FWIW, you don't need to convert from factor for numeric:

 x <- c(2,4,6,3,7,9,1)
 y <- c(6,4,8,2,9,6,1)
 id <- c("a","b","c","d","e","f","g")
 ## don't coerce to character in the 
 ##first place cbind(x, y, id) *must* be 
 ## character and then data.frame 
 ## converts characters to factors 
 dataset <- data.frame(x = x, y = y, id = id)

There are other ways to simplify your task, but here's a reasonably straightforward way (I think this is what you are after):

x <- c(2,4,6,3,7,9,1) y <- c(6,4,8,2,9,6,1) id<-c("a","b","c","d","e","f","g") ## don't coerce to character in the first place cbind(x, y, id) must be character ## and then data.frame converts characters to factors by default dataset<-data.frame(x = x, y = y, id = id)

l <- vector("list", nrow(dataset) * (nrow(dataset) - 1)) 
origID <- destID <- character(length(l))
##xy <- as.matrix(dataset[, c("x", "y")])
cnt <- 0
for (i in seq(nrow(dataset))) {
  pt0 <- as.matrix(dataset[i, c("x", "y") ])
  pts <- dataset[-i, ]
  for (j in seq(nrow(pts))) {
    cnt <- cnt + 1
    l[[cnt]] <- Lines(list(Line(rbind(pt0, as.matrix(pts[j, c("x", "y")])))), as.character(cnt))
    destID[cnt] <- pts$id[j]
    origID[cnt] <- dataset$id[i]
  }
}

x <- SpatialLinesDataFrame(SpatialLines(l), data.frame(dest = destID, orig = origID, row.names = as.character(1:cnt)))

Pick out one line and investigate:

itest <- 10
## so for example
as.data.frame(x[itest, ])

index <- c(x$orig[itest], x$dest[itest])
plot(x)
plot(x[itest, ], lwd = 4, add = TRUE)
lines(dataset[index, c("x", "y")], col = "firebrick", lwd = 2)
text(dataset[index, c("x", "y")], label = dataset$id[index], col = "dodgerblue", cex = 4)