this is my first time working with R shiny and I am attempting to integrate shiny features with a leaflet map I have made. The idea is that I would like to have radio buttons which toggle between four different polygons layers generated by shapefile data, and a slider which controls the opacity of the polygon layer. I used code from several different tutorials on shiny and leaflet but when I attempt to generate the map I get the following warning:
Warning: Error in google_dispatch: Invalid map parameter
[No stack trace available]
the panel with my buttons and slider appear but not my map. I believe this issue is with this section of my code:
opacityf <- reactive({
opacity[opacity$value == input$slider, ]
})
layerf <- reactive({
switch(input$layer,
countiesr = counties,
regionsr = regions,
triber = tribe,
publicr = public,
selected = NULL)
})
observe({
leafletProxy(mapId = "Intensity_Map", data = layerf()) %>%
clear_polygons() %>%
addPolygons(fillOpacity = opacityf(),
weight = 1,
color = "purple4")
})
}
I created a data frame with values between 0.0 and 1.0 for the opacity slider and I am attempting to direct shiny to change to opacity value to be whatever the slider value is. For the buttons I am trying to direct shiny to plot one of the four spatial polygon objects I created using the shapefiles. I believe I have a mistake in here somewhere but I cannot seem to figure out what it is.
Here is the rest of my code for reference:
ui <- fluidPage(
titlePanel("Cyano-Toxin Concentration in Relation
to OEHHA Action Levels for Acute Toxicity in Dogs"),
sliderInput(inputId = "slider",
label = "Opacity",
min = 0,
max = 1,
value = NULL,
step = 0.1),
radioButtons(inputId = "layer",
label = "Map Layer",
choices = c("Counties" = "countiesr",
"Regional Boards" = "regionsr",
"Tribal Lands" = "triber",
"Public Lands" = "publicr")),
leafletOutput("Intensity_Map")
)
opacity <- data.frame(value = c(0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0))
server <- function(input, output, session){
output$Intensity_Map <- renderLeaflet({
leaflet() %>% setView(lat = 36.778259, lng = -119.417931, zoom = 5) %>% addTiles(group = "None") %>%
addCircleMarkers(
data = ws_ND,
radius = 4,
color = "grey",
stroke = FALSE, fillOpacity = 0.7,
label = ~as.character(label),
popup = ~as.character(popup),
group = "None Detected"
)%>%
addCircleMarkers(
data = ws_M,
radius = ws_M$Radius,
color = ~pala(Percent.of.AL),
stroke = FALSE, fillOpacity = 0.7,
label = ~as.character(label),
popup = ~as.character(popup),
group = "Microcystin/Nod."
)%>%
addCircleMarkers(
data = ws_C,
radius = ws_C$Radius,
color = ~palc(Percent.of.AL),
stroke = FALSE, fillOpacity = 0.7,
label = ~as.character(label),
popup = ~as.character(popup),
group = "Cylindrospermopsin"
)%>%
addCircleMarkers(
data = ws_A,
radius = ws_C$Radius,
color = ~palb(Percent.of.AL),
stroke = FALSE, fillOpacity = 0.7,
label = ~as.character(label),
popup = ~as.character(popup),
group = "Anatoxin-a"
)%>%
addCircleMarkers(
data = ws_S,
color = "yellow",
radius = 8,
stroke = FALSE, fillOpacity = 0.7,
label = ~as.character(label),
popup = ~as.character(popup),
group = "Saxitoxin"
)%>%
addLayersControl(
overlayGroups = c("None Detected", "Microcystin/Nod.","Cylindrospermopsin","Anatoxin-a","Saxitoxin"),
options = layersControlOptions(collapsed = FALSE),
position = "topright"
)%>%
addLegend("bottomright", pal = palab, values = (labels = c("1. < 25%","2. 25% - 49%","3. 50% - 99%", "4. ≥ 100%")),
title = "Microcystin/Nod.",
opacity = 1,
group = "Microcystin/Nod."
)%>%
addLegend("bottomright", pal = palbb, values = (labels = c("1. < 25%","2. 25% - 49%","3. 50% - 99%", "4. ≥ 100%")),
title = "Anatoxin-a",
opacity = 1,
group = "Anatoxin-a"
)%>%
addLegend("bottomright", pal = palcb, values = (labels = c("1. < 25%","2. 25% - 49%","3. 50% - 99%", "4. ≥ 100%")),
title = "Cylindrospermopsin",
opacity = 1,
group = "Cylindrospermopsin") })
opacityf <- reactive({
opacity[opacity$value == input$slider, ]
})
layerf <- reactive({
switch(input$layer,
countiesr = counties,
regionsr = regions,
triber = tribe,
publicr = public,
selected = NULL)
})
observe({
leafletProxy(mapId = "Intensity_Map", data = layerf()) %>%
clear_polygons() %>%
addPolygons(fillOpacity = opacityf(),
weight = 1,
color = "purple4")
})
}
shinyApp(ui, server)
Any thoughts would be greatly appreciated!
I made the following map from a data frame that contains the number of parole of each state from the years 1995-2015 per 100,000 as well as the spatial information for each state. I want to incorporate it into r shiny app to have a slider to be able to choose the specific year and view it. I got the slider to work and change the data and when you first run it works and gives you the appropriate state and number. However, when you move around the slider the geospatial labels start moving around using the reactive and different states start getting different states labels. Like the following:
The slider starts at the year 2000 and as you can see the if I move it around it, in this case 2014, now we have florida being labeled as Montana.
All these was done within the R shiny app. This is the code I have below. I have my leaflet map fully created outside the server.
server <- function(input, output) {
#Set YEAR with Slider
state_parole_year <- reactive({
state_parole %>%
filter(year == year(input$year))
})
labels_year <- reactive({paste("Parole/100000 US Adults",
state_parole_year()$state, state_parole_year()$number_on_parole_per_100000_us_adult_residents)})
output$mymap <- renderLeaflet({
state_map %>%
addTiles()%>%
addPolygons(fillColor = ~ pal(state_parole_year()$number_on_parole_per_100000_us_adult_residents),
fillOpacity = 1,
color = "blue",
opacity = 0.1,
weight = 1,
highlight = highlightOptions(
weight = 3,
color = "blue",
fillOpacity = .2,
bringToFront = TRUE),
label = labels_year())
})
}
When I run the leaflet map outside of r shiny app and change the year manually by subsetting the csv it works perfectly. The problem occurs when I try to make the labels reactive to the slider. Does someone know how I can fix the problem? Thanks!
The problem is that you build the map on unfiltered data, then display it with filtered data. There is then a switch in factors.
A quick fix is to build your map on filtered data, directly in the server() function :
output$mymap <- renderLeaflet({
leaflet(data = state_parole_year()) %>%
addTiles() %>%
setView(lng = -80,
lat = 34.5,
zoom = 4) %>%
addPolygons(fillColor = ~ pal(state_parole$number_on_parole_per_100000_us_adult_residents),
fillOpacity = 1,
color = "blue",
opacity = 0.1,
weight = 1,
highlight = highlightOptions(
weight = 3,
color = "blue",
fillOpacity = .2,
bringToFront = TRUE),
label = labels) %>%
addLegend(
position = "topright",
pal = pal,
values = ~number_on_parole_per_100000_us_adult_residents,
title = "# of U.S. Adults on Parole/100000.",
opacity = 1) %>%
addTiles()%>%
addPolygons(fillColor = ~ pal(state_parole_year()$number_on_parole_per_100000_us_adult_residents),
fillOpacity = 1,
color = "blue",
opacity = 0.1,
weight = 1,
highlight = highlightOptions(
weight = 3,
color = "blue",
fillOpacity = .2,
bringToFront = TRUE),
label = ~labels_year())
})
I am building an app based on election results and I would like to colour the polygons on the leaflet map with the elected parties' colours per electorate. The user can select the year for which the choose to see the results: Sitting Party (current), 2013 etc.
I have read a lot on here about dynamic colour palettes and reactive colour palettes based on user input but none of them work with my pre-defined colour palette which sets a specific colour to each party abbreviation based on the party colours.
I am not sure what I am missing or doing wrong, but help will be greatly appreciated.
You can download the shp files here here, I used the Queensland 2018 distributions: https://www.aec.gov.au/electorates/gis/
And here is the elected party data which I merged with the shape file on the field Elect_div:
PartyAb<-c(ALP,"LNP","LNP", "LNP","LNP","LNP","LNP","LNP","LNP","LNP","LNP", "LNP","ALP","LNP","ALP","LNP","KAP","LNP","ALP","ALP","LNP","LNP","LNP","ALP", "ALP","LNP","ALP","LNP","LNP","LNP")
Elected_Party_2013<-c("ALP","LNP","LNP","LNP","LNP","LNP","LNP","LNP","PUP", "LNP","LNP","LNP","ALP","LNP","LNP","LNP","KAP","LNP","ALP","LNP","LNP","LNP", "LNP", "ALP", "ALP", "LNP", "ALP", "LNP","LNP","LNP")
Elect_div<-c("Blair","Bonner","Bowman","Brisbane",
"Capricornia","Dawson","Dickson","Fadden",
"Fairfax","Fisher","Flynn","Forde",
"Griffith","Groom","Herbert","Hinkler",
"Kennedy","Leichhardt","Lilley",
"Longman","Maranoa","McPherson",
"Moncrieff","Moreton","Oxley",
"Petrie","Rankin","Ryan",
"Wide Bay","Wright")
df.party <- data.frame c(PartyAb, Elected_Party_2013, Elect_div)
#read in the shape files and filter to only have qld elects
qld<-readOGR(dsn=path.expand("./data/shape_files"), layer="E_AUGEC_region")
qld<-qld[qld$Elect_div %in% c("Blair","Bonner","Bowman","Brisbane",
"Capricornia","Dawson","Dickson","Fadden",
"Fairfax","Fisher","Flynn","Forde",
"Griffith","Groom","Herbert","Hinkler",
"Kennedy","Leichhardt","Lilley",
"Longman","Maranoa","McPherson",
"Moncrieff","Moreton","Oxley",
"Petrie","Rankin","Ryan",
"Wide Bay","Wright"),]
#merge the csv to the shape file based on elect_div
qld.stats <- merge(qld, df, by = "Elect_div")
ui<- fluidPage(selectInput("stats", "",label="Select a statistic to display spatially on the map.",
choices= list("Sitting Party"="PartyAb",
"2013 results"="Elected_Party_2013" ))
)
#colour palette based on party colours
party_cols<-c("LNP"="#021893","ALP" = "#C12525","IND" = "grey", "KAP" = "#33165F",
"PUA"="orange", "ON"="orange", "GRN"="#339966", "LNQ"="#0066FF",
"LP"="#0033CC", "NP"="#009999", "Electorate not established in 2007"="black", "Electorate not established in 2004"="black")
#attempt to create a reactive colour palette using the party_cols colour palette based on user input but it doesnt work
observe({
if (input$stats == "PartyAb") {
pal <- colorFactor(c("LNP"="#021893","ALP" = "#C12525","IND" = "grey", "KAP" = "#33165F",
"PUA"="orange", "ON"="orange", "GRN"="#339966", "LNQ"="#0066FF",
"LP"="#0033CC", "NP"="#009999", "Electorate not established in 2007"="black", "Electorate not established in 2004"="black"), domain= qld.stats[[input$stats]])
} else {
pal <- colorNumeric(c("red", "green"), domain = qld.stats[[input$stats]], reverse = FALSE)
}
# the second part of the colour palette above is related to the fact that I have other options from the dropdown menu that display numeric stats like unemployment and participation rate
#this colour palette works but it is a total fluke and won't work for
this years data as there are green and yellow colours required so I need something like this but that uses the party_cols colour palette
colorpal <- reactive({
colorFactor(colorRamp(c("red", "blue")), domain = qld.stats[[input$stats]], reverse = FALSE)
})
#create the base map that will be displayed regardless of selected input
output$map<-renderLeaflet({
leaflet(qld.stats) %>%
addProviderTiles(providers$OpenStreetMap.BlackAndWhite) %>% #(providers$OpenStreetMap.BlackAndWhite)%>%
# Centre the map in the middle of our co-ordinates
fitBounds(min(137.99),max(-29.18),min(153.55),max(-9.12))
})
leafletProxy("map", data = qld.stats) %>%
clearShapes() %>%
addPolygons(
layerId = qld.stats$Elect_div,
fillColor = ~pal(qld.stats[[input$stats]]),
fillOpacity = 0.4,
weight = 0.6,
opacity = 1,
color = "#444444",
dashArray = "5",
label = labels,
highlight = highlightOptions(
weight = 4,
color = "#FFFFFF",
dashArray = "",
fillOpacity = 0.9,
bringToFront = TRUE),
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 5px"),
textsize = "13px",
direction = "auto")
)
#we are adding a legend to display the raw data that aligns with the spatially depicted stat from the stats drop-down
#this information is also displayed in the pop-ups for each clickable electorate
varname<-switch(input$stats,
"PartyAb"="Sitting Party", "Electorate Population"="CED_pop_total",
'CED_participation_rate_2018'="Work-force participation rate %",
'Unemployment_rate_2018'="Unemployment rate %")
leafletProxy("map", data = qld.stats) %>% clearControls() %>%
addLegend(pal = pal, opacity = 0.9, title = varname,
values = ~qld.stats[[input$stats]],labels = c(min(input$stats), max(input$stats)),
position = "topleft")
})
#we want to create a reactivity so users can either select the division
#from the drop down menu or by clicking on the map
observe({
event <- input$map_shape_click
if (is.null(event))
return()
updateSelectInput(session, "division", selected = event$id)
})
#we want to create reactivity so that the map to zooms in on and focus on the selected electorate
observe({
selectedPolygon <- subset(qld.stats, qld.stats$Elect_div == input$division)
leafletProxy("map", data = qld.stats) %>%
removeShape("highlightedPolygon") %>%
fitBounds(selectedPolygon#bbox[1,1],
selectedPolygon#bbox[2,1],
selectedPolygon#bbox[1,2],
selectedPolygon#bbox[2,2]) %>%
addPolylines(weight = 4, color = "white",
data = selectedPolygon, layerId = "highlightedPolygon")
})
}
shinyApp(ui, server)
So I figured out a work around to the issue I was having which was needing a predefined colour scheme (political party colours) to fill polygons on a leaflet map based on user input from a drop down menu.
My solution isn't exactly what I was after, but it definitely works and I am happy with it.
#we need to set up 3 separate colour schemes for the different options from the spatial stats drop down menu
#one for current party using factor levels to match the party colours
#one for the previous election results using same rationale
#one for the numeric based stats for unemployment rate and participation rate
observe({
if (input$stats == "PartyNm") {
pal <- colorFactor(c("#C12525","#6600CC","#021893"), domain= qld.stats[[input$stats]])
} else if (input$stats == "Elected_Party_2013") {
pal <- colorFactor(c("#C12525","##6600CC","#021893", "yellow"), domain= qld.stats[[input$stats]])
} else {
pal <- colorNumeric(c("#C12525", "#33ffff"), domain = qld.stats[[input$stats]], reverse = FALSE)
}
#creating a proxy map that displays the various stats from the stats drp down
leafletProxy("map", data = qld.stats) %>%
clearShapes() %>%
addPolygons(
layerId = qld.stats$Elect_div,
fillColor = ~pal(qld.stats[[input$stats]]),
fillOpacity = 0.6,
weight = 0.6,
opacity = 1,
color = "#444444",
dashArray = "5",
label = labels,
highlight = highlightOptions(
weight = 4,
color = "#FFFFFF",
dashArray = "",
fillOpacity = 0.9,
bringToFront = TRUE),
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 5px"),
textsize = "13px",
direction = "auto")
)
I want to color map my polygons based on the user input. The column i am using has categorial variables so I am using the colorFactor function which I have tested it is functioning normally. The issue is with the observe function when I load my shiny app it terminates immediately and outputs "Error in addPolygons: unused argument (fillcolor = ~pal(AreaTyp)) in leaflet".My question is how to include reactivity correctly using the observe function. Here is my code:
#INTERACTIVE MAPPING
#colorfunction
pal<-colorFactor(rainbow(7),mp$AreaTyp)
#set data based on user input
fdata<-reactive({
data<-mp
if(input$area!="All"){
data<-data[data$AreaType==input$area,]
}
data
})
output$leaf<-renderLeaflet({
leaflet(fdata()) %>%
#Initializing the map
setView(lng=36.092245, lat=-00.292115,zoom=15)%>%
#Base map
#Add default OpenStreetMap map tiles
addTiles(group = "default")%>%
#addProviderTiles("Esri.NatGeoWorldMap",group = "default")%>%
#addProviderTiles("CartoDB.Positron",group = "custom")%>%
#Overlay map
addPolygons(
data = fdata(),
fillColor = "blue",
weight = 1, smoothFactor = 0.5,
opacity = 1.0, fillOpacity = 1.0,
group = "basepoly",
highlightOptions = highlightOptions(
weight = 2,
color = "red",
fillOpacity = 0.7,
bringToFront = TRUE
),label =~LIA
)
})
observe({
leafletProxy("leaf",data = fdata()) %>%
clearShapes() %>%
addPolygons(
weight = 1, smoothFactor = 0.5,
opacity = 1.0, fillOpacity = 1.0,
data=fdata(),
fillcolor = ~pal(AreaTyp),
label =~LIA
)
})
Change fillcolor = ~pal(AreaTyp) to fillColor = ~pal(AreaTyp)
Let's break down your error.
"Error in addPolygons: unused argument (fillcolor = ~pal(AreaTyp)) in leaflet"
first:
"Error in addPolygons:
this means that addPolygons failed to run. not that the observer failed
second
"unused argument "
This means that you added an argument that addpolygons can not use.
Third
(fillcolor = ~pal(AreaTyp)) in leaflet
This is telling you exactly which argument is wrong.