renderLeaflet: legend values are not updated - r

I have the following R codes within the shiny framework. Everything looks good, but the legend (Plese see this screenshot).
I want the legend to be updated on the basis of the users' selection of age group (60+, 65+, 85+), sex, or year. But it is not the case. That is, the legend's values remain unchanged, no matter what is selected from the left menu (Please see this screenshot). This makes the map useless if the 85+ is selected. Following is my entire codes.
I appreciate your help.
Nader
load("/Users/nadermehri/Desktop/map codes/nhmap.RData")
library(shiny)
library(leaflet)
ui <- fluidPage(
tabPanel(
"Interactive Maps",
tags$h5 (
)),
br(),
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "Age_Group_map",
label = "Select the Age Group:",
selected = "60+",
selectize = F,
multiple = F,
choices = sort(unique(nhmap$Age_Group))
),
radioButtons(
inputId = "sex_map",
label = strong("Select Sex:"),
selected = "Both Sexes",
choices = sort(unique(nhmap$Sex))
),
sliderInput(
inputId = "Year_map",
label = "Year",
min = 2010,
max = 2050,
value = 2010,
step = 10,
sep = "",
pre = "",
animate = animationOptions(
interval = 1000,
loop = F,
playButton = tags$button("Play", style =
"background-color: #B61E2E ; color:white; margin-top: 10px; border:solid"),
pauseButton = tags$button("Pause", style =
"background-color: #B61E2E !important; color:white; margin-top: 10px; border:solid")
),
round = T,
width = "150%",
ticks = T
)),
mainPanel("Interactive", leafletOutput("int_map", height=500))))
server <- function(input, output) {
mapdata_ <- reactive ({
nhmap$Per <- round(nhmap$Per, 1)
out_map <- nhmap %>%
filter (
Age_Group %in% input$Age_Group_map,
Sex %in% input$sex_map,
Year %in% input$Year_map)
return(out_map)
})
output$int_map <- renderLeaflet ({
leaflet (mapdata_(),
pal8 <- c("#FFFFE5", "#D9F0A3", "#78C679", "#006837") ,
pal <- colorBin(palette = pal8, domain = NULL, bins=quantile(nhmap$Per), na.color = "#808080", alpha = FALSE, reverse = F)) %>%
addProviderTiles("CartoDB.Positron") %>%
clearControls() %>%
clearShapes()%>%
addPolygons(fillColor = ~pal(Per),
stroke=T,
weight=1,
smoothFactor=0.2,
fillOpacity = 1,
color="black",
popup=~paste(NAME,"<br>",input$sex_map,
input$Age_Group_map,"=",Per,"%"),
highlightOptions = highlightOptions(color = "red",
weight = T,
bringToFront = T),
label=~NAME) %>%
addTiles() %>%
setView(-82.706838, 40.358615, zoom=7) %>%
addLegend(position = "bottomright",
values = ~Per,
pal = pal,
title = (paste("%",input$Age_Group_map, input$sex_map, "in", input$Year_map)) ,
labFormat = labelFormat(
))
})
}
shinyApp(ui = ui, server = server)

