Is there a way to conditionally vary opacity of polygons using Leaflet? - r

I am using the R leaflet package to plot data for California counties. I would like the polygons of each county to vary in opacity based on the number of parcels in that county. Counties with more parcels should be more opaque, and counties with fewer parcels should be more transparent. Is this possible?
I have tried changing the fillOpacity option similar to how fillColor varies with number of parcels:
fillOpacity = ~num.parcels
Sample of my data:
packages <- c('dplyr','leaflet','sf','USAboundaries')
lapply(packages, library, character.only = TRUE)
ca_counties <- USAboundaries::us_counties(states = 'CA')
parcels <- structure(list(county = c("Yuba", "Sacramento", "Inyo", "Los Angeles", "Sierra"),
num.parcels = c(27797L, 452890L, 6432L, 15830L, 54291L)), row.names = c(NA, -5L), class = "data.frame")
parcels <- st_as_sf(left_join(parcels, ca_counties[,c('name')], by = c("county" = "name")))
Leaflet map:
labels <- sprintf(
"<strong>%s County</strong><br/>
Parcels: %g<br/>",
parcels$county, parcels$num.parcels
) %>% lapply(htmltools::HTML)
leaflet(parcels) %>%
setView(-119, 37.9, 6) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(num.parcels),
weight = 2,
opacity = 1,
color = 'black',
dashArray = '2',
fillOpacity = 0.7,
highlightOptions = highlightOptions(color = "red", weight = 3,
bringToFront = TRUE),
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "4px 8px"),
textsize = "15px",
direction = 'auto')) %>%
addLegend(pal = pal, values = ~num.parcels, opacity = 0.7, title = "Number of Parcels",
position = "bottomleft")

try setting fillOpacity = ~num.parcels / max(num.parcels),
I also included a pal-function.. it seemed to be missing from your code..
# Create a continuous palette function
pal <- colorNumeric( palette = "Reds", domain = parcels$num.parcels )
#calculate fillopacity
labels <- sprintf(
"<strong>%s County</strong><br/>
Parcels: %g<br/>",
parcels$county, parcels$num.parcels
) %>% lapply(htmltools::HTML)
leaflet(parcels) %>%
setView(-119, 37.9, 6) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(num.parcels),
weight = 2,
opacity = 1,
color = 'black',
dashArray = '2',
fillOpacity = ~num.parcels / max(num.parcels),
highlightOptions = highlightOptions(color = "red", weight = 3,
bringToFront = TRUE),
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "4px 8px"),
textsize = "15px",
direction = 'auto')) %>%
addLegend(pal = pal, values = ~num.parcels, opacity = 1, title = "Number of Parcels",
position = "bottomleft")

Related

specifying colors manually in leaflet bivariate map within shiny app contex

