I am working on a shiny application where a user clicks on a map (leaflet map) and based on that click, certain actions are being performed, like draw a circle of radius one km around the clicked point. This functionality works fine. However I want to add the mouse coordinates by using the addMouseCoordinates() function from the mapview package. I have used this in the past with no problems. However with the following code, I am unable to see the coordinates.
leafletProxy('incidentmap') %>%
addCircles(lng=clng, lat=clat, group='circles',
weight=1, radius=input$radius, color='black', fillColor='green',
fillOpacity=0.2, opacity=1)%>%
addCircles(lng=filtered$Long,lat=filtered$Lat)%>%
addMouseCoordinates(style = "basic")
Now if I click on the map, the application crashes with the following error:
> Warning: Error in : inherits(map, "leaflet") is not TRUE Stack trace
> (innermost first):
> 75: stopifnot
> 74: addMouseCoordinates
> 73: function_list[[k]]
> 72: withVisible
> 71: freduce
> 70: _fseq
> 69: eval
> 68: eval
> 67: withVisible
> 66: %>%
> 65: observeEventHandler [/Users/dhirajkhanna/Desktop/CallAnalysis/CDR/server.R#39]
> 1: runApp ERROR: [on_request_read] connection reset by peer
Has it got something to do with leafletProxy() ?
Help would be appreciated.
Here's a reproducible example:
library(shiny)
library(mapview)
library(leaflet)
ui <- fluidPage(
leafletOutput("incidentmap")
)
server <- function(input,output,session){
output$incidentmap <- renderLeaflet({
leaflet() %>%
setView(lng = 77.9568288, lat = 27.1696145, zoom=11) %>%
addTiles(options = providerTileOptions(noWrap = TRUE))
})
## Observe mouse clicks and add circles
observeEvent(input$incidentmap_click, {
click <- input$incidentmap_click
clat <- click$lat
clng <- click$lng
leafletProxy('incidentmap') %>%
addCircles(lng=clng, lat=clat, group='circles',
weight=1, radius=1000, color='black', fillColor='green',
fillOpacity=0.2, opacity=1)%>%
addMouseCoordinates(style = "basic")
})
}
shinyApp(ui,server)
It works when you move the addMouseCoordinates call to where the map is set up (where you define output$incidentmap)
library(shiny)
library(mapview)
library(leaflet)
ui <- fluidPage(
leafletOutput("incidentmap")
)
server <- function(input,output,session){
output$incidentmap <- renderLeaflet({
leaflet() %>%
setView(lng = 77.9568288, lat = 27.1696145, zoom=11) %>%
addTiles(options = providerTileOptions(noWrap = TRUE)) %>%
addMouseCoordinates(style = "basic")
})
## Observe mouse clicks and add circles
observeEvent(input$incidentmap_click, {
click <- input$incidentmap_click
clat <- click$lat
clng <- click$lng
leafletProxy('incidentmap') %>%
addCircles(lng=clng, lat=clat, group='circles',
weight=1, radius=1000, color='black', fillColor='green',
fillOpacity=0.2, opacity=1)
})
}
shinyApp(ui,server)
Here is an attempt to fill your need. You can easily improve uppon it ..
library(leaflet)
library(mapview)
library(shiny)
ui <- fluidPage(
leafletOutput("map1")
)
server <- function(input, output, session) {
output$map1 <- renderLeaflet({
leaflet() %>% addTiles()
})
observeEvent(input$map1_click, {
click <- input$map1_click
clat <- click$lat
clng <- click$lng
content <- paste(sep = "<br/>",
"<b>",clat, "</b>",
"<b>", clng, "</b>" )
leafletProxy('map1') %>%
addCircles(lng=clng, lat=clat, group='circles',
weight=1, radius=100, color='black', fillColor='orange',
fillOpacity=0.5, opacity=1) %>%
addPopups(lng = clng, lat = clat, content)
})
}
shinyApp(ui, server)
Related
I am trying to improve the usability of my app.R code in R Shiny which is getting very long.
Essentially, I'd like to create a module (infras.R) to contain a large number of observeEvent functions that are linked to checkboxInputs.
I understand I need to source the module in app.R, wrap the observeEvent in a function, include namespaces (ns) for input IDs in the observeEvent function and insert a callModule for the function. I've also wrapped the callModule in an ObserveEvent so that its functionality persists and does not trigger only once after starting the webapp.
The following error is output on running app.R but I'm not sure how to resolve:
Warning: Error in proxy: could not find function "proxy"
81: eval
80: eval
79: %>%
78: module [infras.R#153]
73: callModule
72: observeEventHandler
1: runApp
Thanks for your assistance with this as I've found it challenging to find literature on how to do this.
Key snippets from my R scripts.
infras.R (updated):
icons_pow <- awesomeIcons(
iconColor = 'white',
markerColor = 'green',
text = "m"
)
mod <- function(input, output, session, pow_id, prox){
observeEvent(pow_id(),{
if(pow_id() != 0){
pow_id <- readOGR("../geospatial_files/ind", layer = "plants")
pow_iddf <- as.data.frame(pow_id)
prox %>%
addAwesomeMarkers(lng=pow_iddf$coords.x1, lat=pow_iddf$coords.x2, group = "pow_idg", icon=icons_pow,
label = paste(pow_iddf$Name,pow_iddf$Power_type,sep = ", "))
}
else {prox %>% clearGroup("pow_idg") %>% removeControl(layerId="pow_idc")
}
}
)
}
app.R (updated):
...
source("infras.R")
...
server <- function(input, output, session) {
...
proxy <- leafletProxy("map")
callModule(mod, "mod", reactive(input$pow_id), proxy)
})
...
}
You need to wrap your input object into a reactive and use that as an input argument to your module. The other input argument is your leaflet proxy. Inside the module, you can use observe to change your proxy, which is then instantly updated:
library(shiny)
library(leaflet)
library(RColorBrewer)
# The module containing the observer. Input is the reactive handle of legend input and the proxy
mod <- function(input, output, session, legend, prox){
observe({
prox %>% clearControls()
if (legend()) {
prox %>% addLegend(position = "bottomright",
pal = colorNumeric("Blues", quakes$mag), values = ~mag
)
}
})
}
ui <- bootstrapPage(
checkboxInput("legend", "Show legend", TRUE),
tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
leafletOutput("map", width = "100%", height = "100%")
)
server <- function(input, output, session) {
output$map <- renderLeaflet({
pal <- colorNumeric("Blues", quakes$mag)
leaflet(quakes) %>% addTiles() %>%
addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
fillColor = ~pal(mag), fillOpacity = 0.7, popup = ~paste(mag)) %>%
fitBounds(~min(long), ~min(lat), ~max(long), ~max(lat))
})
# This is the handle for map
proxy <- leafletProxy("map", data = quakes)
callModule(mod, "mod", reactive(input$legend), proxy)
}
shinyApp(ui, server)
I am building a shiny app where I would like to get the coordinates of a polygon from a leaflet map. Specifically, the shape is drawn using the Drawtoolbar from the leaflet.extras package. A simple example app is below.
My question is, how can I get the coordinates from the shape drawn on the map by the user? Thank you in advance.
library(shiny)
library(leaflet)
library(leaflet.extras)
# Define UI
ui <- fluidPage(
leafletOutput("mymap",height=800)
)
# Define server logic
server <- function(input, output) {
output$mymap <- renderLeaflet(
leaflet() %>%
addProviderTiles("Esri.OceanBasemap",group = "Ocean Basemap") %>%
setView(lng = -166, lat = 58.0, zoom = 5) %>%
addDrawToolbar(
targetGroup='draw',
editOptions = editToolbarOptions(selectedPathOptions = selectedPathOptions())) %>%
addLayersControl(overlayGroups = c('draw'), options =
layersControlOptions(collapsed=FALSE))
)
observeEvent(input$mymap_shape_click,{
print(input$mymap_shape_click)
})
observeEvent(input$mymap_click,{
print(input$mymap_click)
})
}
# Run the application
shinyApp(ui = ui, server = server)
You need to observe the _draw_new_feature function
library(leaflet.extras)
# Define UI
ui <- fluidPage(
leafletOutput("mymap",height=800)
)
# Define server logic
server <- function(input, output) {
output$mymap <- renderLeaflet(
leaflet() %>%
addProviderTiles("Esri.OceanBasemap",group = "Ocean Basemap") %>%
setView(lng = -166, lat = 58.0, zoom = 5) %>%
addDrawToolbar(
targetGroup='draw',
editOptions = editToolbarOptions(selectedPathOptions = selectedPathOptions())) %>%
addLayersControl(overlayGroups = c('draw'), options =
layersControlOptions(collapsed=FALSE))
)
observeEvent(input$mymap_draw_new_feature,{
feature <- input$mymap_draw_new_feature
print(feature)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Inserting popups in addCirclemarkers caused lengthy calculation time for data of thousands of points to be mapped. I am assuming all popups have to be calculated before showing the map.
I searched online for a way to only add/create the popup if a point/circle/marker is clicked. Currently, I am at the below code. If you run this code, you will see that the popup is created, but the string to extract from the data is not shown. What am I doing wrong?
library(shiny)
library(leaflet)
library(htmltools)
library(sp)
data <- data.frame(
"name"=c("Place 1","Place 2","Place 3"),
"lat"=c(50,51,52),
"lng"=c(3,4,5), stringsAsFactors = FALSE)
ui = fluidPage(
fluidRow(column(8, offset = 2, leafletOutput("map", width = "100%", height = "650px")))
)
server = function(input, output, session) {
pts <- reactive({
pts <- data
coordinates(pts) <- ~lng+lat
pts
})
output$map <- renderLeaflet({
leaflet(pts()) %>%
addTiles(group="OSM") %>%
addCircleMarkers()
})
observeEvent(input$map_marker_click, {
leafletProxy("map") %>% clearPopups()
event <- input$map_marker_click
if (is.null(event))
return()
isolate({
pts2 <- pts()
sgh <- pts2[row.names(pts2) == event$id,]
# sgh <- pts2[pts2$name == event$id,]
content <- htmlEscape(paste("This place is",as.character(sgh$name)))
leafletProxy("map") %>% addPopups(event$lng, event$lat, content, layerId = event$id)
})
})
}
shinyApp(ui = ui, server = server, options = list(launch.browser=TRUE))
With you code event$id is NULL, so the sgh <- pts2[row.names(pts2) == event$id,] line return NULL as well.
You have to add the layerId to the CircleMarkers (and is not necessary to add it to the Popup.
This also let access it wothout needing to 'merge' it with the original data:
output$map <- renderLeaflet({
leaflet(pts()) %>%
addTiles(group="OSM") %>%
addCircleMarkers(layerId = ~name)
})
observeEvent(input$map_marker_click, {
leafletProxy("map") %>%
clearPopups()
event <- input$map_marker_click
if (is.null(event))
return()
isolate({
content <- htmlEscape(paste("This place is", event$id))
leafletProxy("map") %>%
addPopups(event$lng, event$lat, content)
})
})
Following is my shiny code. I want this app to allow user to click on the map and in response (i.e., Observe event) to the click, I want the map to show the marker.
library(shiny)
library(maps)
library(stringi)
library(ggmap)
library(leaflet)
ui <- shinyUI(bootstrapPage(
tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
leafletOutput("map", width = "100%", height = "100%")
))
server <- shinyServer(function(input, output, session) {
## Make your initial map
output$map <- renderLeaflet({
leaflet() %>%
setView(lng = -4, lat= 52.54, zoom = 7) %>%
addProviderTiles(providers$Stamen.TonerLite,
options = providerTileOptions(noWrap = TRUE))
})
## Observe mouse clicks and add marker
observeEvent(input$map_click, {
click <- input$map_click
clat <- click$lat
clng <- click$lng
text<- paste("Lattitude", click$lat, "Longtitude", click$lng)
proxy <- leafletProxy("map")
proxy %>% clearPopups() %>%
addPopups(click$lng, click$lat, text) %>%
addMarkers(lng=clng, lat=clat, popup = as.character(text), label = as.character(text))
})
})
runApp(shinyApp(ui, server), launch.browser = TRUE)
I get the following error.
Warning: Error in leafletProxy: could not find function "startsWith"
Stack trace (innermost first):
66: leafletProxy
65: observeEventHandler [#22]
1: runApp
Working code:
ui <- shinyUI(bootstrapPage(
leafletOutput("map")
))
server <- shinyServer(function(input, output, session) {
## Make your initial map
output$map <- renderLeaflet({
leaflet() %>%
setView(lng = -86.779633, lat = 33.543682, zoom = 11) %>%
addTiles(options = providerTileOptions(noWrap = TRUE))
})
## Observe mouse click
observeEvent(input$map_click, {
## Get the click info like had been doing
click <- input$map_click
clat <- click$lat
clng <- click$lng
address <- revgeocode(c(clng,clat))
## Add the marker to the map proxy
leafletProxy('map') %>% # use the proxy to save computation
addMarkers(lng=clng, lat=clat,
popup=address)
})
})
shinyApp(ui=ui, server=server)
I would like to enhance the code above by calculating a statistic within a 5000m buffer of the clicked address...everything I try does not work. Am I missing something?
ui <- shinyUI(bootstrapPage(
leafletOutput("map")
))
server <- shinyServer(function(input, output, session) {
## Make your initial map
output$map <- renderLeaflet({
leaflet() %>%
setView(lng = -86.779633, lat = 33.543682, zoom = 11) %>%
addTiles(options = providerTileOptions(noWrap = TRUE))
})
## Observe mouse clicks and add circles
observeEvent(input$map_click, {
## Get the click info like had been doing
click <- input$map_click
clat <- click$lat
clng <- click$lng
address <- revgeocode(c(clng,clat))
I want to create a SPDF of the lng and lat from the click:
coords<-c(clat, clng)
crs <- "+init=epsg:26930" #' this is E Alabama
x_spdf <- spTransform(coords, CRSobj = crs)
Here I want to create a 5000m buffer around the clicked point
b_dist <- 5*1000
buffer_spdf <- gBuffer(x_spdf, width=b_dist, byid=T)
buffer <- gBuffer(x_spdf, width=b_dist)
This is my SPDF of office addresses I have on my computer that I want to convert to CRS for E Alabama
dent_spdf <- spTransform(split_dentist, CRSobj = crs)
Identify # of offices within buffer
office_in_buffer <- split_office[!is.na(sp::over(split_office, buffer)),]
office_in_buffer <- spTransform(dent_in_office, CRS=crs)
Count # of offices in buffer
num_office <- nrow(office_in_buffer)
Calculate statistic based on # offices in buffer
expenditure <-office_in_buffer#data$variable/ (num_office + 1)
output$expenditure <- renderText(revenue) #' tell Shiny to display this number
leafletProxy('map') %>% # use the proxy to save computation
addMarkers(lng=clng, lat=clat,
popup=address)
})
})
shinyApp(ui=ui, server=server)