You have to define the bins in colorBin, at which you want to cut the data in the different color sections. Something like:
pal <- colorBin(palette = pal8, domain = NULL, bins=quantile(mapdata_()$Per),
na.color = "#808080", alpha = FALSE, reverse = F)
And you also have to remove bins= 4 from the addLegend call, as it will get the information from the color palette.
I created some random data for nhmap and it is working for me with this code:
library(shiny)
library(leaflet)
library(sf)
library(sp)
## Random Data #############
data(meuse, package = "sp")
nhmap <- st_as_sf(meuse, coords = c("x", "y"))
st_crs(nhmap) <- "+init=epsg:28992"
nhmap <- st_buffer(nhmap, 100)
n = length(nhmap$cadmium)
nhmap$Age_Group <- sample(c(15,19,25), size = n, T)
nhmap$Sex <- sample(c("m","f"), size = n, T)
nhmap$Per <- runif(n, 1, 150)
nhmap$NAME <- sample(c("a","b","c"), size = n, T)
nhmap$Age_Group <- sample(c(15,19,25), size = n, T)
nhmap$Year <- sample(c(2010,2020,2030, 2040, 2050), size = n, T)
nhmap <- st_transform(nhmap, 4326)
## UI ###########
ui <- {fluidPage(
tabPanel(
"Interactive Maps",
tags$h5 ()),
br(),
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "Age_Group_map",
label = "Select the Age Group:",
# selected = "60+",
selectize = F,
multiple = F,
choices = sort(unique(nhmap$Age_Group))
),
radioButtons(
inputId = "sex_map",
label = strong("Select Sex:"),
# selected = "Both Sexes",
choices = sort(unique(nhmap$Sex))
),
sliderInput(
inputId = "Year_map",
label = "Year",
min = 2010,
max = 2050,
value = 2010,
step = 10,
sep = "",
pre = "",
animate = animationOptions(
interval = 1000,
loop = F,
playButton = tags$button("Play", style =
"background-color: #B61E2E ; color:white; margin-top: 10px; border:solid"),
pauseButton = tags$button("Pause", style =
"background-color: #B61E2E !important; color:white; margin-top: 10px; border:solid")
),
round = T,
width = "150%",
ticks = T
)),
mainPanel("Interactive", leafletOutput("int_map", height=500)))
)}
## SERVER ###########
server <- function(input, output) {
mapdata_ <- reactive ({
nhmap$Per <- round(nhmap$Per, 1)
# nhmap
nhmap %>%
filter (
Age_Group %in% input$Age_Group_map,
Sex %in% input$sex_map,
Year %in% input$Year_map)
})
output$int_map <- renderLeaflet ({
req(mapdata_())
pal8 <- c("#FFFFE5", "#D9F0A3", "#78C679", "#006837")
# pal <- colorBin(palette = pal8, domain = NULL, bins=quantile(mapdata_()$Per),
pal <- colorBin(palette = pal8, domain = NULL, bins=quantile(nhmap$Per),
na.color = "#808080", alpha = FALSE, reverse = F)
leaflet(data = mapdata_()) %>%
# leaflet(data = nhmap) %>%
clearControls() %>%
clearShapes()%>%
addProviderTiles("CartoDB.Positron") %>%
addTiles() %>%
addPolygons(fillColor = ~pal(Per),
stroke=T,
weight=1,
smoothFactor=0.2,
fillOpacity = 1,
color="black",
label=~NAME,
popup=~paste(NAME,"<br>",input$sex_map,
input$Age_Group_map,"=",Per,"%"),
highlightOptions = highlightOptions(color = "red",
weight = T,
bringToFront = T)) %>%
# setView(-82.706838, 40.358615, zoom=7) %>%
addLegend(position = "bottomright",
values = ~Per,
title = (paste("%",input$Age_Group_map, input$sex_map, "in", input$Year_map)),
pal = pal
)
})
}
shinyApp(ui = ui, server = server)

Here is the answer. As I mentioned in my the last comment, the pal needs to be reactive:
mapdata_ <- reactive ({
nhmap$Per <- round(nhmap$Per, 1)
out_map <- nhmap %>%
filter (
Age_Group %in% input$Age_Group_map,
Sex %in% input$sex_map,
Year %in% input$Year_map)
return(out_map)
list(Per)
})
mapdata_1 <- reactive ({
nhmap$Per <- round(nhmap$Per, 1)
out_map_1 <- nhmap %>%
filter (
Age_Group %in% input$Age_Group_map
)
return(out_map_1)
list(Per)
})
output$int_map <- renderLeaflet ({
pal8 <- c("#FFFFE5", "#D9F0A3", "#78C679", "#006837")
pal <- colorBin(palette = pal8, domain =NULL, bins=quantile(mapdata_1()$Per), na.color = "#808080", alpha = FALSE, reverse = F)
leaflet (mapdata_()) %>%
addProviderTiles("CartoDB.Positron") %>%
clearControls() %>%
clearShapes()%>%
addPolygons(fillColor = ~pal(Per),
stroke=T,
weight=1,
smoothFactor=0.2,
fillOpacity = 1,
color="black",
popup=~paste(NAME,"<br>",input$sex_map,
input$Age_Group_map,"=",Per,"%"),
highlightOptions = highlightOptions(color = "red",
weight = T,
bringToFront = T),
label=~NAME) %>%
addTiles() %>%
setView(-82.706838, 40.358615, zoom=7) %>%
addLegend(position = "bottomright",
values = ~Per,
pal = pal,
title = (paste("%",input$Age_Group_map, input$sex_map, "in", input$Year_map)) ,
labFormat = labelFormat(
))
})