Using the code below, I have created a map within the shiny app context. However, as shown in the picture, the polygons' colors are inconsistent with the legend color scheme. I wonder how they can be consistent preferably by changing the legend color scheme. In the code below, the bi_class variable was defined in 9 categories involving a 3-dimensional quantile of x and y variables (i.e, low-low, low-medium, low-high, medium-low, medium-medium, ...).
output$bi_ACSB_BlackP <- renderLeaflet ({
npal2 <- colorFactor(
palette = ("Greens"),
domain = IDD_nhmap$bi_class
)
labels <- sprintf(
"<strong>Zip Code=%s </strong> <br/> African American (ACS) = %s <br/> African American (Projects)= %s ",
IDD_mapdata_()$Zip,
IDD_mapdata_()$Zip_Black,
IDD_mapdata_()$Zip_Hisp
) %>%
lapply(htmltools::HTML)
leaflet (IDD_mapdata_(), options = leafletOptions(zoomSnap = 0.25, zoomDelta =
0.25)) %>%
addProviderTiles("CartoDB.Positron",
options = providerTileOptions(opacity = 2)) %>%
clearControls() %>%
clearShapes() %>%
addPolygons(
fillColor = ~npal2(bi_class),
stroke = T,
weight = 1,
smoothFactor = 0.2,
fillOpacity = 1,
color = "black",
# label=~paste0(NAME," ","County",":"," ",input$sex_map,",", " ",
# input$ProjectID,"=",Age,"%"),
label = labels,
labelOptions = labelOptions(
interactive = TRUE,
style = list(
'direction' = 'auto',
'color' =
'black',
'font-family' = 'sans-serif',
# 'font-style'= 'italic',
'box-shadow' = '3px 3px rgba(0,0,0,0.25)',
'font-size' = '14px',
'border-color' = 'rgba(0,0,0,0.5)'
)
),
# label=~paste(NAME,"<br>",input$sex_map,
# input$ProjectID,"=",Age,"%"),
# label = lapply(labs, htmltools::HTML),
highlightOptions = highlightOptions(
#color = "red",
weight = 2,
bringToFront = T,
# color = "#666",
fillOpacity = 0.7
)
) %>%
setView(lng = IDD_mapdata_1()$long,
lat = IDD_mapdata_1()$lat,
zoom = 8) %>%
bivariatechoropleths::addBivariateChoropleth(
map_data = bivariatechoropleths::renfrew_county,
var1_name = pop_2016,
var2_name = median_household_income_2015,
ntiles= 3,
var1_label = "African American",
var2_label = "Hispanics",
region_name = "CSDNAME",
weight = 1,
fillOpacity = 0.7,
color = "grey",
highlightOptions = leaflet::highlightOptions(color = "orange",
weight = 2,
opacity = 1)) %>%
addTiles(options = tileOptions(opacity = 2))
})
I think if you declare a function that selects the Green colors like this one should probably work:
palColFun <- function(colorPalette = "Greens", n = 9){
pal <- RColorBrewer::brewer.pal(n, colorPalette)
return(pal)
}
Then in your code for bivariatechropleth you should add as follows:
bivariatechoropleths::addBivariateChoropleth(
map_data = bivariatechoropleths::renfrew_county,
var1_name = pop_2016,
var2_name = median_household_income_2015,
ntiles= 3,
var1_label = "African American",
var2_label = "Hispanics",
region_name = "CSDNAME",
weight = 1,
paletteFunction = palColFun,
fillOpacity = 0.7,
color = "grey",
highlightOptions = leaflet::highlightOptions(color = "orange",
weight = 2,
opacity = 1)) %>%
addTiles(options = tileOptions(opacity = 2))
Ideally you would link palColFun with the same color you generated for the plots, but given the example above, it is not for me to reproduce the example.
Hopefully this works.

Bivariate map within Shiny r

