R - создать линию из двух точек в одной строке в фрейме данных

Мне было интересно, есть ли способ создать linestring из двух точек, указанных в одной строке фрейма данных в новом столбце геометрии. Другими словами, долгота и широта двух точек задаются во фрейме данных, как показано ниже:

df <- data.frame(id = c("a", "b"), lon1 = c(1,2), lat1 = c(3,4), lon2 = c(5,6), lat2 = c(7,8))  

где lon1 и lat1 представляют координаты первой точки, а lon2 и lat2 представляют собой координаты второй точки. Желаемый фрейм данных должен иметь две строки и два столбца - столбец id и столбец geometry.

Я пробовал с sf::st_linestring, но, похоже, эта функция работает только с матрицами.

Желаемый фрейм данных:

desired_df <- data.frame(id = c("a", "a", "b", "b"), lon = c(1,2,5,6), lat = c(3,4,7,8)) %>% st_as_sf(coords = c("lon", "lat"), dim = "XY") %>% st_set_crs(4236) %>% group_by(id) %>% summarise(geometry = st_union(geometry), do_union = FALSE) %>% st_cast("LINESTRING")
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
0
2 304
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Мы можем перебрать строки с помощью pmap и применить st_linestring к созданному matrix.

library(tidyverse)
library(sf)
out <- pmap(df[-1], ~
               c(...) %>%
                matrix(., , ncol=2, byrow = TRUE) %>% 
                st_linestring) %>%
          reduce(st_sfc) %>%
          mutate(df, geometry = .)

out$geometry
#Geometry set for 2 features 
#geometry type:  LINESTRING
#dimension:      XY
#bbox:           xmin: 1 ymin: 3 xmax: 6 ymax: 8
#epsg (SRID):    NA
#proj4string:    NA
#LINESTRING (1 3, 5 7)
#LINESTRING (2 4, 6 8)

Есть ли возможность, чтобы столбец строки был столбцом геометрии, а не списком?

adl 19.08.2018 16:26

@adl Можете ли вы проверить, в порядке ли изменение?

akrun 19.08.2018 16:34

в результате все еще остается список. В каждой строке есть список в столбце lstring, а не просто строка

adl 19.08.2018 16:37

@adl А сейчас

akrun 19.08.2018 16:39

формат в порядке, но содержимое внутри строки неверно. Желаемый фрейм данных должен выглядеть следующим образом: df <- data.frame (id = c ("a", "a", "b", "b"), lon = c (1,2,5,6), lat = c (3,4,7,8))%>% st_as_sf (coords = c ("lon", "lat"), dim = "XY")%>% st_set_crs (4236)%>% group_by (id )%>% summarize (geometry = st_union (geometry), do_union = FALSE)%>% st_cast ("LINESTRING")

adl 19.08.2018 16:41

@adl Я думаю, что раньше упустил st_sfc.

akrun 19.08.2018 16:46

Я пытаюсь понять магию муррра, которая здесь произошла. Что именно делает c(...)in pmap(df[-1], ~c(...))? Не могли бы вы заменить нотацию формулы ~ анонимной функцией?

Ratnanil 02.11.2018 09:45

Вдобавок reduce(st_sfc) работает только с двумя строками .. если фрейм данных длиннее этого, возвращается ошибка (Error in vapply(lst, class, rep(NA_character_, 3)) : values must be length 3, but FUN(X[[1]]) result is length 2)

Ratnanil 02.11.2018 10:08

@Ratnanil Это просто объединение c. Вы можете использовать анонимный вызов функции, но отчасти люди используют эти функции, чтобы сделать их чистыми, компактными и т. д. (Это тоже субъективно). По поводу ошибки, возможно, вам придется проверить поведение st_sfc

akrun 02.11.2018 16:38
Ответ принят как подходящий

Обновление - 30 января 2021 г.

Проблема с моим исходным ответом заключается в том, что он неправильно устанавливает ограничивающую рамку.

Сегодня я бы использовал этот подход, используя sfheaders и data.table.

