簡體   English   中英

從R中的leaflet獲取邊界框

[英]Getting bounding box from leaflet in R

我正在使用 R、RStudio 和leaflet package 來可視化 map。

我想獲得 leaflet object 的邊界框的最小和最大經緯度。我認為這可以使用 Shiny 來完成(通過使用input$mapobj_bounds類的東西)但是有沒有一種非閃亮的方法這個。

m <- leaflet(width=500,height=400) %>% 
   addTiles() %>% 
   setView(lng = -0.106831, lat = 51.515328, zoom = 18) %>%
   addCircleMarkers(lng = -0.106831, lat = 51.515328)

我需要的是一個 function 來使用輸入參數m獲取邊界框。

這可以做到嗎?

此外,查看 object m時的參數值看起來不正確。

例如

> m$x$limits
$lat
[1] 51.51533 51.51533

$lng
[1] -0.106831 -0.106831

編輯

我認為 javascript function map.getBounds()在這里可能會有幫助...按照此處的建議( 獲取可見的邊界框 leaflet map? ),但不知道如何將其應用於我們的問題。 對此的任何幫助將不勝感激。

如果你稍微調整一下 Jeremys 的原始答案,你實際上可以在沒有 javascript 的情況下做到這一點:

可重現的例子:

library(magrittr)
library(leaflet)

m <- leaflet(width = 500,height = 400) %>% 
  addTiles() %>% 
  setView(lng = -0.106831, lat = 51.515328, zoom = 18) %>%
  addCircleMarkers(lng = -0.106831, lat = 51.515328)
m
getBox <- function(m){
  view <- m$x$setView
  lat <- view[[1]][1]
  lng <- view[[1]][2]
  zoom <- view[[2]]
  zoom_width <- 360 / 2^zoom
  lng_width <- m$width / 256 * zoom_width
  lat_height <- m$height / 256 * zoom_width
  return(c(lng - lng_width/2, lng + lng_width/2, lat - lat_height/2, lat + lat_height/2))
}
getBox(m)

閃亮的你可以簡單地使用: input$MAPID_bounds

可重現的例子:

library(shiny)
library(leaflet)
library(magrittr)

app <- shinyApp(

  ui = fluidPage(leafletOutput('myMap')),

  server = function(input, output) {

    output$myMap = renderLeaflet({
      leaflet() %>% 
        addTiles() %>% 
        setView(
          lng = 50, 
          lat = 10, 
          zoom = 17
        )
    })

    observeEvent(input$myMap_bounds, {
      print(input$myMap_bounds)
    })

  }
)

有關更多信息,請參見此處: https : //rstudio.github.io/leaflet/shiny.html