Using the code below, I could create my maps of interest which work perfectly fine within my shiny dashboard. I would like to create a bivariate map by combining these two maps.
Here are the codes for the maps:
#The code below reactivates the data:
IDD_mapdata_ <- reactive ({
out_map <- IDD_nhmap %>%
filter (ProjectID %in% input$ProjectID)
return(out_map)
})
#The code below creates the first map:
output$IDD_int_map_svi <- renderLeaflet ({
npal2 <- colorNumeric(palette = "Greens",
domain = IDD_nhmap$svi)
leaflet (IDD_mapdata_(), options = leafletOptions(zoomSnap = 0.25, zoomDelta =
0.25)) %>%
addProviderTiles("CartoDB.Positron",
options = providerTileOptions(opacity = 2)) %>%
clearControls() %>%
clearShapes() %>%
addPolygons(
fillColor = ~npal2(svi),
stroke = T,
weight = 1,
smoothFactor = 0.2,
fillOpacity = 1,
color = "black",
label = labels,
labelOptions = labelOptions(
interactive = TRUE,
style = list(
'direction' = 'auto',
'color' =
'black',
'font-family' = 'sans-serif',
# 'font-style'= 'italic',
'box-shadow' = '3px 3px rgba(0,0,0,0.25)',
'font-size' = '14px',
'border-color' = 'rgba(0,0,0,0.5)'
)
),
highlightOptions = highlightOptions(
weight = 2,
bringToFront = T,
fillOpacity = 0.7
)
) %>%
setView(lng = IDD_mapdata_1()$long,
lat = IDD_mapdata_1()$lat,
zoom = 8) %>%
addLegend(
position = "topright",
opacity = 1,
values = IDD_nhmap$svi,
pal = npal2,
title = (paste("Social Vulnerability Index")) ,
labFormat = labelFormat()
) %>%
addTiles(options = tileOptions(opacity = 2))
})
#The code below generates the second map:
output$IDD_int_map1 <- renderLeaflet ({
npal2 <- colorNumeric(palette = "Greens",
domain = IDD_nhmap$Zip_Black)
leaflet (IDD_mapdata_(), options = leafletOptions(zoomSnap = 0.25, zoomDelta =
0.25)) %>%
addProviderTiles("CartoDB.Positron",
options = providerTileOptions(opacity = 2)) %>%
clearControls() %>%
clearShapes() %>%
addPolygons(
fillColor = ~npal2(Zip_Black),
stroke = T,
weight = 1,
smoothFactor = 0.2,
fillOpacity = 1,
color = "black",
label = labels,
labelOptions = labelOptions(
interactive = TRUE,
style = list(
'direction' = 'auto',
'color' =
'black',
'font-family' = 'sans-serif',
# 'font-style'= 'italic',
'box-shadow' = '3px 3px rgba(0,0,0,0.25)',
'font-size' = '14px',
'border-color' = 'rgba(0,0,0,0.5)'
)
),
highlightOptions = highlightOptions(
weight = 2,
bringToFront = T,
# color = "#666",
fillOpacity = 0.7
)
) %>%
setView(lng = IDD_mapdata_1()$long,
lat = IDD_mapdata_1()$lat,
zoom = 8) %>%
addLegend(
position = "topright",
opacity = 1,
values = IDD_nhmap$Zip_Black,
pal = npal2,
title = (paste("African Americans (ACS)")) ,
labFormat = labelFormat()
) %>%
addTiles(options = tileOptions(opacity = 2))
})

Leaflet with R: Number formatting and thousands separator in label