library(data.table)
library(sfheaders)

dt <- as.data.table(df)

## To use `sfheaders` the data needs to be in long form

dt1 <- dt[, .(id, lon = lon1, lat = lat1)]
dt2 <- dt[, .(id, lon = lon2, lat = lat2)]

## Add on a 'sequence' variable so we know which one comes first
dt1[, seq := 1L ]
dt2[, seq := 2L ]

## put back together
dt <- rbindlist(list(dt1, dt2), use.names = TRUE)
setorder(dt, id, seq)

sf <- sfheaders::sf_linestring(
  obj = dt
  , x = "lon"
  , y = "lat"
  , linestring_id = "id"
)

sf

# Simple feature collection with 2 features and 1 field
# geometry type:  LINESTRING
# dimension:      XY
# bbox:           xmin: 1 ymin: 3 xmax: 6 ymax: 8
# CRS:            NA
#   id              geometry
# 1  a LINESTRING (1 3, 5 7)
# 2  b LINESTRING (2 4, 6 8)


Оригинальный ответ

Альтернативный подход с использованием data.table

требовать (data.table)

dt <- as.data.table(df)

sf <- dt[
    , {
        geometry <- sf::st_linestring(x = matrix(c(lon1, lon2, lat1, lat2), nrow = 2, ncol = 2))
        geometry <- sf::st_sfc(geometry)
        geometry <- sf::st_sf(geometry = geometry)
    }
    , by = id
]

sf::st_as_sf(sf)
# Simple feature collection with 2 features and 1 field
# geometry type:  LINESTRING
# dimension:      XY
# bbox:           xmin: 1 ymin: 3 xmax: 5 ymax: 7
# epsg (SRID):    NA
# proj4string:    NA
# id              geometry
# 1  a LINESTRING (1 3, 5 7)
# 2  b LINESTRING (2 4, 6 8)

Это решение также использует purrrpmap, получая результат в желаемом формате.

library(tidyverse)
library(sf) 

df <- data.frame(id = c("a", "b"), lon1 = c(1,2), lat1 = c(3,4), lon2 = c(5,6), lat2 = c(7,8))  

make_line <- function(lon1, lat1, lon2, lat2) {
    st_linestring(matrix(c(lon1, lon2, lat1, lat2), 2, 2))
}

df %>%
    select(-id) %>% 
    pmap(make_line) %>% 
    st_as_sfc(crs = 4326) %>% 
    {tibble(id = df$id, geometry = .)} %>% 
    st_sf() 

Результат:

Simple feature collection with 2 features and 1 field
geometry type:  LINESTRING
dimension:      XY
bbox:           xmin: 1 ymin: 3 xmax: 6 ymax: 8
epsg (SRID):    4326
proj4string:    +proj=longlat +datum=WGS84 +no_defs
# A tibble: 2 x 2
  id            geometry
  <fct> <LINESTRING [°]>
1 a           (1 3, 5 7)
2 b           (2 4, 6 8)
df = data.frame(id = c("a", "b"), lon1 = c(1,2), lat1 = c(3,4), lon2 = c(5,6), lat2 = c(7,8))  
df
##   id lon1 lat1 lon2 lat2
## 1  a    1    3    5    7
## 2  b    2    4    6    8

Вот еще один способ прохождения WKT:

library(sf)
df$geom = sprintf("LINESTRING(%s %s, %s %s)", df$lon1, df$lat1, df$lon2, df$lat2)
df = st_as_sf(df, wkt = "geom")
df
## Simple feature collection with 2 features and 5 fields
## geometry type:  LINESTRING
## dimension:      XY
## bbox:           xmin: 1 ymin: 3 xmax: 6 ymax: 8
## CRS:            NA
##   id lon1 lat1 lon2 lat2                  geom
## 1  a    1    3    5    7 LINESTRING (1 3, 5 7)
## 2  b    2    4    6    8 LINESTRING (2 4, 6 8)

Другие вопросы по теме