I am looking to add a title to the layer control box along the lines of "Available layers".
My search has lead me to only one relevant result:
Exact same question using JS. Unclear how to translate
My code:
map %>% leaflet() %>%
addProviderTiles(provider = "CartoDB") %>%
# Group 1 Polygons
addPolygons(data = map[!is.na(map$var),] ,weight =1,
color = ~g1_pal(g1), fillOpacity = .6,
group = "Group 1",
# add labels
label = ~labels,
# highlight polygons on hover
highlight = highlightOptions(weight = 5, color = "white",
bringToFront = TRUE)) %>%
# Group 2
addPolygons(data = map[!is.na(map$var2),], weight =1,
color = ~g2_pal(g2), fillOpacity = .6,
group = "Group 2",
# add labels that display mean income
label = ~labels2,
# highlight polygons on hover
highlight = highlightOptions(weight = 5, color = "white",
bringToFront = TRUE)) %>%
addLayersControl(baseGroups = c("Group 1", "Group 2"),
options = layersControlOptions(collapsed=F,
# Series of attempts
label = "Layers",
title = "Layers"))
Neither of these attempts worked. It does appear from the link above that there is an attribute that can be accessed but I am unsure of how to reference it.
The best way to do this (that I'm aware of) is to use htmlwidgets::onRender to add your Javascript to the map upon rendering. This is described in the last section at the bottom of the last page in the docs, so it's easy to miss!
Here's an example that implements the Javascript that Saurabh Yadav described in his answer to the question you linked. You simply add the Javascript function to the end of the leaflet() piped call:
library(leaflet)
leaflet() %>%
addTiles() %>%
addLayersControl(
overlayGroups = "MyImaginaryLine",
options = layersControlOptions(collapsed = FALSE)) %>%
htmlwidgets::onRender("
function() {
$('.leaflet-control-layers-overlays').prepend('<label style=\"text-align:center\">My Epic Title</label>');
}
")
Related
i have somehow a quite tricky question. Im creating an interactive leaflet map in my shinydashboard. Everything works fine (the error just appears because its waiting for some text input to be processed and then mapped).
But.. I don't get the map to work, when only the first textinput is given some Input. One must insert something in the second, which is not handy and can lead to some weird results. If nothing is insert, the script doesn't get any further and is stuck.
Wrap up. How its possible to make the second textinput obligatory?
Is there a workaround or a possibility to deactivate the second textinput until one inserts a string? Otherwise the script just waits and waits (throws this error because no string is given which can be processed obviously)...
Structure
textinput from shiny dashboard -> parsed into google_places request -> tidy -> returns points (Lon, Lat) -> gets displayed on the leaflet map.
The Dashboard
Even though it must not have to do with the leaflet-map I provide a shrinked code. Its the second addCircleMarkers argument.
The map
map$dat <-leaflet () %>%
addProviderTiles(providers$CartoDB.Positron, group = "Positron Design") %>%
addMarkers(lat= Ort_geocode()$lat, lng= Ort_geocode()$lng, group = "Standort") %>%
addCircleMarkers(data = cowork(), popup = paste(as.character(cowork()$name), "</br>", cowork()$rating),fill =TRUE, fillColor ="#20205F", stroke =FALSE, fillOpacity = 0.8, group = "Erste Nutzung",
labelOptions = labelOptions(noHide = T, textOnly = TRUE, direction = "bottom", style = list("color" = "black", "font-size" = "11px", "font-family" = "AkkuratStd", "font-style" = "Thin"))) %>%
addCircleMarkers(data = Zweite_Nutzung(), popup = paste(as.character(Zweite_Nutzung()$name), "</br>", Zweite_Nutzung()$rating), fill =TRUE, fillColor ="#607758", stroke =FALSE, fillOpacity = 0.8, group = "Zweite Nutzung" ,
labelOptions = labelOptions(noHide = T, textOnly = TRUE, direction = "bottom", style = list("color" = "black", "font-size" = "11px", "font-family" = "AkkuratStd", "font-style" = "Thin"))) %>%
addHeatmap(data = cowork(), lng= cowork()$lng,lat= cowork()$lat, intensity = 20 ,max=40,radius=20,blur=15, gradient = "inferno" , group = "Cluster") %>%
addHeatmap(data = Zweite_Nutzung(), lng= Zweite_Nutzung()$lng,lat= Zweite_Nutzung()$lat, intensity = 20 ,max=40,radius=20,blur=15, gradient = "magma", group = "Cluster 2") %>%
addLayersControl(
baseGroups = c("Kartengrundlage", "Positron Design"),
overlayGroups = c("Standort", "Cluster", "Cluster 2", "Erste Nutzung", "Zweite Nutzung", "Modalität 1", "Modalität 2", "Modalität 1 Nacht", "Modalität 2 Nacht"),
options = layersControlOptions(collapsed = FALSE)) %>%
hideGroup("Cluster") %>%
hideGroup("Cluster 2") %>%
addFullscreenControl(pseudoFullscreen = TRUE)
})
Im more than thankful if somebody could help me.
Great weekend guys!
Sebastian
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 would like users to be able to change the choropleth map overlay by selecting different attributes from a dropdown. The map and different attributes render fine based on user selection, but the popup option of the addPolygons function does not interpret the input values the same as the rest of the app.
For below, assume we are using an object of class 'sf' named densitydata with columns for the polygon geography and the different densities to be mapped (dens1, dens2 and dens3). I want the popup to return the values of the selected density for the clicked feature. E.g. "Selected density: 1.23" but instead get the name of the column: "Selected density: dens1".
If I put the input in a mathematical function like round(), I get an error that I'm providing a non-numeric value to a mathematical function:
popup = ~paste0("<b>Selected density:</b> ", round(input$densities, 2))
Dropdown menu:
dashboardSidebar(
selectInput(inputId = "densities", label = "Select attribute",
choices = c("Density 1" = "dens1",
"Density 2" = "dens2",
"Density 3" = "dens3"), selected = NULL, multiple = F, selectize = TRUE, width = '500px', size = NULL),
Rendering the map in the server function:
output$DensMap <- renderLeaflet({
# Define palette for new selection
DensPal <- colorQuantile(palette = "YlOrRd",
domain = {densitydata %>%
pull(input$densities)},
n = 5)
# Render map
leaflet(data = densitydata) %>%
addTiles() %>% # Add default OpenStreetMap map tiles
addPolygons(fillColor = ~DensPal({densitydata %>% pull(input$densities)}),
fillOpacity = 0.5,
weight = 2,
popup = ~paste0("<b>Selected density:</b> ", input$densities) %>%
addLegend(pal = DensPal,
values = {densitydata %>% pull(input$densities)},
opacity=0.7,
title = "Legend title here",
position = "bottomleft" )
} )
You can not use input$densities directly, you can use it thru densitydata[[input$densities]]:
output$DensMap <- renderLeaflet({
# Define palette for new selection
DensPal <- colorQuantile(palette = "YlOrRd",
domain = densitydata[[input$densities]],
n = 5)
# Render map
leaflet(data = densitydata) %>%
addTiles() %>% # Add default OpenStreetMap map tiles
addPolygons(fillColor = ~DensPal(densitydata[[input$densities]]),
fillOpacity = 0.5,
weight = 2,
popup = ~paste0("<b>Selected density:</b> ",
densitydata[[input$densities]]) %>%
addLegend(pal = DensPal,
values = densitydata[[input$densities]],
opacity=0.7,
title = "Legend title here",
position = "bottomleft" )
} )
I am trying to create a high-quality map of a small part of the UK, without any distortions caused by the use of projections, and with the addition of markers consisting of text and symbols. Ultimately the goal is to write out a png or pdf file. An earlier, related question can be found here.
Having not used R in anger for several years, I have been wading through a morass of packages trying to find something suitable. Leaflet for R is promising, but although I can create a decent-looking map, add markers, and vary the colour of markers and so on using columns from a data frame, I have not been able to vary the size, colour, and text offsets used in the labelOptions argument.
The following reproducible example shows what I can achieve, and also where I am not succeeding. I would like the size of text label to vary according to the df.data$textsizes column. Given that the style argument takes a list of value pairs, that would seem difficult, and nothing has worked so far.
If am hoping that somebody can either suggest either a way to bend the wily labelOptions to my will, or a completely different approach to try.
require(leaflet)
require(magrittr)
df.entrynames <- c("Entry 1: Some text","Entry 2: More text")
df.lat <- c(51.509898,51.510736)
df.lon <- c(-0.1345093,-0.135190)
df.colors <-c("Blue","Red")
df.sizes <-c(36,12)
df.data <- data.frame(entrynames=df.entrynames,lat=df.lat,lon=df.lon,colors=df.colors,textsizes=df.sizes)
df.data$entrynames <- as.character(df.data$entrynames)
df.data$colors <- as.character(df.data$colors)
df.data$textsizes <- paste(df.data$textsizes,"px",sep="")
leaflet() %>% setView(lng = -0.134509, lat = 51.509898, zoom = 17) %>% addTiles() %>%
addCircleMarkers(data = df.data,
lat = ~lat, lng = ~lon,
label = df.data$entrynames,
color = df.data$colors,
labelOptions = labelOptions(noHide = TRUE,
style = list(
"color" = "gray30",
"font-family" = "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)"
),
textOnly = FALSE,
offset=c(0,0)))
df.entrynames <- c("Entry 1: Some text","Entry 2: More text")
df.lat <- c(51.509898,51.510736)
df.lon <- c(-0.1345093,-0.135190)
df.colors <-c("Blue","Red")
df.sizes <-c(36,2)
df.data <- data.frame(entrynames=df.entrynames,lat=df.lat,lon=df.lon,colors=df.colors,textsizes=df.sizes)
df.data$entrynames <- as.character(df.data$entrynames)
df.data$colors <- as.character(df.data$colors)
df.data$textsizes <- paste(df.data$textsizes,"px",sep="")
#Add a vector to split the data by
df.data$place<-seq(1:nrow(df.data))
library(purrr)
#split the data
ob_place <- df.data %>%
split(., .$place)
#make a map
m <- leaflet() %>%
addTiles()
#Add layers
names(ob_place) %>%
purrr::walk(function(df.data) {
m<<-m %>% #seems like there's supposed to be two carrots here, i had problems without one
addCircleMarkers(data=ob_place[[df.data]],fillColor=~colors,
fillOpacity = 0.6,
weight=1,
radius=13,
color="white",
opacity = .6,
lng=~lon, lat=~lat,
group = "Show All",
label = ~entrynames,
labelOptions = labelOptions(noHide = T,
#direction = ~MyDirection, #https://rstudio.github.io/leaflet/popups.html
textsize = ~textsizes,
#opacity=~opacity,
style = list(
"color"="black",
"font-family" ="sans-serif",
"box-shadow" = "3px 3px rgba(0,0,0,0.25)",
#"font-size" = "12px",
"border-color" = "rgba(0,0,0,0.5)"
)))
})
m
Similar to setting the direction of labels
There is a plug-in for Leaflet JS that allows to group the layers in the layer control. https://github.com/ismyrnow/Leaflet.groupedlayercontrol
This plug-in does not seem to exist for Leaflet R but I found this post saying that there is a way to use arbitraty Leaflet JS plug-in in Leaflet R.
https://gist.github.com/jcheng5/c084a59717f18e947a17955007dc5f92
I tried to apply this method to the Leaflet.groupedlayercontrol plug-in but did not succeed. Do you have any idea how I can possibly use this plug-in or any other way to group my layers in the layercontrol generated by Leaflet R? Thank you.
You definitely can do layer control in leafletR. If you version does not have it, then you need to update, probably from the most recent GITHUB version.
I am working on a map right now that has layer controls, see the photograph. Here is the code that makes it happen. As you can see each of the addPolygons has a group = " A Name" This is where you identify the layers in the check boxes on my image.
map<-leaflet()%>%
addTiles()%>%
addPolygons(data = plotMerge,
fillColor = ~pal(plotMerge$incomePerCapita),
color = "#000000", #this is an outline color
fillOpacity = 0.8,
group="Tract",
weight = 0.2,
popup=popup)%>%
addPolygons(data = countyPoly,
fillColor = "transparent",
color = "#000000", #this is an outline color
fillOpacity = 0.8,
group="County",
popup=countyPoly#data$NAME,
weight = 2)%>%
addPolygons(data = townPoly,
fillColor = "transparent",
color = "#000000", #this is an outline color
fillOpacity = 0.8,
group="Town",
weight = .8,
popup=townPoly#data$TOWN)%>%
addPolygons(data = rphnPoly,
fillColor = "transparent",
color = "#000000", #this is an outline color
fillOpacity = 0.8,
group="Public Health Region",
weight = .8,
popup=rphnPoly#data$PHN)%>%
addLegend(pal = pal,
values = plotMerge$incomePerCapita,
position = "bottomright",
title = "State-wide Income Percentiles",
labFormat = labelFormat(digits=1))%>%
addLayersControl(
overlayGroups =c("County", "Town", "Public Health Region", "Tract"),
options = layersControlOptions(collapsed=FALSE)
)
saveWidget(map, file="map1.html", selfcontained=FALSE)
Here is what it looks like:
You can also add other controls check it out here:
Leaflet R Hidden Layers
I know this is an old question but I didn't find a good answer elsewhere - this may help others in the future.
Here is a reprex with comments that explains the code:
#load library
library(tidyverse)
library(leaflet)
#load data
data("quakes")
#map all points
# quakes %>%
# leaflet() %>%
# addProviderTiles(providers$CartoDB.Positron) %>%
# addCircleMarkers(lng = ~long, lat = ~lat, radius = 1)
#create a grouping variable -- this can be whatever you want to filter by
quakes <- quakes %>%
mutate(groups = case_when(
stations < 30 ~ 1,
stations < 50 ~ 2,
TRUE ~ 3
))
#function to plot a map with layer selection
map_layers <- function() {
#number of groups
k <- n_distinct(quakes$groups)
#base map
map <- leaflet() %>%
addProviderTiles(providers$CartoDB.Positron)
#loop through all groups and add a layer one at a time
for (i in 1:k) {
map <- map %>%
addCircleMarkers(
data = quakes %>% filter(groups == i), group = as.character(i),
lng = ~long, lat = ~lat, radius = 1
)
}
#create layer control
map %>%
addLayersControl(
overlayGroups = c(1:k),
options = layersControlOptions(collapsed = FALSE)) %>%
hideGroup(as.character(c(2:k))) #hide all groups except the 1st one
}
#plot the map
map_layers()