So i'm trying to include some numeric figures in my label but am struggling to get it in the correct accounting format so that it is consistent with the legend. I have no trouble producing the labels without any numeric formatting, so any help in achieving the desired thousands separator would be brilliant.
library(geojson)
library(geojsonio)
library(leaflet)
library(sf)
url <- "http://leafletjs.com/examples/choropleth/us-states.js"
doc <- readLines(url)
doc2 <- gsub("var statesData = ", "", doc)
write(doc2, file = "tempgeo.json")
states <- geojson_read("tempgeo.json", what = "sp")
bins <- c(0, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, Inf)
pal <- colorBin("YlOrRd", domain = states$density, bins = bins)
states$density <- states$density*1000
c <- leaflet(states) %>%
setView(-96, 37.8, 4) %>%
addProviderTiles("MapBox", options = providerTileOptions(
id = "mapbox.light",
accessToken = Sys.getenv('MAPBOX_ACCESS_TOKEN')))
labels <- sprintf(
"<strong>%s</strong><br/>%g",
states$name, states$density
) %>% lapply(htmltools::HTML)
c <- c %>% addPolygons(
fillColor = ~pal(density),
weight = 2,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 5,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(pal = pal, values = ~density, opacity = 0.7, title = NULL,
position = "bottomright")
c
Thank you
You can convert the label to a string, and use prettyNum to format it with commas.
labels <- sprintf(
"<strong>%s</strong><br/>%s",
states$name, prettyNum(states$density, big.mark = ",")
) %>% lapply(htmltools::HTML)

leaflet + shiny: "argument is of length zero" in addLegend values

I'm developing a shiny app to show a choropleth map, using leaflet and a shapefile to add the polygons. Outside shiny everything works fine, but with shiny I got a problem when using addLegend as follows:
mypal <- reactive({
colorBin(palette = "RdYlBu", domain = get("map_fires")[[paste0("qm_", selectedYear())]],
bins = 5, reverse = TRUE, pretty = FALSE,
na.color = "#FFFAFA")
})
output$map <- renderLeaflet({
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
addPolygons(data = map_fires,
stroke = TRUE, weight = 1, smoothFactor = 0.2, fillOpacity = 0.3,
fillColor = ~mypal()(get("map_fires")[[paste0("qm_", selectedYear())]]),
highlight = highlightOptions(
weight = 5,
color = "#666",
fillOpacity = 0.7,
bringToFront = TRUE),
label= lapply(stats_labels(), HTML),
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(position = "bottomright", pal = ~mypal(),
values = ~get("map_fires")[[paste0("qm_", selectedYear())]],
opacity = 1)
})
The code above returns:
Warning: Error in if: argument is of length zero
104: addLegend
...
I'm using paste0("qm_", selectedYear()) to refer to different columns with yearly data.
I believe the problem is in values = ~get("map_fires")[[paste0("qm_", selectedYear())]], but can't tell why. I have already tried to specify the dataset on addLegend, and also to put a specific column on values = (i.e., without depending on the reactive value of selectedYear()), to no avail.
Outside shiny things work good with the code below (where I keep using get("map_fires")[[paste0("qm_", 2018)]], changing selectedYear() for a specific year, just to better show my case):
mypal <- colorBin(palette = "RdYlBu", domain = get("map_fires")[[paste0("qm_", 2018)]],
bins = 5, reverse = TRUE, pretty = FALSE,
na.color = "#FFFAFA")
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
addPolygons(data = map_fires,
stroke = TRUE, weight = 1, smoothFactor = 0.2, fillOpacity = 0.3,
fillColor = ~mypal(get("map_fires")[[paste0("qm_", 2018)]]),
highlight = highlightOptions(
weight = 5,
color = "#666",
fillOpacity = 0.7,
bringToFront = TRUE),
label= lapply(stats_labels, HTML),
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(position = "bottomright", pal = mypal,
values = get("map_fires")[[paste0("qm_", 2018)]],
opacity = 1)
Am I missing something?

Highlight Borders When Mouseover Fill Area - Leaflet-R

Following the guidance of #TimSalabim, I separated the borders and fill of my neighbourhood polygons so that I could order them appropriately with zIndex.
https://lawsblog.netlify.com/post/leaflet-map/
If I place the highlightOptions() function within the addPolygons(neighbourhood fill) function, I don't know how to increase the border of the polygon upon mouseover.
If I place the highlightOptions() function within the addPolylines(neighbourhood border) function I can CAREFULLY mouse-over just the borders and the widths increase. That's the behavior I want, when I mouse-over any part of the neighbourhood area.
Now that I've separated the fill and borders of the polygons how do I increase the border width when I mouse-over the fill area?
# Add hood borders
addPolylines(data = borders,
color = "white",
opacity = 1,
weight = 2,
options = pathOptions(pane = "hood_borders")) %>%
# Add hood fill
addPolygons(data = hood_shp,
fillColor = ~pal(be_per_cap),
fillOpacity = 1.0,
color = NA,
options = pathOptions(pane = "hoods",
# Highlight neighbourhoods upon mouseover - NOT CORRECT
highlight = highlightOptions(
stroke = 4),
# Add label info when mouseover
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")))
Taking what SeGa advised, I've modified the code. See here. The neighbourhood borders are not obscured and the border does expand upon hover. However the border does not revert back to its original width with mouse out. Why is that?
leaflet(options = leafletOptions(minZoom = 11, maxZoom = 16), width = "100%") %>%
addTiles() %>%
# Raster image surrounding Toronto
addProviderTiles(providers$OpenStreetMap.BlackAndWhite) %>%
# Center map north of Toronto City Hall slightly zoomed in
setView(map,
lng = -79.384293,
lat = 43.685, #43.653908,
zoom = 12) %>%
# Vector neighbourhoods
addPolygons(data = hood_shp,
fillColor = ~pal(be_per_cap),
color = NA,
fillOpacity = 1,
# Highlight neighbourhoods upon mouseover
highlight = highlightOptions(
weight = 3,
fillOpacity = 0,
color = "black",
opacity = 1.0,
bringToFront = TRUE,
sendToBack = TRUE),
# # Add label info when mouseover
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
# Add highways
addPolygons(data = xway,
color = "sienna",
weight = 1.0,
opacity = 1.0,
fillOpacity = 0.7) %>%
# Add major arterial
addPolygons(data = mart,
color = "#737373",
weight = 1.0,
opacity = 1.0,
fillOpacity = 1.0) %>%
# Add parks
addPolygons(data = parks,
color = "green",
weight = 1.0,
opacity = 1.0,
fillOpacity = 1.0,
options = pathOptions(clickable = FALSE)) %>%
# Add border
addPolylines(data = hood_shp,
color = "black",
stroke = TRUE,
opacity = 1,
weight = 1) %>%
# Add legend
addLegend(data = hood_shp,
colors =c("#AA122E", "#F4AE7E", "#FEFDB7"),
labels= c("More", "", "Less"),
opacity = 1.0,
title = "B&Es",
position = "bottomright")
I'm not sure if I understand your problem correctly but if you only want to increase the borders of a polygon with leaflet, the highlightoption is the right choice, but you shouldn't place it inside the pathOptions.
The following example uses addPolygons for the neighboorhoods with a highlightOption. Within those you define the behaviour of the neighboorhoods when mouse-overing. With the weight argument you define the border size.
The parks also go in an addPolygons but with options =
pathOptions(clickable = FALSE) you make them unclickable, so they
dont interact with mouse events.
And the borders go in a addPolylines without any further
options.
Is the following example what you are looking for?
library(sp)
Sr1 = Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))
Sr2 = Polygon(cbind(c(5,4,2,5),c(2,3,2,2)))
Srs1 = Polygons(list(Sr1), "s1")
Srs2 = Polygons(list(Sr2), "s2")
hood_shp = SpatialPolygons(list(Srs1,Srs2), 1:2)
hood_shp <- SpatialPolygonsDataFrame(hood_shp, data=data.frame(be_per_cap = 1:length(hood_shp)), match.ID = F)
parks = Polygon(cbind(c(2,3,3,1,2),c(1,2,4,3,1)))
parks = SpatialPolygons(list(Polygons(list(parks), "parks")))
xway = Polygon(cbind(c(1,5,5,1,3),c(3,5,5,3,1)))
xway = SpatialPolygons(list(Polygons(list(xway), "xway")))
library(shiny)
library(leaflet)
library(htmlwidgets)
ui <- fluidPage(
leafletOutput("map")
)
server <- function(input, output) {
output$map <- renderLeaflet({
pal = colorBin("Blues", hood_shp$be_per_cap)
leaflet(width = "100%") %>%
addTiles() %>%
# Raster image surrounding Toronto
addProviderTiles(providers$OpenStreetMap.BlackAndWhite) %>%
# Vector neighbourhoods
addPolygons(data = hood_shp,
fillColor = ~pal(be_per_cap),
color = "transparent",
fillOpacity = 1,
# Highlight neighbourhoods upon mouseover
highlight = highlightOptions(
weight = 3,
fillOpacity = 0,
color = "black",
opacity = 1.0,
bringToFront = TRUE,
sendToBack = TRUE),
# # Add label info when mouseover
label = "labels",
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
# Add parks
addPolygons(data = parks,
color = "green",
weight = 1.0,
opacity = 1.0,
fillOpacity = 1.0,
options = pathOptions(clickable = FALSE)) %>%
# Add highways
addPolygons(data = xway,
color = "sienna",
weight = 1.0,
opacity = 1.0,
fillOpacity = 0.7) %>%
# Add border
addPolylines(data = hood_shp,
color = "black",
stroke = TRUE,
opacity = 1,
weight = 1) %>%
# Add legend
addLegend(data = hood_shp,
colors =c("#AA122E", "#F4AE7E", "#FEFDB7"),
labels= c("More", "", "Less"),
opacity = 1.0,
title = "B&Es",
position = "bottomright")
})
}
shinyApp(ui, server)

Resources