如何使用 R 中的 Leaflet 将两个坐标与一条线连接起来
How Do I connect two coordinates with a line using Leaflet in R
我正在尝试使用 R 中的 Leaflet 包绘制放大器并连接标记,给出下面 table 中的纬度和经度信息。
| Observation | InitialLat | InitialLong | NewLat | NewLong |
|-------------|------------|-------------|-----------|-----------|
| A | 62.469722 | 6.187194 | 51.4749 | -0.221619 |
| B | 48.0975 | 16.3108 | 51.4882 | -0.302621 |
| C | 36.84 | -2.435278 | 50.861822 | -0.083278 |
| D | 50.834194 | 4.298361 | 54.9756 | -1.62179 |
| E | 50.834194 | 4.298361 | 54.9756 | -1.62179 |
| F | 50.834194 | 4.298361 | 51.4882 | -0.302621 |
| G | 47.460427 | -0.530804 | 51.44 | -2.62021 |
| H | 51.5549 | -0.108436 | 53.4281 | -1.36172 |
| I | 51.5549 | -0.108436 | 52.9399 | -1.13258 |
| J | 51.5549 | -0.108436 | 51.889839 | -0.193608 |
| | 51.5549 | -0.108436 | 52.0544 | 1.14554 |
我想从 InitialLat
和 InitialLong
列中的坐标给定的起点到 NewLat
和 NewLong
给定的终点画线列。
这是我当前的 R 代码,它只在地图上绘制标记。
library(leaflet)
map3 = leaflet(data) %>% addTiles()
map3 %>% addMarkers(~InitialLong,~InitialLat, popup=~Observation)
Leaflet 可以使用addPolylines
函数添加行。这样做的问题是它假设每条线都已连接 - 您将把它们全部连接起来。
解决此问题的最佳方法 (AFAIK) 是使用循环:
library(leaflet)
map3 = leaflet(data) %>% addTiles()
map3 <- map3 %>% addMarkers(~InitialLong,~InitialLat, popup=~Observation)
for(i in 1:nrow(data)){
map3 <- addPolylines(map3, lat = as.numeric(data[i, c(2, 4)]),
lng = as.numeric(data[i, c(3, 5)]))
}
map3
编辑:使用 Kyle Walker 的 points_to_line function 还有一种更简单的方法(请参阅最底部的代码粘贴副本)。
首先对数据进行整形,使起点和终点在同一列中:
library(tidyr)
library(dplyr)
z <- gather(dta, measure, val, -Observation) %>% group_by(Observation) %>%
do(data.frame( lat=c(.[["val"]][.[["measure"]]=="InitialLat"],
.[["val"]][.[["measure"]]=="NewLat"]),
long = c(.[["val"]][.[["measure"]]=="InitialLong"],
.[["val"]][.[["measure"]]=="NewLong"])))
然后调用points_to_line
z <- as.data.frame(z)
y <- points_to_line(z, "long", "lat", "Observation")
现在剧情:
map3 = leaflet(data) %>% addTiles()
map3 %>% addMarkers(~InitialLong, ~InitialLat, popup = ~Observation) %>%
addPolylines(data = y)
Kyle Walker points_to_line 的来源:
library(sp)
library(maptools)
points_to_line <- function(data, long, lat, id_field = NULL, sort_field = NULL) {
# Convert to SpatialPointsDataFrame
coordinates(data) <- c(long, lat)
# If there is a sort field...
if (!is.null(sort_field)) {
if (!is.null(id_field)) {
data <- data[order(data[[id_field]], data[[sort_field]]), ]
} else {
data <- data[order(data[[sort_field]]), ]
}
}
# If there is only one path...
if (is.null(id_field)) {
lines <- SpatialLines(list(Lines(list(Line(data)), "id")))
return(lines)
# Now, if we have multiple lines...
} else if (!is.null(id_field)) {
# Split into a list by ID field
paths <- sp::split(data, data[[id_field]])
sp_lines <- SpatialLines(list(Lines(list(Line(paths[[1]])), "line1")))
# I like for loops, what can I say...
for (p in 2:length(paths)) {
id <- paste0("line", as.character(p))
l <- SpatialLines(list(Lines(list(Line(paths[[p]])), id)))
sp_lines <- spRbind(sp_lines, l)
}
return(sp_lines)
}
}
这是使用 leaflet
包的替代方法。为了演示,我只是在你的数据中取了两个数据点。
mydf <- data.frame(Observation = c("A", "B"),
InitialLat = c(62.469722,48.0975),
InitialLong = c(6.187194, 16.3108),
NewLat = c(51.4749, 51.4882),
NewLong = c(-0.221619, -0.302621),
stringsAsFactors = FALSE)
我更改了 mydf
的格式并为传单创建了一个新的数据框。您可以通过多种方式重塑数据。
mydf2 <- data.frame(group = c("A", "B"),
lat = c(mydf$InitialLat, mydf$NewLat),
long = c(mydf$InitialLong, mydf$NewLong))
# group lat long
#1 A 62.46972 6.187194
#2 B 48.09750 16.310800
#3 A 51.47490 -0.221619
#4 B 51.48820 -0.302621
library(leaflet)
library(magrittr)
leaflet()%>%
addTiles() %>%
addPolylines(data = mydf2, lng = ~long, lat = ~lat, group = ~group)
我对得到的交互式地图进行了裁剪。请看下面的地图。尽管此图像中两条线相连,但它们是分开的。如果你 运行 代码并放大,你会看到这两行是分开的。
我知道一年前有人问过这个问题,但我也有同样的问题,并在传单中找到了解决方法。
您首先必须调整数据框,因为 addPolyline 只是连接序列中的所有坐标。出于演示目的,我将制作一个包含 4 个独立结束位置的数据框。
dest_df <- data.frame (lat = c(41.82, 46.88, 41.48, 39.14),
lon = c(-88.32, -124.10, -88.33, -114.90)
)
接下来,我将创建一个中心位置与目标位置大小相同(本例中为 4)的数据框。我很快就会解释为什么要这样做
orig_df <- data.frame (lat = c(rep.int(40.75, nrow(dest_df))),
long = c(rep.int(-73.99,nrow(dest_df)))
)
我这样做的原因是因为addPolylines 功能会按顺序连接所有坐标。解决此问题以创建您描述的图像的方法是从起点开始,然后到达目的地点,然后返回起点,然后到达下一个目的地点。为了创建数据框来执行此操作,我们必须通过这样放置在行中来交错两个数据框:
起点
- 目的地点 1
- 初始点
- 目的地点 2
-等等...
我要做的是为两个数据框创建一个键。对于原始数据帧,我将从 1 开始,然后递增 2(例如 1 3 5 7)。对于目标数据帧,我将从 2 开始并递增 2(例如 2、4、6、8)。然后我将使用 UNION all 组合这 2 个数据帧。然后我将按我的顺序排序,使每隔一行成为起点。我将为此使用 sqldf,因为我对此很满意。可能有更有效的方法。
orig_df$sequence <- c(sequence = seq(1, length.out = nrow(orig_df), by=2))
dest_df$sequence <- c(sequence = seq(2, length.out = nrow(orig_df), by=2))
library("sqldf")
q <- "
SELECT * FROM orig_df
UNION ALL
SELECT * FROM dest_df
ORDER BY sequence
"
poly_df <- sqldf(q)
新数据框看起来像这样
Notice how the origin locations are interwoven between the destination
最后,您可以制作地图了:
library("leaflet")
leaflet() %>%
addTiles() %>%
addPolylines(
data = poly_df,
lng = ~lon,
lat = ~lat,
weight = 3,
opacity = 3
)
And finally it should look like this
我希望这对将来希望做类似事情的人有所帮助
根据这些行的用途,另一个不错的选择是 gcIntermediate()。它根据地球的曲率输出一个 CURVED SpatialLines 对象。虽然不太适合指示。 SpatialLines class 对象与 Leaflet 配合得很好。请参阅 以获取出色示例。我发布了一个修改后的表格,它以 Paul Reiners 的数据框开头。
library(leaflet)
library(geosphere)
mydf <- data.frame(InitialLat = c(62.469722,48.0975), # initial df
InitialLong = c(6.187194, 16.3108),
NewLat = c(51.4749, 51.4882),
NewLong = c(-0.221619, -0.302621))
p1 <- as.matrix(mydf[,c(2,1)]) # it's important to list lng before lat here
p2 <- as.matrix(mydf[,c(4,3)]) # and here
gcIntermediate(p1, p2,
n=100,
addStartEnd=TRUE,
sp=TRUE) %>%
leaflet() %>%
addTiles() %>%
addPolylines()
认为这就是您想要的:
install.packages("leaflet")
library(leaflet)
mydf <- data.frame(Observation = c("A", "B","C","D","E"),
InitialLat = c(62.469722,48.0975,36.84,50.834194,50.834194),
InitialLong = c(6.187194, 16.3108,-2.435278,4.298361,4.298361),
NewLat = c(51.4749, 51.4882,50.861822,54.9756,54.9756),
NewLong = c(-0.221619, -0.302621,-0.083278,-1.62179,-1.62179),
stringsAsFactors = FALSE)
mydf
Observation InitialLat InitialLong NewLat NewLong
1 A 62.46972 6.187194 51.47490 -0.221619
2 B 48.09750 16.310800 51.48820 -0.302621
3 C 36.84000 -2.435278 50.86182 -0.083278
4 D 50.83419 4.298361 54.97560 -1.621790
5 E 50.83419 4.298361 54.97560 -1.621790
m<-leaflet(data=mydf)%>%addTiles
for (i in 1:nrow(mydf))
m<-m%>%addPolylines(lat=c(mydf[i,]$InitialLat,mydf[i,]$NewLat),lng=c(mydf[i,]$InitialLong,mydf[i,]$NewLong))
它显示:
Network Connection using Leaflet
我正在尝试使用 R 中的 Leaflet 包绘制放大器并连接标记,给出下面 table 中的纬度和经度信息。
| Observation | InitialLat | InitialLong | NewLat | NewLong | |-------------|------------|-------------|-----------|-----------| | A | 62.469722 | 6.187194 | 51.4749 | -0.221619 | | B | 48.0975 | 16.3108 | 51.4882 | -0.302621 | | C | 36.84 | -2.435278 | 50.861822 | -0.083278 | | D | 50.834194 | 4.298361 | 54.9756 | -1.62179 | | E | 50.834194 | 4.298361 | 54.9756 | -1.62179 | | F | 50.834194 | 4.298361 | 51.4882 | -0.302621 | | G | 47.460427 | -0.530804 | 51.44 | -2.62021 | | H | 51.5549 | -0.108436 | 53.4281 | -1.36172 | | I | 51.5549 | -0.108436 | 52.9399 | -1.13258 | | J | 51.5549 | -0.108436 | 51.889839 | -0.193608 | | | 51.5549 | -0.108436 | 52.0544 | 1.14554 |
我想从 InitialLat
和 InitialLong
列中的坐标给定的起点到 NewLat
和 NewLong
给定的终点画线列。
这是我当前的 R 代码,它只在地图上绘制标记。
library(leaflet) map3 = leaflet(data) %>% addTiles() map3 %>% addMarkers(~InitialLong,~InitialLat, popup=~Observation)
Leaflet 可以使用addPolylines
函数添加行。这样做的问题是它假设每条线都已连接 - 您将把它们全部连接起来。
解决此问题的最佳方法 (AFAIK) 是使用循环:
library(leaflet)
map3 = leaflet(data) %>% addTiles()
map3 <- map3 %>% addMarkers(~InitialLong,~InitialLat, popup=~Observation)
for(i in 1:nrow(data)){
map3 <- addPolylines(map3, lat = as.numeric(data[i, c(2, 4)]),
lng = as.numeric(data[i, c(3, 5)]))
}
map3
编辑:使用 Kyle Walker 的 points_to_line function 还有一种更简单的方法(请参阅最底部的代码粘贴副本)。
首先对数据进行整形,使起点和终点在同一列中:
library(tidyr)
library(dplyr)
z <- gather(dta, measure, val, -Observation) %>% group_by(Observation) %>%
do(data.frame( lat=c(.[["val"]][.[["measure"]]=="InitialLat"],
.[["val"]][.[["measure"]]=="NewLat"]),
long = c(.[["val"]][.[["measure"]]=="InitialLong"],
.[["val"]][.[["measure"]]=="NewLong"])))
然后调用points_to_line
z <- as.data.frame(z)
y <- points_to_line(z, "long", "lat", "Observation")
现在剧情:
map3 = leaflet(data) %>% addTiles()
map3 %>% addMarkers(~InitialLong, ~InitialLat, popup = ~Observation) %>%
addPolylines(data = y)
Kyle Walker points_to_line 的来源:
library(sp)
library(maptools)
points_to_line <- function(data, long, lat, id_field = NULL, sort_field = NULL) {
# Convert to SpatialPointsDataFrame
coordinates(data) <- c(long, lat)
# If there is a sort field...
if (!is.null(sort_field)) {
if (!is.null(id_field)) {
data <- data[order(data[[id_field]], data[[sort_field]]), ]
} else {
data <- data[order(data[[sort_field]]), ]
}
}
# If there is only one path...
if (is.null(id_field)) {
lines <- SpatialLines(list(Lines(list(Line(data)), "id")))
return(lines)
# Now, if we have multiple lines...
} else if (!is.null(id_field)) {
# Split into a list by ID field
paths <- sp::split(data, data[[id_field]])
sp_lines <- SpatialLines(list(Lines(list(Line(paths[[1]])), "line1")))
# I like for loops, what can I say...
for (p in 2:length(paths)) {
id <- paste0("line", as.character(p))
l <- SpatialLines(list(Lines(list(Line(paths[[p]])), id)))
sp_lines <- spRbind(sp_lines, l)
}
return(sp_lines)
}
}
这是使用 leaflet
包的替代方法。为了演示,我只是在你的数据中取了两个数据点。
mydf <- data.frame(Observation = c("A", "B"),
InitialLat = c(62.469722,48.0975),
InitialLong = c(6.187194, 16.3108),
NewLat = c(51.4749, 51.4882),
NewLong = c(-0.221619, -0.302621),
stringsAsFactors = FALSE)
我更改了 mydf
的格式并为传单创建了一个新的数据框。您可以通过多种方式重塑数据。
mydf2 <- data.frame(group = c("A", "B"),
lat = c(mydf$InitialLat, mydf$NewLat),
long = c(mydf$InitialLong, mydf$NewLong))
# group lat long
#1 A 62.46972 6.187194
#2 B 48.09750 16.310800
#3 A 51.47490 -0.221619
#4 B 51.48820 -0.302621
library(leaflet)
library(magrittr)
leaflet()%>%
addTiles() %>%
addPolylines(data = mydf2, lng = ~long, lat = ~lat, group = ~group)
我对得到的交互式地图进行了裁剪。请看下面的地图。尽管此图像中两条线相连,但它们是分开的。如果你 运行 代码并放大,你会看到这两行是分开的。
我知道一年前有人问过这个问题,但我也有同样的问题,并在传单中找到了解决方法。
您首先必须调整数据框,因为 addPolyline 只是连接序列中的所有坐标。出于演示目的,我将制作一个包含 4 个独立结束位置的数据框。
dest_df <- data.frame (lat = c(41.82, 46.88, 41.48, 39.14),
lon = c(-88.32, -124.10, -88.33, -114.90)
)
接下来,我将创建一个中心位置与目标位置大小相同(本例中为 4)的数据框。我很快就会解释为什么要这样做
orig_df <- data.frame (lat = c(rep.int(40.75, nrow(dest_df))),
long = c(rep.int(-73.99,nrow(dest_df)))
)
我这样做的原因是因为addPolylines 功能会按顺序连接所有坐标。解决此问题以创建您描述的图像的方法是从起点开始,然后到达目的地点,然后返回起点,然后到达下一个目的地点。为了创建数据框来执行此操作,我们必须通过这样放置在行中来交错两个数据框:
起点 - 目的地点 1 - 初始点 - 目的地点 2 -等等...
我要做的是为两个数据框创建一个键。对于原始数据帧,我将从 1 开始,然后递增 2(例如 1 3 5 7)。对于目标数据帧,我将从 2 开始并递增 2(例如 2、4、6、8)。然后我将使用 UNION all 组合这 2 个数据帧。然后我将按我的顺序排序,使每隔一行成为起点。我将为此使用 sqldf,因为我对此很满意。可能有更有效的方法。
orig_df$sequence <- c(sequence = seq(1, length.out = nrow(orig_df), by=2))
dest_df$sequence <- c(sequence = seq(2, length.out = nrow(orig_df), by=2))
library("sqldf")
q <- "
SELECT * FROM orig_df
UNION ALL
SELECT * FROM dest_df
ORDER BY sequence
"
poly_df <- sqldf(q)
新数据框看起来像这样 Notice how the origin locations are interwoven between the destination
最后,您可以制作地图了:
library("leaflet")
leaflet() %>%
addTiles() %>%
addPolylines(
data = poly_df,
lng = ~lon,
lat = ~lat,
weight = 3,
opacity = 3
)
And finally it should look like this 我希望这对将来希望做类似事情的人有所帮助
根据这些行的用途,另一个不错的选择是 gcIntermediate()。它根据地球的曲率输出一个 CURVED SpatialLines 对象。虽然不太适合指示。 SpatialLines class 对象与 Leaflet 配合得很好。请参阅
library(leaflet)
library(geosphere)
mydf <- data.frame(InitialLat = c(62.469722,48.0975), # initial df
InitialLong = c(6.187194, 16.3108),
NewLat = c(51.4749, 51.4882),
NewLong = c(-0.221619, -0.302621))
p1 <- as.matrix(mydf[,c(2,1)]) # it's important to list lng before lat here
p2 <- as.matrix(mydf[,c(4,3)]) # and here
gcIntermediate(p1, p2,
n=100,
addStartEnd=TRUE,
sp=TRUE) %>%
leaflet() %>%
addTiles() %>%
addPolylines()
认为这就是您想要的:
install.packages("leaflet")
library(leaflet)
mydf <- data.frame(Observation = c("A", "B","C","D","E"),
InitialLat = c(62.469722,48.0975,36.84,50.834194,50.834194),
InitialLong = c(6.187194, 16.3108,-2.435278,4.298361,4.298361),
NewLat = c(51.4749, 51.4882,50.861822,54.9756,54.9756),
NewLong = c(-0.221619, -0.302621,-0.083278,-1.62179,-1.62179),
stringsAsFactors = FALSE)
mydf
Observation InitialLat InitialLong NewLat NewLong
1 A 62.46972 6.187194 51.47490 -0.221619
2 B 48.09750 16.310800 51.48820 -0.302621
3 C 36.84000 -2.435278 50.86182 -0.083278
4 D 50.83419 4.298361 54.97560 -1.621790
5 E 50.83419 4.298361 54.97560 -1.621790
m<-leaflet(data=mydf)%>%addTiles
for (i in 1:nrow(mydf))
m<-m%>%addPolylines(lat=c(mydf[i,]$InitialLat,mydf[i,]$NewLat),lng=c(mydf[i,]$InitialLong,mydf[i,]$NewLong))
它显示: Network Connection using Leaflet