Как создать объект SpatialLines из неопределенной и неизвестной пространственной последовательности точек в R? - PullRequest
0 голосов
/ 05 августа 2020

У меня есть точки долготы / широты. Проблема в том, что у меня нет идентификатора строк или идентификатора сортировки внутри строк. Итак, я хочу сделать многострочные из точек по критерию расстояния между точками. Например, на изображении здесь должно быть создано не менее 4 строк.

Как я могу этого добиться?

1 Ответ

1 голос
/ 06 августа 2020

Я не думаю, что есть простое общее решение этой проблемы. Вот пример использования spatstat для достижения цели:

library(spatstat)

Создание тестовых данных:

d1 <- data.frame(x=1:9, y=-4)
d2 <- data.frame(x=1:9, y=0)
d3 <- data.frame(x=1:9, y=4)
X <- as.ppp(rbind(d1,d2,d3), W = owin(c(0,10), c(-5,5)))
set.seed(42)
X <- rjitter(X, 0.5)
plot(X)

Find connected components and within each component connect every point with the two closest neighbours:

Xcomp <- connected.ppp(X, R = 2)
Xcomp <- split(Xcomp)
neighbours <- list()
line_list <- list()
for(i in seq_along(Xcomp)){
  pts <- Xcomp[[i]]
  nn <- nnwhich(pts, k=1:2)
  x0 <- c(pts$x, pts$x)
  y0 <- c(pts$y, pts$y)
  x1 <- c(pts$x[nn[,1]], pts$x[nn[,2]])
  y1 <- c(pts$y[nn[,1]], pts$y[nn[,2]])
  line_list[[i]] <- psp(x0, y0, x1, y1, window = Window(X))
}

Соберите компоненты вместе и преобразуйте их в линейную сеть (linnet), которая по сути представляет собой неориентированный граф, в котором узлы имеют явное расположение в евклидовом пространстве, а не являются абстрактными.

L <- Reduce(superimpose.psp, line_list)
L <- as.linnet(L)
#> Warning: Network is not connected
plot(L)

The remaining task is to find all triangles and delete the longest edge which is more fiddly. You can use edges2triangles to find all triangles:

tri <- edges2triangles(L$from, L$to)
tri
#>       i  j  k
#> [1,]  1  2  3
#> [2,]  4  5  6
#> [3,]  7  8  9
#> [4,] 10 11 12
#> [5,] 13 14 15
#> [6,] 16 17 18
#> [7,] 19 20 21
#> [8,] 25 26 27

Так, например, вершины 25,26,27 образуют треугольник

i <- as.numeric(tri[8,])
Li <- thinNetwork(L, retainvertices = i)
plot(Li)

The triangle has three edges from i to j:

j <- i[c(2,3,1)]
i
#> [1] 25 26 27
j
#> [1] 26 27 25

Матрица расстояний между всеми вершинами (перебор, но легко вычисляется и должно выполняться только один раз - избегайте больших наборов данных)

D <- pairdist(vertices(L))

Индекс самого большого расстояния:

long <- which.max(diag(D[i,j]))
long
#> [1] 1

Таким образом, край от i[long] до j[long] должен быть удален

plot(L)
edge <- which(paste(L$from,L$to)==paste(sort(c(i[long],j[long])), collapse = " "))
plot(thinNetwork(L, retainedges = edge), add = TRUE, col = 2, lwd = 1.5)

We should apply this code to all triangles in a loop:

edge <- numeric(nrow(tri))
for(k in seq_len(nrow(tri))){
  i <- tri[k,]
  j <- i[c(2,3,1)]
  long <- which.max(diag(D[i,j]))
  edge[k] <- which(paste(L$from,L$to)==paste(sort(c(i[long],j[long])), collapse = " "))
}
Lfinal <- thinNetwork(L, retainedges = -edge)
plot(Lfinal)

If the lines are needed separately we can use connected:

Lfinal_list <- connected.linnet(Lfinal, what = "components")
Lfinal_list
#> [[1]]
#> Linear network with 9 vertices and 8 lines
#> Enclosing window: rectangle = [0, 10] x [-5, 5] units
#> 
#> [[2]]
#> Linear network with 9 vertices and 8 lines
#> Enclosing window: rectangle = [0, 10] x [-5, 5] units
#> 
#> [[3]]
#> Linear network with 9 vertices and 8 lines
#> Enclosing window: rectangle = [0, 10] x [-5, 5] units

Поиск и удаление треугольников может быть легко выполнено для каждого компонента при построении линий, а не в конце, когда все строки будут собраны. Это было бы намного эффективнее для больших наборов данных, но это прекрасно работает как доказательство концепции. Остерегайтесь хитростей, таких как трюк со вставкой выше, чтобы найти номер края - это может быть не очень надежно, и я не уверен, работает ли он во всех случаях.

...