I am quite new to shiny, and I am facing a difficulty. I want to have a map with interactive circles. When clicked, these circles will allow me to make a query to a SQL database to get the corresponding data and so make plots.
I don't manage to get the circles info into a variable, although I am able to print it to the shiny ui.
Here is the example code:
library(shiny)
library(leaflet)
ui <- fluidPage(
leafletOutput("mymap"),
verbatimTextOutput("marker")
)
server <- function(input, output, session) {
output$mymap <- renderLeaflet({
leaflet(data = mapStates, options = leafletOptions(minZoom = 3, maxZoom = 18)) %>%
addTiles() %>%
addProviderTiles(providers$Stamen.TonerLite,
options = providerTileOptions(noWrap = TRUE))%>%
addCircleMarkers(data = data.frame(lat = 51, lng = 13,STANAME = "somewhere",STAID = "1" ), lng = ~lng, lat = ~lat,radius = 1, color = "red", fill = "red", popup = ~STANAME,layerId = ~STAID)
})
# here the circle info
output$marker <- renderPrint(input$mymap_marker_click)
}
shinyApp(ui, server)
but I don't manage to get the id of the marker into a variable in the server function. I tried:
input$mymap_marker_click$id
But it tells me that I need a reactive context. If I do:
renderPrint(input$mymap_marker_click)$id
Error : object of type 'closure' is not subsettable
I can't use the output in the server side, but I need this variable in the server side to do the query and the plots.
I should I proceed ?
Thank you for your help.
In Shiny you need to create an observer to "listen" for the click event (or any event/change to input) and perform a certain response.
Removing the map tiles, bc I don't know where mapStates comes from but the idea is identical.
library(shiny)
library(leaflet)
ui <- fluidPage(
leafletOutput("mymap"),
verbatimTextOutput("marker")
)
server <- function(input, output, session) {
output$mymap <- renderLeaflet({
leaflet(options = leafletOptions(minZoom = 3, maxZoom = 18)) %>%
addCircleMarkers(data = data.frame(lat = 51, lng = 13,STANAME = "somewhere",STAID = "1" ), lng = ~lng, lat = ~lat,radius = 1, color = "red", fill = "red", popup = ~STANAME,layerId = ~STAID)
})
# needs to be in a observer to "listen" for events
observeEvent(input$mymap_marker_click, {
output$marker <- renderPrint(input$mymap_marker_click$id)
})
}
shinyApp(ui, server)
Live demo
Related
I'm using addFlows() to add some flow data to a leaflet map in Shiny.
What I need it to do is emit the layerId when the appropriate line is clicked, so that I can display some information to the user in a sidebar. How can I trigger a click event?
I know that with polylines or polygons I can use observeEvent(input$map_shape_click, {}), but I'm not sure of the addFlows variant of this. I can't use addPolylines() instead because I need the arrow heads as representative of direction.
Reproducible code (with non-working click event):
library(shiny)
library(leaflet)
library(leaflet.minicharts)
library(tidyverse)
dat <- data.frame(
Line_no = c("line1", "line2"),
Origin_lat = c(40.15212, 40.65027),
Origin_lng = c(-74.79037, -74.91990),
Dest_lat = c(40.78749, 40.78749),
Dest_lng = c(-73.96188, -73.96188),
flow = c(237, 84)
)
ui <- fluidPage(
leafletOutput("map", height=800)
)
server <- function(input, output, session) {
output$map <- renderLeaflet({
leaflet() %>%
addProviderTiles(provider = providers$Esri.WorldImagery) %>%
setView(lat = 40.39650, lng = -74.39541, zoom = 9)
})
observe({
leafletProxy("map") %>%
addFlows(
layerId = dat$Line_no,
lng0 = dat$Origin_lng,
lat0 = dat$Origin_lat,
lng1 = dat$Dest_lng,
lat1 = dat$Dest_lat,
flow = dat$flow
)
})
observeEvent(input$map_shape_click, {
glimpse("Clicked!")
})
}
shinyApp(ui, server)
I have a map which has a series of lines with associated values, which is rendered based on a reactive dataframe, filtered by a sliderInput.
When a line is clicked, the map view is updated with new lng, lat and zoom values, based on that line. What I would like is that the view does not reset when the slider is updated. I understand that it's resetting to the values in the initial setView() because the map is rerendering when the slider is changed, but I'm unsure how I can prevent this behaviour.
In short, when a user clicks on the line, I want it to stay at that lng/lat/zoom even as the slider changes. How can I accomplish this?
Below is a simplified reproducible example, with only one line:
library(shiny)
library(leaflet)
library(tidyverse)
library(RColorBrewer)
# Example data frame
line1 <- data.frame(
lng = rep(c(13.35011, 13.21514), 4),
lat = rep(c(52.51449, 52.48042), 4),
id = rep("10351A", 8),
period = rep(c(1, 2, 3, 4), each = 2),
value = rep(c(1200, 2300, 3140, 1111), each = 2)
)
ui <- fluidPage(
sidebarPanel(
sliderInput(
inputId = "period_picker",
label = "Period",
min = 1,
max = 4,
value = 1
),
uiOutput("clicked_info")
),
mainPanel(
leafletOutput("map")
)
)
server <- function(input, output) {
# Reactive dataframe based on period_picker
dat <- reactive({
filtered <- line1 %>%
filter(period == input$period_picker)
return(filtered)
})
# Render map
output$map <- renderLeaflet({
# Create color palette based on reactive frame
pal <- colorNumeric(palette = "Purples", domain = c(0, max(line1$value)))
# Render leaflet map
leaflet(data = dat()) %>%
addTiles() %>%
setView(lng = 13.38049, lat = 52.51873, zoom = 13) %>%
addPolylines(
lng = ~lng,
lat = ~lat,
layerId = ~id,
color = ~pal(dat()$value),
opacity = 1
)
})
# Zoom in and readjust view if shape matching id is clicked - this is the
# lng/lat/zoom value I want to keep when the sliderInput is changed
observeEvent(input$map_shape_click, {
x <- input$map_shape_click
if(x$id == "10351A") {
leafletProxy(
mapId = "map",
) %>%
flyTo(
lng = 13.282625,
lat = 52.497455,
zoom = 12
)
}
# Render dataset in the UI
output$clicked_info <- renderUI({
div(
tags$span("Line ID:", dat()$id[1]),
br(),
tags$span("Period:", dat()$period[1]),
br(),
tags$span("Value:", dat()$value[1])
)
})
})
}
shinyApp(ui = ui, server = server)
You need to put the addPolylines not in the map rendering, but in another observeEvent with leafletProxy. Replace your output$map block of code by the following lines :
# Render map
output$map <- renderLeaflet({
leaflet() %>%
addTiles() %>%
setView(lng = 13.38049, lat = 52.51873, zoom = 13)
})
observeEvent(dat(), {
req(dat())
pal <- colorNumeric(palette = "Purples", domain = c(0, max(line1$value)))
leafletProxy("map") %>%
addPolylines(
data = dat(),
lng = ~lng,
lat = ~lat,
layerId = ~id,
color = ~pal(dat()$value),
opacity = 1
)
})
I am trying to plot the word cloud of sub-categories of that state in popup window when user clicks on that state in map.
ui <- bootstrapPage(
leafletOutput("mymap", height = 300)
)
server <- function(input, output, session){
output$mymap <- renderLeaflet({
leaflet(Sales) %>%
addTiles() %>%
addCircles(lng = ~longitude, lat = ~latitude,
popup= popupGraph(p),
weight = 3,
radius = ~Sales,
color=~cof(newdata$Category), stroke = TRUE, fillOpacity = 0.8)) )
})
shinyApp(ui = ui, server = server)
Here is my leaflet code, I have used it in r shiny. Can anyone please suggest how i render wordcloud on popup when user clicks on a state on map? I don't know how write that function 'p' for word-cloud in popupGraph(p) but i want to pass it as an argument like this, where p is word-cloud
I have a leaflet map and I want the option of switching from the values of A being mapped to the values of B. Every example I can find says to use shiny and leaflet and all of these examples include something along the lines of:
ui <- fluidPage(
selectInput(inputId = "Data",
label = "Data",
choices = c("A","B"),
leafletProxy(outputId = "map") #or leafletOutput
))
but I keep getting the error that
leafletProxy (or leafletOutput)does not exist
. How do I solve this? My leaflet is created with :
mypal <- colorNumeric(palette = "viridis", domain = d$A)
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
setView(lat = 39.8283, lng = -98.5795, zoom = 4) %>%
addPolygons(data =
USA, stroke = TRUE, color='black', opacity=1, weight=.5, smoothFactor = 0.2, fillOpacity = 1,
fillColor = ~mypal(d$A),
popup = paste('<b>',d$state, "</b><br>A:", d$A) %>%
addLegend(position = "bottomleft", pal = mypal, values = d$A,
title = "A",
opacity = 1)
It seems from your example that your shiny has no server function, so it is not going to work.
Please, find attached a mock shiny you can start building on:
library(shiny)
library(leaflet)
ui <- fluidPage(
selectInput(inputId = "Data",
label = "Data",
choices = c("A", "B")),
leafletOutput("map")
)
server <- server <- function(input, output, session) {
output$map <- renderLeaflet({
if((input$Data) == "A"){
point = c(42.6525, -73.757222)
}
if((input$Data) == "B"){
point = c(39.283333, -76.616667)
}
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
addMarkers(lat = point[1], lng = point[2])
})
It will show "Albany" when you select "A" and Baltimore when you select "B"
Basically:
ui is kind of the "interface", what it is going to be shown:
selectInput: you can choose A or B here
leafletOutput: will show the leaflet map
server will do the "hard job" of creating the map and computing actions when you use selecInput:
output$map means that we want to render the leafletOuput (that is why it is called map, as in leafletOutput("map")
Then, according to the input selected (A or B)
if((input$Data) == "A"){
point = c(42.6525, -73.757222)
}
if((input$Data) == "B"){
point = c(39.283333, -76.616667)
}
We assign coordinates of Albany or Baltimore to point.
Finally, we build the map:
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
addMarkers(lat = point[1], lng = point[2])
PLEASE, take into account that this is a mock shiny, it is far from perfect, it is only illustrative.
Best!
I am very new to shiny, and I have a question.
I have a simple dataset with observations (Number_Total) of species (Species), in a certain location (X,Y).
I would like to generate a map, that enables you to select the species in a dropdown menu. Shiny then shows you were the species occurs on the map.
I got pretty far (for my experience), but selecting species in the menu does not do anything...
ui <- (fluidPage(titlePanel("Species Checker"),
sidebarLayout(
sidebarPanel(
selectizeInput('species', 'Choose species',
choices = df$Species, multiple = TRUE)
),
mainPanel(
leafletOutput("CountryMap",
width = 1000, height = 500))
)
))
The server side
server <- function(input, output, session){
output$CountryMap <- renderLeaflet({
leaflet() %>% addTiles() %>%
setView(lng = 10, lat = 40, zoom = 5) %>%
addCircles(lng = df$Y, lat = df$X, weight = 10,
radius =sqrt(df$Number_Total)*15000, popup = df$Species)
})
observeEvent(input$species, {
if(input$species != "")
{
leafletProxy("CountryMap") %>% clearShapes()
index = which(df$Species == input$species)
leafletProxy("CountryMap")%>% addCircles(lng = df$X[index],
lat = df$Y[index],
weight = 1,
radius =sqrt(df$Number_Total[index])*30, popup = df$Species[index])
}
})
}
And finally plot it
shinyApp(ui = ui, server = server)
I know my code is probably messy, but again, I blaim my experience =)
I did not manage to get an example dataset in here right away, so here it comes as picture
This is the result of the above code (with slightly different data)
enter image description here
Here's what you need. I think you are skilled enough to understand this but comment if you have any questions.
server <- function(input, output, session) {
# map_data <- reactive({
# req(input$species)
# df[df$Species %in% input$species, ]
# })
output$CountryMap <- renderLeaflet({
leaflet() %>% addTiles() %>%
setView(lng = 10, lat = 40, zoom = 5)
})
map_proxy <- leafletProxy("CountryMap")
observe({
md <- df[df$Species %in% input$species, ]
map_proxy %>%
addCircles(lng = md$Y, lat = md$X, weight = 10,
radius = sqrt(md$Number_Total)*15000, popup = md$Species)
})
}