如何在R中使用Leaflet连接两个坐标点?

31

我正在尝试使用R中的Leaflet包,在给定以下表格中的纬度和经度信息的情况下绘制一个走向并连接标记。

    | 观测点   | 初始纬度  | 初始经度    | 新纬度     | 新经度     |
    |-------------|------------|-------------|-----------|-----------|
    | 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   |

我想从由InitialLatInitialLong列中的坐标给出的起始点,连线到由NewLatNewLong列中的结束点。

这是我的当前R代码,它只在地图上绘制标记。

    调用leaflet库
    创建地图map3并添加瓷贴图
    在map3上添加标记,标记信息为Observation,位置由InitialLong和InitialLat决定
5个回答

29

这里是使用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的格式,并创建了一个新的数据框用于leaflet。你可以以各种方式重新塑造你的数据。

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)

我裁剪了我得到的交互式地图。请参见下面的地图。尽管这个图片中有两条线连接在一起,但它们是分开的。如果您运行代码并放大,您将看到这两条线是分开的。

输入图像描述


3
我想象这个曾经有效,但现在并不是了。即使使用~group,leaflet仍然会连接所有的折线(甚至在“放大此地图”时也是如此)。 - Remko Duursma

19

Leaflet可以使用addPolylines函数添加线条。问题在于它假定每条线都是相连的 - 你会得到所有线都连接在一起的结果。

修复这个问题最好的方法(据我所知)是使用循环:

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函数 (请参见底部复制的代码)。

首先,重新塑造数据,使起点和终点位于同一列中:

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)
  }
}

4

认为这是您想要的:

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))

它显示为: 使用Leaflet的网络连接


3

根据线条的用途,另一个很好的选择是gcIntermediate()。它基于地球的曲率输出一个CURVED SpatialLines对象。但不适合用于方向。SpatialLines类对象与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()

2

我知道这个问题是一年前提出的,但我也有同样的问题,并且找到了在leaflet中如何解决它。

首先,您需要调整数据框,因为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组合这两个数据框架。然后按照我的序列排序,使每隔一行成为起点。我将使用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)

新的数据框如下所示:请注意起始位置和目的地之间的交织 最后,您可以制作您的地图:
library("leaflet")
leaflet() %>%
  addTiles() %>%

  addPolylines(
    data = poly_df,
    lng = ~lon, 
    lat = ~lat,
    weight = 3,
    opacity = 3
  ) 

最终效果应该是这样的,希望这能帮助那些未来想要做类似事情的人。


太棒了 David,谢谢!在 addPolylines() 中有一个小错误。应该是 lng = ~long 而不是 lon。 - Yeshyyy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接