Related

How do I dynamically update a calculated value based on the number of input values in R Shiny?

I am trying to update the value in a plotly chart in R shiny whose calculated value depends on the number of inputs
library(shiny)
library(httr)
library(jsonlite)
library(dplyr)
library(plotly)
library(shinythemes)
library(flexdashboard)
library(shinydashboard)
setwd("X:/Work/Covid-19 Project/Shiny Dashboard")
rp_1 <- read.csv("Data/Risk Profile 1.csv")
rp_2 <- read.csv("Data/Risk Profile 2.csv")
gender <- c("Male","Female")
age <- c("Less than 20 years", "20 to 50 years","More than 50 years")
city <- c("Delhi","Chennai")
diabetes <- c("Have diabetes","Don't have diabetes")
hypertension <- c("Have hypertension","Don't have hypertension")
risk_level_est <- function(city, gender, age, db, ht){
p_inv <- as.numeric(rp_1 %>%
filter(City == city & Gender == gender) %>%
select(Prob))
p_adv <- as.numeric(rp_2 %>%
filter(Age == age & Diabetes == db & Hypertension == ht) %>%
summarise(Hosp + Death))
as.numeric(p_inv*p_adv*100)
}
sar_risk_level_est <- function(age, db, ht){
p_adv <- as.numeric(rp_2 %>%
filter(Age == age & Diabetes == db & Hypertension == ht) %>%
summarise(Hosp + Death))
as.numeric(0.2*p_adv*100)
}
about_page <- tabPanel(
title = "About",
titlePanel("About"),
"Created with R Shiny",
br(),
"2021 April"
)
main_page <- tabPanel(
title = "Estimator",
titlePanel(""),
sidebarLayout(
sidebarPanel(
title = "Inputs",
selectInput("gender", "Select your gender", gender),
selectInput("age", "Select your age", age),
selectInput("city", "Select your city", city),
selectInput("db", "Do you have diabetes", diabetes),
selectInput("ht", "Do you have hypertension", hypertension),
radioButtons("radio", "Do you want to include your household members",
choices = list("No" = 1,"Yes" = 2)),
conditionalPanel("input.radio == 2",
numericInput("members", label = "How many household members do you have?", value='1'),
uiOutput("member_input")
),
actionButton("risk","Calculate my risk profile")
),
mainPanel(
tabsetPanel(
tabPanel(
title = "Risk Profile",
plotlyOutput("risk_profile", height = 250, width = "75%"),
plotlyOutput("overall_risk_profile", height = 250, width = "75%")
)
)
)
)
)
ui <- navbarPage(
title = "Risk Estimator",
theme = shinytheme('united'),
main_page,
about_page
)
server <- function(input, output, session) {
output$member_input <- renderUI({
numMembers <- as.integer(input$members)
lapply(1:numMembers, function(i) {
list(tags$p(tags$u(h4(paste0("Member ", i)))),
selectInput(paste0("age", i), "Select their age", age, selected = NULL),
selectInput(paste0("db", i), "Do they have diabetes", diabetes, selected = NULL),
selectInput(paste0("ht", i), "Do they have hypertension", hypertension, selected = NULL))
})
})
risk_level <- eventReactive(input$risk, {
risk_level_est(input$city, input$gender, input$age, input$db, input$ht)
})
sar_risk_level <- eventReactive(input$risk,{
sar_risk <- 0
lapply(1:input$members, function(i){
sar_risk <- sar_risk + sar_risk_level_est(input[[paste0("age", i)]],input[[paste0("db", i)]],input[[paste0("ht", i)]])
})
as.numeric(sar_risk)
})
output$risk_profile <- renderPlotly({
fig <- plot_ly(
domain = list(x = c(0, 1), y = c(0, 1)),
value = risk_level(),
title = list(text = "Personal Risk Profile"),
type = "indicator",
mode = "gauge+number",
gauge = list(
axis = list(range = list(0, 15)),
bar = list(color = "gray"),
bgcolor = "white",
borderwidth = 2,
bordercolor = "gray",
steps = list(
list(range = c(0, 3.75), color = "darkgreen"),
list(range = c(3.75, 7.5), color = "chartreuse"),
list(range = c(7.5,11.25), color = "orange"),
list(range = c(11.25,15), color = "red")
)))
fig <- fig %>% layout(margin = list(l=30, r=30, t=80, b=30))
fig
})
output$overall_risk_profile <- renderPlotly({
fig <- plot_ly(
domain = list(x = c(0, 1), y = c(0, 1)),
value = risk_level() + sar_risk_level(),
title = list(text = "Overall Risk Profile"),
type = "indicator",
mode = "gauge+number",
gauge = list(
axis = list(range = list(0, 15+(25*input*members))),
bar = list(color = "gray"),
bgcolor = "white",
borderwidth = 2,
bordercolor = "gray",
steps = list(
list(range = c(0, 3.75), color = "darkgreen"),
list(range = c(3.75, 7.5), color = "chartreuse"),
list(range = c(7.5,11.25), color = "orange"),
list(range = c(11.25,15), color = "red")
)))
fig <- fig %>% layout(margin = list(l=30, r=30, t=80, b=30))
fig
})
}
shinyApp(ui, server)
While the risk_profile plot works fine, the overall_risk_profile plot throws the "non-numeric argument to binary operator" error. The sar_risk_level() value in overall_risk_profile is dependent on a calculation (sar_risk_level_est) which depends on the number of inputs. I want this value (sar_risk) to be initizialied to zero and updated everytime the action button is pressed.
Great looking app. I think it is just a typo. The code has 25*input*members instead of 25*input$members on line 151.

