[英]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.