Highlight marker from user input in leaflet - R Shiny - r

I'm trying to highlight points in my map based on the user input slider. If the point falls within a certain date range, change the color, and if it doesn't, default it to black.
#server
shinyServer(function(input, output,session) {
output$myMap <- renderLeaflet({
leaflet() %>%
addTiles()%>%
addCircles(data=df,
# ~Longitude,
# ~Latitude,
group = "myMarkers",
label = ~htmlEscape(date))
})
observeEvent(input$selectVariable, {
mydat$col_format<- ifelse(mydat$Date >= input$falltime[1] & mydat$Date <= input$falltime [2],'blue',
ifelse(mydat$Date >= input$springtime[1] & mydat$Date <= input$springtime [2], 'black',
ifelse (mydat$Date, 'yellow')) )
leafletProxy("myMap") %>%
clearGroup("myMarkers") %>%
addCircles(data = df[df$AnimlID == input$selectVariable, ],
#~ mydat$Longitd ,
#~ mydat$Latitud,
group = "myMarkers",
col = mydat$col_format,
label = ~htmlEscape(date)
)
})
})
#ui shinyUI(dashboardPage(#skin = "black",
dashboardHeader(title = "Mapping Test", titleWidth = 350
),
dashboardSidebar(width = 350,
selectInput("selectVariable", label = h4("Select an D:"),
choices = unique(df$id)),
sliderInput("falltime","NSD Fall Slider:",
min = min, max = max, value = c(min, max)),
verbatimTextOutput("dateText"),
sliderInput("springtime","NSD Spring Slider:",
min = min, max = max, value = c(min, max)),
actionButton("submit", ("Submit"))),
dashboardBody(fluidPage(
box( plotOutput("plotlraj")),
box( leafletOutput("myMap")),
box(DT::dataTableOutput("Table"),
)
),
)
))
With the above code I don't get any errors but the map is really slow to load and the points are always blue no matter what the date range the slider input is set to.
I've also tried adding this reactive block but again, all the points are blue even when I change the slider date range
colorpal<- reactive({
if(mydat$Date >= input$falltime[1] & mydat$Date <= input$falltime [2]){
mydat[,'seasonColor']<-'#626262'
}
if(mydat$Date >= input$springtime[1] & mydat$Date <= input$springtime [2]){
mydat[,'seasonColor']<-'#BAF218
'
}

Using quakes so others can replicate.
In the filtered_df reactive function, manipulate your data.frame as you prefer. I prefer using dplyr, but am showing base R.
req() are used to ensure those inputs have values.
There is no need to have addCircles() in the leaflet instantiation. The observe reactive will take care of displaying the circles once filtered_df() is ready and every time it is changed after that.
For brevity, showing just the server code.
output$myMap <- renderLeaflet({
leaflet() %>%
addTiles()
})
filtered_df <- reactive({
req(input$depth_slider,
input$mag_slider)
filtered_df <- quakes[quakes$depth <= input$depth_slider,]
filtered_df[filtered_df$mag <= input$mag_slider, 'Strength'] <- 'Weak'
filtered_df[filtered_df$mag > input$mag_slider, 'Strength'] <- 'Strong'
return(filtered_df)
})
observe({
filtered_df <- filtered_df()
pal <- colorFactor(c('Green', 'Red'), domain = filtered_df$Strength)
leafletProxy('myMap') %>%
clearGroup('myMarkers') %>%
clearControls() %>%
addCircles(
data = filtered_df,
lng = ~long,
lat = ~lat,
group = 'myMarkers',
color = ~pal(Strength)
) %>%
addLegend(
pal = pal,
values = filtered_df$Strength
)
})

Related

Creating Shiny App of a Map using Reactive Date Input in Leaflet

I have created a shiny app where the user can select from a date range to show crimes that occurred in Chicago by Longitude and Latitude.
The problem I am having is to make the dateRangeInput reactive within the leafletOutput. I have looked up a LOT of different option and found that these work the best but the problems I am having are:
Map generates with markers but is not reactive (when commenting out the clearMarkers())
Map generates without markers so I cant even tell if its reactive or not (when using clearMarkers())
I have tried both approaches of using observe() and observeEvent().
Please help... what am I missing.
Data can be found at https://data.cityofchicago.org/Public-Safety/Crimes-2001-to-Present/ijzp-q8t2
**** Interested in date range 01/01/20 to 09/30/20.... the file referenced in a data
crimes.df <- read.csv("Crimes_2020.csv", stringsAsFactors = TRUE)
#Seprating Date and Time into multiple columns
dup_crimes.df$datetime <- as.POSIXct(dup_crimes.df$Date, format = "%m/%d/%Y %H:%M")
dup2_crimes.df <- transform(dup_crimes.df, time = format(dup_crimes.df$datetime, "%T"),
date = format(dup_crimes.df$datetime, "%m/%d/%Y"))
class(dup2_crimes.df$date)
dup2_crimes.df$Month <- as.numeric(format(as.Date(dup2_crimes.df$date), format = "%y"))
dup2_crimes.df$Month.Name <- month.abb[dup2_crimes.df$Month]
#Filter out locations NOT related to Chicago
dup3_crimes.df <- filter(dup2_crimes.df, dup2_crimes.df$Latitude >= 41)
unique(dup3_crimes.df$Primary.Type)
ui <- fluidPage(
titlePanel("2020 Crimes in Chicago"),
tabsetPanel(type = "tabs",
tabPanel("Map of Location of crimes by date",
dateRangeInput(inputId = "date",
label = "Date",
start = '2020-02-25',
end = '2020-07-04',
min = '2020-01-01',
max = '2020-09-30'
),
leafletOutput("Map"))
)
)
server <- function(input,output){
datefileter1 <- reactive({
dup3_crimes.df[
dup3_crimes.df$date >= input$date[1] &
dup3_crimes.df$date <= input$date[2],]
})
#https://www.youtube.com/watch?v=G5BDubIyQZY
#Static Map
output$Map <- renderLeaflet({
leaflet(data = dup3_crimes.df) %>%
addTiles() %>%
addCircleMarkers(lng = ~Longitude, lat = ~Latitude)
})
#Put Dynamic Content
# observe(leafletProxy("Map", data = datefileter1()) %>%
# clearMarkers() %>%
# addCircleMarkers(lng = ~Longitude, lat = ~Latitude)
# )
observeEvent(input$date,
leafletProxy("Map", data = datefileter1()) %>%
clearMarkers() %>%
addCircleMarkers(lng = ~Longitude, lat = ~Latitude)
)
# observe({
#
# leafletProxy("Map", data = datefilter()) %>%
# clearShapes() %>%
# addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
# fillColor = ~pal(mag), fillOpacity = 0.7, popup = ~paste(mag)
# )
# })
#
}
#Run Shiny App
shinyApp(ui = ui , server =server)
---->> With clearMarkers()
---->> Without clearMarkers() - shows all the locations and NOT reactive (intentionally selected 7/4/20)
Try this, it should work. You can include the reactive df in a simple leaflet call:
ui <- fluidPage(
titlePanel("2020 Crimes in Chicago"),
tabsetPanel(type = "tabs",
tabPanel("Map of Location of crimes by date",
dateRangeInput(inputId = "date",
label = "Date",
start = '2020-02-25',
end = '2020-07-04',
min = '2020-01-01',
max = '2020-09-30'
),
leafletOutput("Map"),
tableOutput("tab"))
)
)
server <- function(input,output){
datefileter1 <- reactive({
dup3_crimes.df[
dup3_crimes.df$date >= input$date[1] &
dup3_crimes.df$date <= input$date[2],]
})
output$tab <- renderTable(datefileter1())
output$Map <- renderLeaflet({
leaflet(data = datefileter1()) %>%
addTiles() %>%
addCircleMarkers(lng = ~Longitude, lat = ~Latitude)
})
}
#Run Shiny App
shinyApp(ui = ui , server =server)

How to addPolyline of max distance, based on attributes filter from dropdown list using haversine calculation in shiny leaflet map?

I am trying to show maximum distance covered from swimming events for each person in leaflet map with "shinyapp" based on filtering a "Name" and a "SwimType".
Here is my code:
library(shiny)
library(dplyr)
library(shinydashboard)
library(leaflet)
library(osrm)
swimd <- read.csv('swim.csv', stringsAsFactors = F)
ui <- shinyUI(dashboardPage(
dashboardHeader(title = "Training"),
dashboardSidebar("A swim session"),
dashboardBody(
fluidPage(
box("",
leafletOutput("abc", height = 430),
width = 8, height = 450, background = 'black'),
box("",
selectInput('st', label = 'Swim Type:', choices = unique(swimd$SwimStyle)),
selectInput('pn', label = 'Name:', choices = unique(swimd$Name)),
width = 4, height = 450, background = 'black')
)
)
))
server <- shinyServer(function(input, output, session){
a <- reactive({
swimd %>%
select(Name, SwimStyle, Longitude, Latitude) %>%
filter( SwimStyle %in% input$st)
})
observe({
updateSelectInput(session,
inputId='pn',
choices = c("< select Name>"="", a()$Name ))
})
output$abc <- renderLeaflet({
leaflet() %>%
addProviderTiles(providers$OpenStreetMap) %>%
setView(lng=0, lat=0, zoom = 2)
})
observe({
selection <- a() %>% filter(Name %in% input$pn)
selection$res <- distHaversine(selection$Longitude, selection$Latitude, r=6378137)
#to find the difference between two sequence values
selection[ , list(Name, SwimStyle, Longitude, Latitude,res,Diff=diff(res))]
b <- selection %>% arrange(desc(Diff)) %>% top_n(2)
leafletProxy("abc") %>% clearMarkers() %>% addMarkers(lat = b$Latitude, lng = b$Longitude) %>%
addPolylines(route$lon,route$lat,
label = paste(round(route_summary[1]), 'Minutes - ', round(route_summary[2]/1000), 'Meters'),
labelOptions = labelOptions(noHide = TRUE))
flyTo(lat = b$Latitude, lng = b$Longitude, zoom = 2)
})
})
shinyApp(ui,server)
In this app when the name and swim type filtered the maximum distance of swimming should be shown in map with 'polyline'. For an example a person finished 10 mins of swimming. For each 1 min of swimming we record the distance. I would like to show addPolyline for maximum distance covered in a min for each person by selecting a name from the dropdown list as created in this app.
Can someone help me on this use-case?
Thank you.

How to change circle marker color in leaflet when I select a row in the table in Shiny?

So I want to change the CircleMarker colour in Leaflet map when I select a row in the table. I didn't get any errors but nothing happens. I don't know how to create and apply the reactive function properly in my Shiny app.
I tried to create a reactive function when a row is selected in the table and apply it to a separate leaflet proxy and leaflet map.
library(shiny)
library(DT)
library(dplyr)
library(leaflet)
library(leaflet.extras)
# Define UI
ui <- fluidPage(
# Application title
titlePanel("Quakes Test"),
# Sidebar with numericInput for quakes depth range
sidebarLayout(
sidebarPanel(
numericInput(inputId = "min_depth", label = "Mininum depth", value = min(quakes$depth), min = min(quakes$depth), max = max(quakes$depth)),
numericInput(inputId = "max_depth", label = "Maximum depth", value = max(quakes$depth), min = min(quakes$depth), max = max(quakes$depth))
),
# Show a map
mainPanel(
fluidRow(
leafletOutput("mymap_occ", width = "98%", height = 500))
)
),
fluidRow(DT::dataTableOutput(outputId = "prop_table"))
)
server <- function(input, output) {
#filter terrains
depth_final <- reactive({
obj <- quakes
if (input$min_depth != "All") {
obj <- quakes %>%
filter(depth >= as.numeric(input$min_depth)) %>%
filter(depth <= as.numeric(input$max_depth))
}
})
#row selected in table
table2_bat <- reactive({
data <- depth_final()
data <- data[input$prop_table, ]
})
output$prop_table <- renderDT({
datatable(depth_final(), extensions = 'Buttons', rownames = FALSE, escape = FALSE, selection = 'single')
})
#row selected map
observe({
leafletProxy("mymap_occ", data = table2_bat()) %>%
clearGroup(group = "FOO") %>%
addCircleMarkers(lng = ~long, lat = ~lat,
color = "white", fillColor = "yellow", opacity = 1, fillOpacity = 1,
radius = 5, weight = 20, group = "FOO")
})
#map
observe({
leafletProxy("mymap_occ", data = depth_final()) %>%
clearGroup(group = "FOO_2") %>%
addCircleMarkers(lng = ~long, lat = ~lat,
color = "white", fillColor = "red", opacity = 1, fillOpacity = 0.75,
radius = 5, weight = 2, group = "FOO_2")
})
output$mymap_occ <- renderLeaflet({
leaflet(table2_bat()) %>%
fitBounds(~min(long), ~min(lat), ~max(long), ~max(lat)) %>%
addProviderTiles(providers$Esri.WorldImagery, group = "Vue satellite") %>%
addProviderTiles(providers$Stamen.TonerLabels, group = "Vue satellite")
})
output$mymap_occ <- renderLeaflet({
leaflet(depth_final()) %>%
fitBounds(~min(long), ~min(lat), ~max(long), ~max(lat)) %>%
addProviderTiles(providers$Esri.WorldImagery, group = "Vue satellite") %>%
addProviderTiles(providers$Stamen.TonerLabels, group = "Vue satellite")
})
}
shinyApp(ui = ui, server = server)
First. You have to use eventReactive instead of reactive to trigger an action based on an event, i.e. when the user selects a row. Second. To get the index of the selected row you have to use input$prop_table_rows_selected (see here) instead of input$prop_table. input$prop_table does not exist, i.e. it returns NULL. Hence, to make your app work try this:
#row selected in table
table2_bat <- eventReactive(input$prop_table_rows_selected, {
data <- depth_final()
data <- data[input$prop_table_rows_selected, ]
})

I cannot get slider inputs to modify a map in shiny

I cannot get the map to react with the sliders. THe data was from https://www.kaggle.com/nasa/meteorite-landings/data#
when i move the sliders the map "refreshes" like it resets itself as if something were going to change but all of the data points show up on the graph. any help would be appreciated.
library(shiny)
library(dplyr)
library(leaflet)
library(ggplot2)
Meteor <- read.csv()
#to take all NA values out
ReMeteor <- na.omit(Meteor) #from now on using ReMeteor instead of Meteor
ui <- shinyUI(fluidPage(
titlePanel("Meteorite Landings"),
# Sidebar with a sliders and checkbox
sidebarLayout( position = "right",
sidebarPanel(
#1st slider year range
sliderInput("years","The year the meteorite fell, or the year it was found ",
min = min(ReMeteor$year),
max = max(ReMeteor$year),
step = 1,value = c(1399,2013),
animate = TRUE),
#2nd slider mass range
sliderInput("masss","The mass of the meteorite, in grams",
min = min(ReMeteor$mass),
max = max(ReMeteor$mass),
step = 100,value = c(.010,60000000),
animate = TRUE),
#checkbox
selectInput("fall",
"Was meteorite seen falling or found?",
choices = sort(unique(ReMeteor$fall))),
),
mainPanel( leafletOutput("my_leaf",height = 650, width = 605),textOutput("text1"),textOutput("text2")
))))
server <- shinyServer(function(input, output, session) {
#i think this block of four was letting it refresh, although no changes
filtered <- reactive({
ReMeteor[ReMeteor$year >= input$years[1] & ReMeteor$year <= input$years[2],]
ReMeteor[ReMeteor$mass >= input$masss[1] & ReMeteor$mass <= input$masss[2],]
})
#need last checkbox
# filter(ReMeteor >= input$year[1] &
# ReMeteor <= input$year[2]) %>%
# filter(ReMeteor >= input$mass[1] &
# ReMeteor <= input$mass[2])%>%
# filter(ReMeteor = sort(unique(ReMeteor$fall)))
# fitBounds()#here it is !!! https://rstudio.github.io/leaflet/shiny.html search : fitbounds --- this too https://rstudio.github.io/leaflet/markers.html
output$my_leaf <- renderLeaflet({
leaflet(data = filtered()) %>%
addMiniMap(zoomLevelOffset = -4) %>%
addProviderTiles("Esri.NatGeoWorldMap")
})
#fitBounds(ReMeteor, ReMeteor$reclong,ReMeteor$reclat,ReMeteor$reclong,ReMeteor$reclat)
observe({
# year_ <-input$year
# mass_ <-input$mass
# fall_ <-input$fall
#
leafletProxy("my_leaf", data = filtered()) %>%
clearShapes() %>%
clearMarkers() %>%
clearPopups() %>%
addMarkers(lat = ReMeteor$reclat,
lng = ReMeteor$reclong,
clusterOptions = markerClusterOptions(),
popup = as.character(ReMeteor$name,ReMeteor$recclass))
})
output$text1 <- renderText({
paste("You have chosen a range from the year", input$years[1], "to", input$years[2])
})
output$text2 <- renderText({
paste("You have chosen a range of mass from", input$masss[1], "to", input$masss[2], "grams")
})
})
shinyApp(ui, server)
The issue here is that although you correctly used the reactive value filtered() in your leafletProxy call, you use the non-reactive version of ReMeteor in your addMarkers call.
observe({
leafletProxy("my_leaf", data = filtered()) %>%
clearShapes() %>%
clearMarkers() %>%
clearPopups() %>%
addMarkers(lat = filtered()$reclat,
lng = filtered()$reclong,
clusterOptions = markerClusterOptions(),
popup = as.character(filtered()$name,filtered()$recclass))
})

Clear leaflet markers in shiny app with slider bar

I'm trying to build a shiny app that will only plot points on rows that have a value within the range of a slider bar. If I increase the range of the slider bar, points will be added, but points are never removed when I decrease the range of the slider bar. Below is a reproducible example of my problem.If you increase the slider bar to full range, 3 points will show up on the map. If you then decrease the range enough it will zoom in on one point, but if you zoom out you will see that there are still 3 points being plotted on a map. I thought the clearShapes or clearMarkers function in leaflet would remove these points, but it's not working. Any suggestions?
library(shiny)
library(leaflet)
library(tidyverse)
ui <- fluidPage(
titlePanel("Test"),
sidebarLayout(
sidebarPanel(
radioButtons("choice","Group:",choices = c(1,2), selected = 1),
uiOutput("value"),
verbatimTextOutput("Click_text")
),
mainPanel(
leafletOutput("Map")
)
)
)
server <- function(input, output) {
df <- data.frame(lat = c(42.34,43.65,45.26,48.63,47.65,47.52),
lng = c(-96.43,-97.45,-98.56,-92.35,-94.56,-95.62),
id = c(32,45,65,76,34,12),
grp = c(1,1,1,2,2,2),
val = c(1.75,2.12,3.2,3.32,4.76,4.85))
subsetData1 <- reactive({
df %>% filter(grp == input$choice)
})
output$value <- renderUI({
sliderInput("value",label = h3("value"),
min = min(subsetData1()$val,na.rm = TRUE),
max = max(subsetData1()$val,na.rm=TRUE),
value = c(quantile(subsetData1()$val,.25,na.rm = TRUE),quantile(subsetData1()$val,.75,na.rm=TRUE)))
})
subsetData <- reactive({
df2 <- subsetData1() %>% data.frame()
df2 %>% filter(val >= min(as.numeric(input$value)) & val <= max(as.numeric(input$value)))
})
output$Map <- renderLeaflet({
leaflet(height = 1000) %>%
addTiles() %>%
fitBounds(min(df$lng),min(df$lat),max(df$lng),max(df$lat))
})
observe({
leafletProxy("Map") %>%
clearMarkers() %>%
clearShapes() %>%
addCircleMarkers(data = subsetData(),
lng = ~lng,
lat = ~lat,
layerId = ~id,
radius = 8,
weight = 10) %>%
fitBounds(.,min(subsetData()$lng),min(subsetData()$lat),
max(subsetData()$lng),max(subsetData()$lat))
})
observe({
click<-input$Map_marker_click
if(is.null(click))
return()
text<-paste("Latitude ", click$lat, "Longtitude ", click$lng)
text2<-paste("You've selected point ", click$id)
output$Click_text<-renderText({
text2
})
})
}
# Run the application
shinyApp(ui = ui, server = server)
You can change your observe function where you clear markers to an observeEvent function.
observeEvent(input$value,{
leafletProxy("Map") %>%
clearMarkers() %>%
clearShapes() %>%
addCircleMarkers(data = subsetData(),
lng = ~lng,
lat = ~lat,
layerId = ~id,
radius = 8,
weight = 10) %>%
fitBounds(.,min(subsetData()$lng),min(subsetData()$lat),
max(subsetData()$lng),max(subsetData()$lat))
})
You also have both the uiOutput and sliderInput id's as the same (value). You should make sure every element has a unique id. Rename one of them to something unique.

Resources