AddLegend based on reactive values in r leaflet

I'm trying to addlegend feature on my interactive map app based on user input such that when he selects a range of input the color mapping changes based on the conditions selected.
I tried to do this putting colorBin() inside reactive() function in this way:
colorpal <- reactive({
colorBin(palette = "plasma", domain = data_input_ordered()$totale, bins = 6)
})
and than using colorpal() inside renderLeaflet() in this way:
output$mymap <- renderLeaflet(
leaflet() %>%
addProviderTiles(providers$Stamen.Terrain) %>%
setView(lng = 9.768875, lat = 45.619111, zoom = 9) %>%
addPolygons(data = province_lonlat,
weight = 1,
color = "white",
fillOpacity = 0.8,
fillColor = colorpal(data_input_ordered()$totale),
highlight = highlightOptions(weight = 1,
color = "#666666",
fillOpacity = 0.5,
bringToFront = TRUE
),
label = lapply(labels(), HTML)
) %>%
addLegend(pal = colorpal,
values = data_input_ordered()$totale,
position = "topright",
labFormat = labelFormat(big.mark = ".")
)
)
The problem is the app is running but the map tab isn't showing anything but: "Error: argument is of length zero
Anyone has tips to fix my code making my map working properly?
Full code is here:
# APP
library(shiny)
library(shinydashboard)
library(leaflet)
library(rgdal)
library(dplyr)
library(DT)
province <- readOGR("../in/province.shp")
province_lonlat <- spTransform(province, CRS("+proj=longlat +datum=WGS84"))
crimini <- read.csv2("../in/crimini.csv")
### UI
ui <- dashboardPage(
skin = "blue",
dashboardHeader(title = "Crimini denunciati nelle province della Lombardia"),
dashboardSidebar(
sliderInput(
# nome per indicare i valori controllati dallo slider (si utilizza nel SERVER per riferirsi ai dati da controllare)
inputId = "date_range",
label = "Anno",
min = min(crimini$anno),
max = max(crimini$anno),
# valori iniziali dello slider
value = c(min(crimini$anno), max(crimini$anno)),
sep = ".",
step = 1
)
),
dashboardBody(
fluidRow(box(width = 12, leafletOutput(outputId = "mymap"))),
fluidRow(box(width = 12, dataTableOutput(outputId = "summary_table")))
)
)
### SERVER
server <- function(input, output) {
data_input <-
# inserisco una funzione REACTIVE che aggiorna il calcolo ogni volta che i parametri di input vengono modificati
reactive({
crimini %>%
# filtro i valori in base al massimo e al minimo selezionati con lo slider
filter(`anno` >= input$date_range[1]) %>%
filter(`anno` <= input$date_range[2]) %>%
group_by(`provincia`) %>%
summarize("totale" = sum(`n_crimini`),
"media annua" = round(sum(`n_crimini`) / (input$date_range[2] - input$date_range[1]), digits = 2)
)
})
data_input_ordered <- reactive({
data_input()[order(match(data_input()$provincia, province_lonlat$provincia)), ]
})
labels <- reactive({
paste("<p>", data_input_ordered()$provincia, "</p>",
"<p>", "totale crimini: ", data_input_ordered()$totale, "</p>",
"<p>", "media annua: ", round(data_input_ordered()$`media annua`, digits = 2), "</p>"
)
})
colorpal <- reactive({
colorBin(palette = "plasma", domain = data_input_ordered()$totale, bins = 6)
})
output$mymap <- renderLeaflet(
leaflet() %>%
addProviderTiles(providers$Stamen.Terrain) %>%
setView(lng = 9.768875, lat = 45.619111, zoom = 9) %>%
addPolygons(data = province_lonlat,
weight = 1,
color = "white",
fillOpacity = 0.8,
fillColor = colorpal(data_input_ordered()$totale),
highlight = highlightOptions(weight = 1,
color = "#666666",
fillOpacity = 0.5,
bringToFront = TRUE
),
label = lapply(labels(), HTML)
) %>%
addLegend(pal = colorpal,
values = data_input_ordered()$totale,
position = "topright",
labFormat = labelFormat(big.mark = ".")
)
)
output$summary_table <- renderDataTable(data_input())
}
Files are here: https://drive.google.com/drive/folders/1rL3R5W2cRrX34NDi9bpCphnVGTFcu6s7?usp=sharing

