如何创建多行字符串 sf 对象以在 Leaflet 地图中创建时间滑块
How to create multiline string sf object to create a time slider in Leaflet map
我正在尝试创建一张传单地图,其中显示了一年中不同月份的不同移动路径。 IE。我有一个显示每月多次旅程的数据集,我想使用 leaflet.extras2 包的 addTimeslider 功能分别显示每个月的移动路径。
为此,我一直在尝试调整我在此处找到的 SymbolixAU 发布的代码:leaflet add multiple polylines
此代码使用包括 st_linestring 在内的 sf 函数来创建一个对象,该对象可提供给 addPolylines 传单函数以一次显示所有移动路径。
我很确定我的目的(每个月分别显示数据)我必须使用 st_multilinestring,它需要一个矩阵列表,其中包含每行多条折线的坐标(每行一行月)而不是每行一条折线。
一旦我有了它,我想我可以将该对象提供给 leaflet.extras2 的 addTimeslider 函数来实现我需要的。我对此非常确定,因为当我在 AddTimeslider 功能中使用使用 sf_linestring 创建的 sf 对象时,我能够一次将地图上的时间滑块用于单独的移动路径。
但是,我已经尝试了几个小时,但一直没有成功。非常感谢任何指点,谢谢。
一些示例数据:
#load packages
library(dplyr)
library(leaflet)
library(leaflet.extras2)
library(sf)
library(data.table)
# create the example dataset
data <- structure(list(arrival_month = structure(c(3L, 3L, 4L, 4L, 4L,
5L, 5L, 6L, 6L, 6L), .Label = c("January", "February", "March",
"April", "May", "June", "July", "August", "September", "October",
"November", "December"), class = c("ordered", "factor")), start_lat = c(33.40693,
33.64672, 33.57127, 33.42848, 33.54936, 33.53418, 33.60399, 33.49554,
33.5056, 33.61696), start_long = c(-112.0298, -111.9255, -112.049,
-112.0998, -112.0912, -112.0911, -111.9273, -111.9687, -112.0563,
-111.9866), finish_lat...4 = c(33.40687, 33.64776, 33.57125,
33.42853, 33.54893, 33.53488, 33.60401, 33.49647, 33.5056, 33.61654
), finish_lat...5 = c(-112.0343, -111.9303, -112.0481, -112.0993,
-112.0912, -112.0911, -111.931, -111.9711, -112.0541, -111.986
)), row.names = c(NA, -10L), class = c("data.table", "data.frame"
), .internal.selfref = <pointer: 0x0000026e5df41ef0>)
我对代码的尝试:
# Convert the data into a list of matrices for each month
mnths <- c("May","March","April","June")
mat_list <- list()
for (i in mnths) {
month <- as.matrix(data %>% filter(arrival_month == i) %>% select(-1))
mat_list[[i]] <- month
}
# convert to an sf object
data_DT <- setDT(data)
sf <- data_DT[
, {
geometry <- sf::st_multilinestring(x = mat_list)
geometry <- sf::st_sfc(geometry)
geometry <- sf::st_sf(geometry = geometry)
}
, by = arrival_month
]
sf <- sf::st_as_sf(sf)
这会产生以下结果:
这是不正确的,因为每一行都包含所有月份的坐标,而不仅仅是相应行中月份的坐标。我不知道从哪里开始 - 任何帮助将不胜感激。
谢谢
今天我会稍微不同,利用 {sfheaders}
构建线串。
library(sfheaders)
library(sf)
library(data.table)
setDT( data )
data[, line_id := .I ] ## Assuming each row is a line
## create a long-form of the data
dt_line <- rbindlist(
list(
data[, .(arrival_month, line_id, lon = start_long, lat = start_lat, sequence = 1)]
, data[, .(arrival_month, line_id, lon = finish_lat...5, lat = finish_lat...4, sequence = 2)] ## I think 'finish_lat...5' is actually the 'long'
)
)
setorder(dt_line, line_id, sequence)
sf <- sfheaders::sf_multilinestring(
obj = dt_line
, x = "lon"
, y = "lat"
, multilinestring_id = "arrival_month"
, linestring_id = "line_id"
, keep = T
)
sf::st_crs( sf ) <- 4326 ## Assuming it's in Web Mercator
# Simple feature collection with 4 features and 2 fields
# Geometry type: MULTILINESTRING
# Dimension: XY
# Bounding box: xmin: -112.0998 ymin: 33.40687 xmax: -111.9255 ymax: 33.64776
# Geodetic CRS: WGS 84
#. arrival_month sequence geometry
# 1 3 1 MULTILINESTRING ((-112.0298...
# 2 4 1 MULTILINESTRING ((-112.049 ...
# 3 5 1 MULTILINESTRING ((-112.0911...
# 4 6 1 MULTILINESTRING ((-111.9687...
注意 arrival_month
已重新编码为它的因子水平。
我设法调整了 SymbolixAU 提供的代码以满足我的目的,使用 sf_multilinestring 而不是 sf_line 字符串:
## Generate data
data <- structure(list(arrival_month = structure(c(3L, 3L, 4L, 4L, 4L,
5L, 5L, 6L, 6L, 6L), .Label = c("January", "February", "March",
"April", "May", "June", "July", "August", "September", "October",
"November", "December"), class = c("ordered", "factor")), start_lat = c(33.40693,
33.64672, 33.57127, 33.42848, 33.54936, 33.53418, 33.60399, 33.49554,
33.5056, 33.61696), start_long = c(-112.0298, -111.9255, -112.049,
-112.0998, -112.0912, -112.0911, -111.9273, -111.9687, -112.0563,
-111.9866), finish_lat...4 = c(33.40687, 33.64776, 33.57125,
33.42853, 33.54893, 33.53488, 33.60401, 33.49647, 33.5056, 33.61654
), finish_lat...5 = c(-112.0343, -111.9303, -112.0481, -112.0993,
-112.0912, -112.0911, -111.931, -111.9711, -112.0541, -111.986
)), row.names = c(NA, -10L), class = c("data.table", "data.frame"
))
## Add id column and convert to data table
data[, line_id := .I ]
setDT(data)
## create a long-form of the data
dt_line <- rbindlist(
list(
data[, .(arrival_month, line_id, lon = start_long, lat = start_lat, sequence = 1)]
, data[, .(arrival_month, line_id, lon = finish_lat...5, lat = finish_lat...4, sequence = 2)] ## I think 'finish_lat...5' is actually the 'long'
)
)
setorder(dt_line, line_id, sequence)
## Create multistring sf object
sf <- sfheaders::sf_multilinestring(
obj = dt_line
, x = "lon"
, y = "lat"
, linestring_id = "line_id"
, multilinestring_id = "arrival_month"
, keep = TRUE
)
sf::st_as_sf(sf)
## Convert arrival_month back to factor
sf$arrival_month <- as.factor(sf$arrival_month)
可能不是最优雅的,但这个可以。
关键是使用 sf_multilinestring 和 include/specify linestring_id 和 multilinestring_id 来区分不同的多段线。
这是结果:
现在,当在 AddTimeslider 中使用此 sf 对象时,它的行为符合预期。
大部分代码归功于 SymbolixAU,并让我注意到 sfheaders 包
我正在尝试创建一张传单地图,其中显示了一年中不同月份的不同移动路径。 IE。我有一个显示每月多次旅程的数据集,我想使用 leaflet.extras2 包的 addTimeslider 功能分别显示每个月的移动路径。
为此,我一直在尝试调整我在此处找到的 SymbolixAU 发布的代码:leaflet add multiple polylines
此代码使用包括 st_linestring 在内的 sf 函数来创建一个对象,该对象可提供给 addPolylines 传单函数以一次显示所有移动路径。
我很确定我的目的(每个月分别显示数据)我必须使用 st_multilinestring,它需要一个矩阵列表,其中包含每行多条折线的坐标(每行一行月)而不是每行一条折线。
一旦我有了它,我想我可以将该对象提供给 leaflet.extras2 的 addTimeslider 函数来实现我需要的。我对此非常确定,因为当我在 AddTimeslider 功能中使用使用 sf_linestring 创建的 sf 对象时,我能够一次将地图上的时间滑块用于单独的移动路径。
但是,我已经尝试了几个小时,但一直没有成功。非常感谢任何指点,谢谢。
一些示例数据:
#load packages
library(dplyr)
library(leaflet)
library(leaflet.extras2)
library(sf)
library(data.table)
# create the example dataset
data <- structure(list(arrival_month = structure(c(3L, 3L, 4L, 4L, 4L,
5L, 5L, 6L, 6L, 6L), .Label = c("January", "February", "March",
"April", "May", "June", "July", "August", "September", "October",
"November", "December"), class = c("ordered", "factor")), start_lat = c(33.40693,
33.64672, 33.57127, 33.42848, 33.54936, 33.53418, 33.60399, 33.49554,
33.5056, 33.61696), start_long = c(-112.0298, -111.9255, -112.049,
-112.0998, -112.0912, -112.0911, -111.9273, -111.9687, -112.0563,
-111.9866), finish_lat...4 = c(33.40687, 33.64776, 33.57125,
33.42853, 33.54893, 33.53488, 33.60401, 33.49647, 33.5056, 33.61654
), finish_lat...5 = c(-112.0343, -111.9303, -112.0481, -112.0993,
-112.0912, -112.0911, -111.931, -111.9711, -112.0541, -111.986
)), row.names = c(NA, -10L), class = c("data.table", "data.frame"
), .internal.selfref = <pointer: 0x0000026e5df41ef0>)
我对代码的尝试:
# Convert the data into a list of matrices for each month
mnths <- c("May","March","April","June")
mat_list <- list()
for (i in mnths) {
month <- as.matrix(data %>% filter(arrival_month == i) %>% select(-1))
mat_list[[i]] <- month
}
# convert to an sf object
data_DT <- setDT(data)
sf <- data_DT[
, {
geometry <- sf::st_multilinestring(x = mat_list)
geometry <- sf::st_sfc(geometry)
geometry <- sf::st_sf(geometry = geometry)
}
, by = arrival_month
]
sf <- sf::st_as_sf(sf)
这会产生以下结果:
这是不正确的,因为每一行都包含所有月份的坐标,而不仅仅是相应行中月份的坐标。我不知道从哪里开始 - 任何帮助将不胜感激。
谢谢
今天我会稍微不同,利用 {sfheaders}
构建线串。
library(sfheaders)
library(sf)
library(data.table)
setDT( data )
data[, line_id := .I ] ## Assuming each row is a line
## create a long-form of the data
dt_line <- rbindlist(
list(
data[, .(arrival_month, line_id, lon = start_long, lat = start_lat, sequence = 1)]
, data[, .(arrival_month, line_id, lon = finish_lat...5, lat = finish_lat...4, sequence = 2)] ## I think 'finish_lat...5' is actually the 'long'
)
)
setorder(dt_line, line_id, sequence)
sf <- sfheaders::sf_multilinestring(
obj = dt_line
, x = "lon"
, y = "lat"
, multilinestring_id = "arrival_month"
, linestring_id = "line_id"
, keep = T
)
sf::st_crs( sf ) <- 4326 ## Assuming it's in Web Mercator
# Simple feature collection with 4 features and 2 fields
# Geometry type: MULTILINESTRING
# Dimension: XY
# Bounding box: xmin: -112.0998 ymin: 33.40687 xmax: -111.9255 ymax: 33.64776
# Geodetic CRS: WGS 84
#. arrival_month sequence geometry
# 1 3 1 MULTILINESTRING ((-112.0298...
# 2 4 1 MULTILINESTRING ((-112.049 ...
# 3 5 1 MULTILINESTRING ((-112.0911...
# 4 6 1 MULTILINESTRING ((-111.9687...
注意 arrival_month
已重新编码为它的因子水平。
我设法调整了 SymbolixAU 提供的代码以满足我的目的,使用 sf_multilinestring 而不是 sf_line 字符串:
## Generate data
data <- structure(list(arrival_month = structure(c(3L, 3L, 4L, 4L, 4L,
5L, 5L, 6L, 6L, 6L), .Label = c("January", "February", "March",
"April", "May", "June", "July", "August", "September", "October",
"November", "December"), class = c("ordered", "factor")), start_lat = c(33.40693,
33.64672, 33.57127, 33.42848, 33.54936, 33.53418, 33.60399, 33.49554,
33.5056, 33.61696), start_long = c(-112.0298, -111.9255, -112.049,
-112.0998, -112.0912, -112.0911, -111.9273, -111.9687, -112.0563,
-111.9866), finish_lat...4 = c(33.40687, 33.64776, 33.57125,
33.42853, 33.54893, 33.53488, 33.60401, 33.49647, 33.5056, 33.61654
), finish_lat...5 = c(-112.0343, -111.9303, -112.0481, -112.0993,
-112.0912, -112.0911, -111.931, -111.9711, -112.0541, -111.986
)), row.names = c(NA, -10L), class = c("data.table", "data.frame"
))
## Add id column and convert to data table
data[, line_id := .I ]
setDT(data)
## create a long-form of the data
dt_line <- rbindlist(
list(
data[, .(arrival_month, line_id, lon = start_long, lat = start_lat, sequence = 1)]
, data[, .(arrival_month, line_id, lon = finish_lat...5, lat = finish_lat...4, sequence = 2)] ## I think 'finish_lat...5' is actually the 'long'
)
)
setorder(dt_line, line_id, sequence)
## Create multistring sf object
sf <- sfheaders::sf_multilinestring(
obj = dt_line
, x = "lon"
, y = "lat"
, linestring_id = "line_id"
, multilinestring_id = "arrival_month"
, keep = TRUE
)
sf::st_as_sf(sf)
## Convert arrival_month back to factor
sf$arrival_month <- as.factor(sf$arrival_month)
可能不是最优雅的,但这个可以。
关键是使用 sf_multilinestring 和 include/specify linestring_id 和 multilinestring_id 来区分不同的多段线。
这是结果:
现在,当在 AddTimeslider 中使用此 sf 对象时,它的行为符合预期。
大部分代码归功于 SymbolixAU,并让我注意到 sfheaders 包