【问题标题】:How Do I connect two coordinates with a line using Leaflet in R如何使用 R 中的 Leaflet 将两个坐标与一条线连接起来
【发布时间】:2024-01-14 06:11:02
【问题描述】:

我正在尝试使用 R 中的 Leaflet 包来绘制放大器并连接下表中给出的纬度和经度信息的标记。

|观察 |初始纬度 |初始长 |新纬度 |新龙 | |-------------|------------|-------------|-------- ---|-----------| |一个 | 62.469722 | 6.187194 | 51.4749 | -0.221619 | |乙| 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 | |克| 47.460427 | -0.530804 | 51.44 | -2.62021 | | H | 51.5549 | -0.108436 | 53.4281 | -1.36172 | |我 | 51.5549 | -0.108436 | 52.9399 | -1.13258 | | Ĵ | 51.5549 | -0.108436 | 51.889839 | -0.193608 | | | 51.5549 | -0.108436 | 52.0544 | 1.14554 |

我想从InitialLatInitialLong 列中的坐标给定的初始点到NewLatNewLong 列给定的终点画线。

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

图书馆(传单) map3 = 传单(数据)%>% addTiles() map3 %>% addMarkers(~InitialLong,~InitialLat, popup=~Observation)

【问题讨论】:

    标签: r leaflet r-leaflet


    【解决方案1】:

    这是使用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)
    

    我修剪了我得到的交互式地图。请看下面的地图。尽管在此图像中两条线相连,但它们是分开的。如果你运行代码并放大,你会看到这两行是分开的。

    【讨论】:

    • 我想这曾经可以工作,但现在真的不行了。即使使用 ~group,leaflet 也会连接所有折线(在“放大此地图”时也是如此)。
    【解决方案2】:

    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(请参阅最底部的代码粘贴副本)。

    先reshape数据,让开始和结束在同一列:

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

    【讨论】:

      【解决方案3】:

      认为这就是你想要的:

      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

      【讨论】:

        【解决方案4】:

        根据行的用途,另一个不错的选择是 gcIntermediate()。它根据地球的曲率输出一个 CURVED SpatialLines 对象。虽然不是很好的方向。 SpatialLines 类对象与 Leaflet 配合得非常好。请参阅here 以获得一个很好的例子。我发布了一个修改后的表格,它以 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()
        

        【讨论】:

          【解决方案5】:

          我知道这是在一年前提出的,但我也有同样的问题,并且在传单中想出了如何做到这一点。

          您首先必须调整您的数据框,因为 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)
          

          新的数据框如下所示 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 我希望这可以帮助任何希望在未来做类似事情的人

          【讨论】:

          • 很棒的大卫谢谢你! addPolylines() 中的一个小错误。它应该是 lng = ~long 而不是 lon。
          最近更新 更多