Updating spatial polygon dataframe with shiny

My shapefile has columns mean, median and sd and i want to draw a choropleth map in R Shiny. I have a sidebar that controls if tiles of map should display mean, median or sd. But I am not able to do it in Shiny. I tried using the reactive funtions but I keep getting the error below
Error: Polygon data not found; please provide addPolygons with data and/or lng/lat arguments
My code is below
library(shiny)
library(leaflet)
library(rgdal)
library(RColorBrewer)
val <- readOGR('exampleshapefile.shp')
mybins <- c(24,270,470,555,770,2000,Inf)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
radioButtons("stat", "Stat Type:",
c("Mean" = "mean",
"Median" = "q0_50",
"Standard Deviation" = "sd"
)
)
),
mainPanel("mainpanel",
leafletOutput("distSAM")
)
)
)
server <- function(input, output) {
###################### dist-wise
data <- eventReactive(input$stat,{
val#data$input$stat
})
pal <- reactive({
colorBin(palette="RdYlGn", domain = data(), na.color = "transparent", bins=mybins, reverse = TRUE)
})
labels <- reactive({
sprintf(
"<strong>%s<br/>%s</strong>%.1f",
val#data[["NAME_2"]], "SAM: ", data()
) %>% lapply(htmltools::HTML)
})
output$distSAM <- renderLeaflet({
df <- data()
pal <- pal()
lab <- labels()
leaflet() %>% addTiles() %>%
addPolygons(data = df,
fillColor = ~pal(mean),
weight = 2,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 5,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
label = lab,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(pal = pal, values = ~df$mean,
title = "SAM </br> Prevalence",
position = "bottomleft")
}
)
}
shinyApp(ui, server)
val#data$input$stat is not a valid data selection. Instead you can use:
selected_stat <- val[[input$stat]]

Chloropleth map shading in Shiny Leaflet Input slider based on column of large spatial polygons Dataframe

I am trying to create a Shiny Leaflet map with slider input based on the years listed in the columns. The data component of the Large SpatialPolygonsDataFrame looks like this with the postcode on the side and years as column names:
I am wanting to create a slider using the P2015 to P2020 columns.
How do I get the map to change the colours when a different input year is selected?
I'm not sure I understand how to use the reactive function properly.
Here is the code that I currently have:
ui <- fillPage(
titlePanel("Title"),
tags$style(type = "text/css", "html, body {width:100%; height:100%}"),
leafletOutput("mymap", width = "100%", height = "100%"),
absolutePanel(top = 10, right = 10,
sliderInput("year", "Year", min = 2015, max = 2020,
value = 2015, step = 1)
)
)
server <- function(input, output, session) {
LargeSpatialPDF <- rgdal::readOGR("~/blah.geojson")
output$mymap <- renderLeaflet({
leaflet(LargeSpatialPDF ) %>%
addMapPane(name="polygons", zIndex = 410) %>%
setView( lat=-32.30, lng=116.5 , zoom=9.45) %>%
addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
addProviderTiles(providers$Stamen.TonerLabels,
options = leafletOptions(pane = "maplabels"),
group = "map labels")
})
#not sure how to use this reactive statement here?
layer <- reactive({LargeSpatialPDF})
observeEvent({input$year}, {
year_column <- paste0('P',input$year)
data=layer()[year_column]
bins <- c(0,1,5, 10,15,20,25,30,Inf)
pal <- colorBin(c("#fff7cf",
"#f7e2af",
"#f2cc91",
"#eeb576",
"#eb9c60",
"#e7824e",
"#e36543",
"#dd433d",
"#d6003d"), domain = LargeSpatialPDF#data[year_column], bins = bins)
leafletProxy("mymap", data = data) %>%
addPolygons(
fillColor = ~pal(x),
weight = 1,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 2,
color = "white",
dashArray = "",
fillOpacity = 1,
bringToFront = TRUE),
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto"))
})
}
shinyApp(ui = ui, server = server)
reactive isn't necessary because LargeSpatialPDF is static.
I think the problems of your code are:
Whrere does x come from in fillColor = ~pal(x) ??
not df["colname"] but df[["colname"]] gives a vector.
clearShapes() is necessary.
Below is my example:
library(shiny)
library(leaflet)
library(sp)
ui <- fillPage(
titlePanel("Title"),
leafletOutput("mymap", width = "100%", height = "100%"),
absolutePanel(top = 10, right = 10,
sliderInput("year", "Year", min = 1, max = 3,
value = 1, step = 1)
)
)
server <- function(input, output, session) {
# sample_data
dsn <- system.file("vectors/ps_cant_31.MIF", package = "rgdal")[1]
LargeSpatialPDF <- rgdal::readOGR(dsn=dsn, layer="ps_cant_31", stringsAsFactors=FALSE)
set.seed(1); LargeSpatialPDF#data <- cbind(LargeSpatialPDF#data,
data.frame(P1 = sample(44), P2 = sample(44), P3 = sample(44)))
output$mymap <- renderLeaflet({
leaflet() %>%
addMapPane(name="polygons", zIndex = 410) %>%
setView( lat=43.5, lng=1.5 , zoom=8 ) %>%
addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
addProviderTiles(providers$Stamen.TonerLabels,
options = leafletOptions(pane = "maplabels"),
group = "map labels")
})
observeEvent({input$year}, {
year_column <- paste0('P',input$year)
bins <- seq(0, 45, length = 9)
pal <- colorBin(c("#fff7cf",
"#f7e2af",
"#f2cc91",
"#eeb576",
"#eb9c60",
"#e7824e",
"#e36543",
"#dd433d",
"#d6003d"), domain = LargeSpatialPDF#data[[year_column]], bins = bins)
leafletProxy("mymap") %>%
clearShapes() %>% # important
addPolygons(
data = LargeSpatialPDF,
fillColor = ~ pal(LargeSpatialPDF#data[[year_column]]), # use values of the year
options = pathOptions(pane = "polygons")) # my guess
})
}
shinyApp(ui = ui, server = server)

Shiny Leaflet R Won't Correctly Change Color of Circle Markers

I am trying to make a leaflet map in shiny so that the user is able to select a variable and the map will color the markers according to the variable that the user has selected. I am able to color the markers but unfortunately the colors aren't corresponding to the selected variable. So, for example, if the user chooses to color by "Year" all points from the same year should be colored the same, but this is not the case. What am I missing?
library(shiny)
library(dplyr)
library(leaflet)
library(RColorBrewer)
SampleData <- data.frame(year = c('2017', '2018', '2017', '2020'),
lon = c(38.62893, 38.62681, 38.62797, 38.62972),
lat = c(-90.26233, -90.25272, -90.26232, -90.25703),
month = c('January', 'February', 'March', 'April'),
new_use = c('Industrial', 'Institutional', 'Commercial', 'Residential'))
vars <- c(
"Color by Year" = "year",
"Color by Month" = "month",
"Color by Use" = "new_use"
)
ui <- bootstrapPage(
tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
leafletOutput("map", width = "100%", height = "100%"),
absolutePanel(top = 10, right = 10,
pickerInput(inputId = "month",
label = "Select Month:",
choices = sort(unique(SampleData$month)),
multiple = TRUE,
selected = sort(unique(SampleData$month)),
options = list(
`actions-box` = TRUE,
`selected-text-format` = paste0("count > ", length(sort(unique(SampleData$month))) -1), `count-selected-text` = "All Months")),
pickerInput(inputId = "year",
label = "Select Year:",
choices = sort(unique(SampleData$year)),
multiple = TRUE,
selected = sort(unique(SampleData$year)),
options = list(
`actions-box` = TRUE,
`selected-text-format` = paste0("count > ", length(sort(unique(SampleData$year))) -1), `count-selected-text` = "All Years")),
pickerInput(inputId = "new_use",
label = "Select Permit Use:",
choices = sort(unique(SampleData$new_use)),
multiple = TRUE,
selected = sort(unique(SampleData$new_use)),
options = list(
`actions-box` = TRUE,
`selected-text-format` = paste0("count > ", length(sort(unique(SampleData$new_use))) -1), `count-selected-text` = "All Permit Types")),
selectInput(inputId = "color",
label = "Select a Color Scheme:",
choices = vars)
)
)
server <- function(input, output, session) {
output$map <- renderLeaflet({
leaflet() %>%
setView(lng = -90.1994, lat = 38.6270, zoom = 10)%>%
addProviderTiles(providers$CartoDB.Positron)
})
# Reactive expression for the data subsetted to what the user selected
filteredData <- reactive({
dplyr::filter(SampleData, year %in% input$year & new_use %in% input$new_use & month %in% input$month)
})
observe({
colorBy <- input$color
if (colorBy == "year") {
colorData <- sort(unique(SampleData$year))
pal <- colorFactor("Set1", colorData)
}
if (colorBy == "month") {
colorData <- sort(unique(SampleData$month))
pal <- colorFactor("Set1", colorData)
}
if (colorBy == "dayNight") {
colorData <- sort(unique(tot$dayNight))
pal <- colorFactor("Set1", colorData)
}
leafletProxy("map") %>%
clearShapes() %>%
addCircleMarkers(data = filteredData(),
~lat, ~lon, color = pal(colorData), popup = paste("<b>Year:</b> ", filteredData()$year, "<br>",
"<b>Permit Type:</b> ", filteredData()$new_use, "<br>")) %>%
addLegend("bottomright", pal=pal, values=colorData, title=colorBy,
layerId="colorLegend")
})
}
shinyApp(ui, server)
colorFactor needs categorical data
library(shiny)
library(shinyWidgets)
library(dplyr)
library(leaflet)
library(RColorBrewer)
SampleData <- data.frame(year = c('2017', '2018', '2017', '2020', '2018', '2018', '2017'),
lon = c(38.62893, 38.62681, 38.62797, 38.62972, 38.624, 38.6245, 38.6252),
lat = c(-90.26233, -90.25272, -90.26232, -90.25703, -90.264, -90.265, -90.266),
month = c('January', 'February', 'March', 'April', 'February', 'March', 'April'),
new_use = c('Industrial', 'Institutional', 'Commercial', 'Residential', 'Institutional', 'Commercial', 'Residential'))
vars <- c(
"Color by Year" = "year",
"Color by Month" = "month",
"Color by Use" = "new_use"
)
ui <- bootstrapPage(
tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
leafletOutput("map", width = "100%", height = "100%"),
absolutePanel(top = 10, right = 10,
pickerInput(inputId = "month",
label = "Select Month:",
choices = sort(unique(SampleData$month)),
multiple = TRUE,
selected = sort(unique(SampleData$month)),
options = list(
`actions-box` = TRUE,
`selected-text-format` = paste0("count > ", length(sort(unique(SampleData$month))) -1), `count-selected-text` = "All Months")),
pickerInput(inputId = "year",
label = "Select Year:",
choices = sort(unique(SampleData$year)),
multiple = TRUE,
selected = sort(unique(SampleData$year)),
options = list(
`actions-box` = TRUE,
`selected-text-format` = paste0("count > ", length(sort(unique(SampleData$year))) -1), `count-selected-text` = "All Years")),
pickerInput(inputId = "new_use",
label = "Select Permit Use:",
choices = sort(unique(SampleData$new_use)),
multiple = TRUE,
selected = sort(unique(SampleData$new_use)),
options = list(
`actions-box` = TRUE,
`selected-text-format` = paste0("count > ", length(sort(unique(SampleData$new_use))) -1), `count-selected-text` = "All Permit Types")),
selectInput(inputId = "color",
label = "Select a Color Scheme:",
choices = vars)
)
)
server <- function(input, output, session) {
output$map <- renderLeaflet({
leaflet() %>%
setView(lng = -90.1994, lat = 38.6270, zoom = 10)%>%
addProviderTiles(providers$CartoDB.Positron)
})
# Reactive expression for the data subsetted to what the user selected
filteredData <- reactive({
dplyr::filter(SampleData, year %in% input$year & new_use %in% input$new_use & month %in% input$month)
})
observe({
colorBy <- input$color
if (colorBy == "year") {
colorData <- factor(SampleData$year)
pal <- colorFactor(palette = "Set1", levels = levels(colorData))
}
if (colorBy == "month") {
colorData <- factor(SampleData$month)
pal <- colorFactor(palette = "Set1", levels = levels(colorData))
}
if (colorBy == "dayNight") {
colorData <- factor(tot$dayNight)
pal <- colorFactor(palette = "Set1", levels = levels(colorData))
}
leafletProxy("map") %>%
clearShapes() %>%
addCircleMarkers(data = filteredData(),
~lat, ~lon, color = ~pal(colorData), popup = paste("<b>Year:</b> ", filteredData()$year, "<br>",
"<b>Permit Type:</b> ", filteredData()$new_use, "<br>")) %>%
addLegend("bottomright", pal = pal, values = levels(colorData), title = colorBy,
layerId = "colorLegend")
})
}
shinyApp(ui, server)

Resources