這是一個 javscript 版本(初始解決方法)。 對於更好的版本,請參見上文。

  leaflet() %>% addTiles()  %>% 
  setView(lng = -0.106831, lat = 51.515328, zoom = 18) %>%
  addEasyButton(easyButton(
    states = list(
      easyButtonState(
        stateName="unfrozen-markers",
        icon="ion-toggle",
        title="Get Bounding box",
        onClick = JS("
                     function(btn, map) {
                        alert(map.getBounds().getEast());
                        alert(map.getBounds().getWest());
                        alert(map.getBounds().getNorth());
                        alert(map.getBounds().getSouth());
                     }")
      )
    )
  )
)

感謝@BigDataScientist 的回答指出,寬度和高度是可用的!

只要您知道傳單小部件的尺寸,就可以計算邊界框。 Leafletjs.com/examples/zoom-levels

鑒於這是用leaflet(width=500,height=400) ,這將起作用。

if (is.null(m$width) | is.null(m$height)) {
    print("Leaflet width and height must be speciied")
} else {
       width <- m$width 
       height <- m$height 
       zoom <- m$x$setView[[2]]
       lng <- m$x$setView[[1]][2]
       lat <- m$x$setView[[1]][1]
       lng_width <- 360 * width / 2^(zoom + 8)
       lng_east <- lng - lng_width/2
       lng_west <- lng + lng_width/2
       lat_height <- 360 * height * cos(lat/180 * pi) / 2^(zoom + 8)
       lat_north <- lat + lat_height/2
       lat_south <- lat - lat_height/2
}

> lng_east
[1] -0.1081721
> lng_west
[1] -0.1054899
> lat_north
[1] 51.516
> lat_south
[1] 51.51466

與@BigDataScientist 相比,這給出了與map.getBounds相同的答案, map.getBounds 3 個小數位。

在此處輸入圖片說明

編輯我的回答基於參考傳單中的文檔。 這似乎是一種簡化。 我添加了cos(lat/180 * pi)項以提高准確性。 例如,這現在給出了 51.516 的北邊界,這與傳單的 51.51599707 僅相差 0.0000029。

我已經在幾個不同的緯度和縮放比例下對此進行了測試。 精度在較低的縮放級別下會降低。

這是一個老問題,但它最近 [2022 年 4 月 29 日] 幫助我找到了解決我所面臨問題的方法。 為了表示感謝,我將@TonioLiebrand@JeremyVoisey的方法組合成一個獨立的(四舍五入的)function,如下所示:

# Self-contained function to calculate 'Leaflet Map Widget' Bounding Box co-ordinates ...
"f.calc.leaflet.bounding.box.coords" <- function(objLeafletMap=NULL) {
  FUNC_ID_SHORT <- "fCLBBC"; FUNC_ID_FULL <- "f.calc.leaflet.bounding.box.coords";
  boundNorth_ <- NULL; boundWest_ <- NULL; boundSouth_ <- NULL; boundEast_ <- NULL;
  if (is.null(objLeafletMap) || is.null(objLeafletMap$width) || is.null(objLeafletMap$height)) {
    base::message(base::paste0(" --> ", FUNC_ID_SHORT, " - Line 4 ", "| LEAFLET MAP WIDTH & HEIGHT NOT SPECIFIED ( FUNC ID: '", FUNC_ID_FULL, "' )."))
    base::stop(base::paste0(" --> ", FUNC_ID_SHORT, " - Line 5 ", " | Function Execution Terminated [ reason: REQUIRED PARAMS are NULL ] !!"))
  } else {        
    # Extract Leaflet Map Widget 'x' property list values ( i.e. [center 'lat' & 
    # 'lon'], 'zoom' and 'options' widget property values )...
    view_ <- objLeafletMap$x$setView; zoom_ <- view_[[2]]; 
    lon_ <- view_[[1]][2]; lat_ <- view_[[1]][1];
    
    # Extract Leaflet Map Widget 'width' and 'height' values ...
    width_ <- objLeafletMap$width; height_ <- objLeafletMap$height;
    
    # Calculate Leaflet Map Widget peripheral extent in co-ordinate dimensions ...
    lon_width_ <- 360 * width_ / 2 ^ (zoom_ + 8);
    lat_height_ <- 360 * height_ * cos(lat_ / 180 * base::pi) / 2 ^ (zoom_ + 8);
    
    # Calculate Leaflet Map Widget peripheral extent ( i.e. Bounding Box ) in co-ordinate values ...
    boundEast_ <- lon_ + lon_width_ / 2; boundWest_ <- lon_ - lon_width_ / 2;
    boundNorth_ <- lat_ + lat_height_ / 2; boundSouth_ <- lat_ - lat_height_ / 2;
  }
  return(list(top=boundNorth_, right=boundEast_, bottom=boundSouth_, left=boundWest_, zoom=zoom_))
}

這對某些人來說可能有點矯枉過正,但對其他尋求快速 [時間關鍵] 解決方案的人來說也可能是一個福音(就像我所做的那樣)。 Simply copy & paste the function into your R script, and once the function is read into your R Session Memory extract your Leaflet Map Widget bounding co-ordinates as follows:

# Simply call the function from wherever you need in your R script ...
mapBounds <- f.calc.leaflet.bounding.box.coords(m);   # <- 'm' == Leaflet Map Widget (with 'width' and 'height' defined) !!


# ... and extract the results as follows:
mapBounds$top
> -5.83050217387398

mapBounds$right
> 38.25046875 

mapBounds$bottom
> -40.209497826126 

mapBounds$left
> -9.21046875

我還將zoom值添加為 output(因為在 function中計算它似乎很浪費,但不將它 [結果] 返回給 function 調用)。 所以現在您可以通過調用輕松輕松地獲取zoom值...

mapBounds$zoom
> 5

... after every map zoom change - 如果您真的、真的需要這樣做。

最后,我同意@JeremyVoisey的觀點,這種方法的結果存在准確性問題 - 但這段代碼片段足以解決我遇到的問題(而且我有點時間緊迫)......所以我沒有當時考慮解決准確性問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM