I am struggling to draw multiple polygons in a Shiny app - based on leaflet package.
Here is a non-app output that I wish for:
data <- list(
beam1 = data.frame(lat = c(-115,-125, -125, -115),
lon = c(32, 32, 45,45)),
beam2 = data.frame(lat = c(-100, -111, -111, -100),
lon = c(42, 42, 50,50))
)
dataTemp <- do.call(rbind, lapply(data, function(x) rbind(x, NA)))
library(leaflet)
m = leaflet() %>% addTiles()
m %>%
addPolygons(
dataTemp[,"lat"],
dataTemp[,"lon"],
color = c('red', 'green'), weight = 3
)
However, creating a Shiny app out of it is proving to be difficult - the polygons get plotted and then disappear one by one once a new polygon is plotted. Here is the code I am using. You need to click on 'Draw' to plot polygons Notice how: 1 - red polygon disappears when green is drawn (after 3 seconds) 2 - the polygons are triangles here, while in the above code they are rectangles. 3 - if you look at code in server.R below, I actually had to flip 'lat' and 'lon' columns to get even remotely correct picture.
ui.R:
library(shiny)
library(leaflet)
shinyUI(navbarPage("Beams", id="nav",
tabPanel("Interactive map",
div(class="outer",
leafletMap("map", "100%", 650,
options = list(center = c(37.45, -93.85), zoom = 4)),
actionButton("drawPoints", "Draw")
)
)
))
server.R:
library(shiny)
library(leaflet)
data <- list(
beam1 = data.frame(lat = c(-115,-125, -125, -115),
lon = c(32, 32, 45,45)),
beam2 = data.frame(lat = c(-100, -111, -111, -100),
lon = c(42, 42, 50,50))
)
# server activity
shinyServer(function(input, output, session) {
map <- createLeafletMap(session, "map")
observe({
if(input$drawPoints == 0) {
return(NULL)
} else {
map$clearShapes()
for (i in seq_along(data)) {
map$addPolygon(
data[[i]][,"lon"], # - notice, i had to change lat and lon
data[[i]][,"lat"],
layerId=c("1"),
list( fillOpacity=0.4),
list(color = c('red','green')[i])
)
Sys.sleep(3) # - this is to see first (red) polygon
}
}
})
})
Any ideas would be appreciated!
I've updated your code to use leaflet proxies, which is a cleaner way to update existing maps, and is the currently maintained method for doing this in ongoing updates to the leaflet
package (as far as I know). I switched your "lat" and "lon" in the data.frame to make them correct. I also added the origin point again at the end of your coordinates to complete the shape -- that's why you had triangles and not rectangles. Lastly, I changed the layerId
for the polygons to i
to make them different -- that's why they were erasing each other.
I assumed that you want the shapes to be hardcoded, but there are ways to open up the polygon plot selection (or even drawing) to the user. Interesting note: in solving this, learned about the deferUntilFlush
param in leafletProxy
-- without this set to FALSE
, both shapes plot only after Sys.sleep
is done counting.
ui.R
library(shiny)
library(leaflet)
shinyUI(navbarPage("Beams", id="nav",
tabPanel("Interactive map",
div(class="outer",
leafletOutput("map", "100%", 650),
actionButton("drawPoints", "Draw")
)
)
))
server.R
library(shiny)
library(leaflet)
data <- list(
beam1 = data.frame(lon = c(-115,-125, -125, -115, -115),
lat = c(32, 32, 45, 45, 32)),
beam2 = data.frame(lon = c(-100, -111, -111, -100, -100),
lat = c(42, 42, 50, 50, 42))
)
shinyServer(function(input, output, session) {
map <- leaflet() %>% addTiles() %>% setView(-93.85, 37.45, zoom = 4)
output$map <- renderLeaflet(map)
proxy <- leafletProxy("map", deferUntilFlush = FALSE)
observeEvent(input$drawPoints, {
proxy %>% clearShapes()
for (i in seq_along(data)) {
proxy %>% addPolygons(
data[[i]][,"lon"],
data[[i]][,"lat"],
layerId=i,
opacity=0.4,
color = c('red','green')[i]
)
Sys.sleep(2) # - this is to see first (red) polygon
}
})
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With