I'm trying to make a simple map with Leaflet in R Markdown. I used standard deviation classification method to divide the data into 4 classes. When it produces the map, the colors on the map appear much lighter than what they should be. What is the problem here ? Thank you!
library(rgdal)
library(leaflet)
library(readr)
STCOU<- readOGR("H:/SP/STCOU.shp", "STCOU", GDAL1_integer64_policy = TRUE)
UNGEOCODED <- read_csv("H:/SP/UNGEOCODED.csv")
palette1 <- colorBin(c('#f1eef6','#bdc9e1','#74a9cf','#0570b0'),bins = c(0,1600, 3400, 5200, 32000),pretty = FALSE)
palette2 <- colorBin(c('#ece7f2','#a6bddb','#2b8cbe'),bins = c(0,1816, 3821, 35781),pretty = FALSE)
popup1<-paste("2015 Ungeocoded Tallies",
"<br>GEO_ID: ",
STCOU$GEOID,
"<br>State: ",
STCOU$STATEFP,
"<br>County: ",
STCOU$COUNTYFP,
"<br>Name: ",
STCOU$NAME,
"<br>LSAD: ",
STCOU$LSAD,
"<br>CensusArea: ",
STCOU$ALAND,
"<br>Current_UNGEO_Counts: ",
STCOU$CURRENT_UN,
"<br>Fall15_UNGEO_Counts: ",
STCOU$FAL15_UNGE)
popup2<-paste("2016 Ungeocoded Tallies",
"<br>GEO_ID: ",
STCOU$GEOID,
"<br>State: ",
STCOU$STATEFP,
"<br>County: ",
STCOU$COUNTYFP,
"<br>Name: ",
STCOU$NAME,
"<br>LSAD: ",
STCOU$LSAD,
"<br>CensusArea: ",
STCOU$ALAND,
"<br>Current_UNGEO_Counts: ",
STCOU$CURRENT_UN,
"<br>Fall15_UNGEO_Counts: ",
STCOU$FAL16_UNGE)
```
### Ungeocoded 2015 2016
```{r}
leaflet() %>%
setView(lng = -94.308561, lat = 38.561161, zoom=5) %>%
addProviderTiles("Esri.WorldGrayCanvas",
options = tileOptions()) %>%
addPolygons(data=STCOU,weight=0.1,
fillColor = ~palette1(UNGEOCODED$FAL15_UNGE),
popup = popup1,
group="<span style='color: #7f0000; font-size: 11pt'><strong>2015</strong></span>")%>%
addPolygons(data=STCOU,weight=0.1,
fillColor = ~palette2(UNGEOCODED$SPR16_UNGE),
popup=popup2,
group="2016") %>%
addLayersControl(baseGroups = c("<span style='color: #7f0000; font-size: 11pt'><strong>2015</strong></span>",
"2016"), options = layersControlOptions(collapsed =FALSE))%>%
addLegend(position = 'topleft',
colors = c('#f1eef6','#bdc9e1','#74a9cf','#0570b0'),
labels = c('Low'," "," ","High"),
opacity = 0.6,
title = "2015 2016 Ungeocoded")
```
Basically you just need to read the docs on the various addLayers functions in leaflet package and you'll see that fillOpacity is set to 0.2 as the default. This is to save you from yourself when features overlap, but you can definitely set the parameter higher, i.e.
Minimal Reproducible Example + Answer -->
library(leaflet)
df <- data.frame(
lon = sample(seq(-94.9, -93.1, 0.00001), 10, replace = T),
lat = sample(seq(38.1, 39.9, 0.00001), 10, replace = T),
value = sample(density(c(0,1600, 3400, 5200, 32000))$x, 10)
)
palette1 <- colorBin(c('#f1eef6','#bdc9e1','#74a9cf','#0570b0'), bins = c(0,1600, 3400, 5200, 32000), pretty = FALSE)
leaflet(df) %>%
setView(lng = -94.308561, lat = 38.561161, zoom=7) %>%
addProviderTiles("Esri.WorldGrayCanvas") %>%
addCircleMarkers(
weight=0.1,
fillOpacity = 0.7,
fillColor = ~palette1(value)
)
Related
With the code below I get my dataframe with US county data
library(raster)
library(leaflet)
library(tidyverse)
# Get USA polygon data
USA <- getData("GADM", country = "usa", level = 2)
### Get data
mydata <- read.csv("https://www.betydb.org/miscanthus_county_avg_yield.csv",
stringsAsFactors = FALSE)
My object is to crate an interactive leaflet choropleth map of Avg_yield so first I fortify my USA polygon data
library(rgeos)
library(maptools)
library(ggplot2)
states.shp.f <- fortify(USA, region = "NAME_2")
Then I subset my dataset and merge it with the fortified:
mydata2<-mydata[,c("COUNTY_NAME","Avg_yield")]
colnames(mydata2)[1]<-"id"
## merge shape file with data
merge.shp.coef <- merge(states.shp.f, mydata2, by = "id")
but now I have a dataset with every county name many times and also some counties have different values of Avg_yield. Whats the proper way to process those data in order to use the leaflet code like:
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
setView(lat = 39.8283, lng = -98.5795, zoom = 4) %>%
addPolygons(data = USA, stroke = FALSE, smoothFactor = 0.2, fillOpacity = 0.3,
fillColor = ~mypal(mydata$Avg_yield),
popup = paste("Region: ", USA$NAME_2, "<br>",
"Avg_yield: ", mydata$Avg_yield, "<br>")) %>%
addLegend(position = "bottomleft", pal = mypal, values = mydata$Avg_yield,
title = "Avg_yield",
opacity = 1)
The propoer way to do this is to transform your polygon object into a sf object
with st_as_sf()
Here you have a working example :
(I did used some other data for the polygon, I thought yours too precise and require a lot of resources, plus I made it work with shiny)
library(leaflet)
library(tidyverse)
library(ggplot2)
library(sf)
library(shiny)
USA <- st_read(dsn = '[your path]/cb_2018_us_county_500k.shp')
### Get data
mydata <- read.csv("https://www.betydb.org/miscanthus_county_avg_yield.csv",
stringsAsFactors = FALSE)
states_sf <- st_as_sf(USA)
mydata2<-mydata[,c("COUNTY_NAME","Avg_yield")]
colnames(mydata2)[1]<-"NAME"
## merge shape file with data
states_sf_coef <- left_join(states_sf, mydata2, by = "NAME")
ui <- fluidPage(
leafletOutput("map", height = "100vh")
)
server <- function(input, output, session) {
bins <- c(0, 5, 10, 15, 20, 25, 30, 35, 40)
mypal <- colorBin("YlOrRd", domain = states_sf_coef$Avg_yield, bins = bins)
#Sortie map
output$map <- renderLeaflet({
leaflet()%>%
addProviderTiles("OpenStreetMap.Mapnik")%>%
setView(lat = 39.8283, lng = -98.5795, zoom = 4) %>%
addPolygons(
data = states_sf_coef,
fillColor = ~mypal(states_sf_coef$Avg_yield),
stroke = FALSE,
smoothFactor = 0.2,
fillOpacity = 0.3,
popup = paste("Region: ", states_sf_coef$NAME_2, "<br>",
"Avg_yield: ", states_sf_coef$Avg_yield, "<br>"))%>%
addLegend(position = "bottomleft",
pal = mypal,
values = states_sf_coef$Avg_yield,
title = "Avg_yield",
opacity = 1)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
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)
I am trying to plot few countries using leaflet but the countries that it is showing is incorrect. Following is my minimal reproducible example:
library(leaflet)
library(maps)
df <- data.frame(name = c("Afghanistan", "Albania" , "Algeria" , "Armenia"),
code = c("AFG", "ALB", "DZA", "ARM"),
val = c(5, 10, 15, 20), stringsAsFactors = FALSE)
pal <- colorNumeric(
palette = "Blues",
domain = as.numeric(df$val))
labels <- sprintf(
"<strong>Country:%s</strong><br/>Value:%g /",
df$name, df$val)%>% lapply(htmltools::HTML)
Country = map("world", fill = TRUE, plot = FALSE, regions=iso.expand(df$code,regex = TRUE))
leaflet(Country) %>% addTiles() %>%
addPolygons(fillOpacity = 0.6, smoothFactor = 0.5, stroke = TRUE, weight = 1,
color = ~pal(as.numeric(df$val)),
label = labels)
I get the following leaflet with this:
As you can see Algeria is shown as Albania. If I remove the Armenia from my data and plot the leaflet I get correct location. Following is the code and image for that.
library(leaflet)
library(maps)
df <- data.frame(name = c("Afghanistan", "Albania" , "Algeria" ),
code = c("AFG", "ALB", "DZA"),
val = c(5, 10, 15), stringsAsFactors = FALSE)
pal <- colorNumeric(
palette = "Blues",
domain = as.numeric(df$val))
labels <- sprintf(
"<strong>Country:%s</strong><br/>Value:%g /",
df$name, df$val)%>% lapply(htmltools::HTML)
Country = map("world", fill = TRUE, plot = FALSE, regions=iso.expand(df$code,regex = TRUE))
leaflet(Country) %>% addTiles() %>%
addPolygons(fillOpacity = 0.6, smoothFactor = 0.5, stroke = TRUE, weight = 1,
color = ~pal(as.numeric(df$val)),
label = labels)
Am I missing something?
I think the issue is related to the polygons order in map object (if you set label = Country$names, the labels are now correct). Anyway, you can solve the problem by converting Country into a SpatialPolygons object (see here).
library(maptools)
IDs <- sapply(strsplit(Country$names, ":"), function(x) x[1])
Country <- map2SpatialPolygons(Country,
IDs=IDs,
proj4string=CRS("+proj=longlat +datum=WGS84"))
leaflet(Country) %>% addTiles() %>%
addPolygons(fillOpacity = 0.6, smoothFactor = 0.5, stroke = TRUE, weight = 1,
color = pal(as.numeric(df$val)),
label = labels)
I am working with the leaflet R package. I have a zoning system made of polygons and I'd like to lay their IDs on top of them. Below is an illustration (with another software) of my objective.
Thanks for your suggestions!
Since there is no reproducible data, I decided to use one of my previous posts related to leaflet. There are two things you want to take away from this post: 1) you need to create a data frame containing center points of target regions, 2) you need to use addLabelOnlyMarkers(). You can achieve the first thing using gCentroid(). I added row names of the polygon data set (UK) as character to centers. This is used for labeling. You need to think what labels you use in your own case. Once this data set is ready, you want to use it in addLabelOnlyMarkers().
library(raster)
library(rgeos)
library(leaflet)
# Get UK polygon data
UK <- getData("GADM", country = "GB", level = 2)
# Find a center point for each region
centers <- data.frame(gCentroid(UK, byid = TRUE))
centers$region <- row.names(UK)
### Create dummy data
set.seed(111)
mydf <- data.frame(place = unique(UK$NAME_2),
value = sample.int(n = 1000, size = n_distinct(UK$NAME_2), replace = TRUE))
### Create five colors for fill
mypal <- colorQuantile(palette = "RdYlBu", domain = mydf$value, n = 5, reverse = TRUE)
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
setView(lat = 55, lng = -3, zoom = 6) %>%
addPolygons(data = UK,
stroke = FALSE, smoothFactor = 0.2, fillOpacity = 0.3,
fillColor = ~mypal(mydf$value),
popup = paste("Region: ", UK$NAME_2, "<br>",
"Value: ", mydf$value, "<br>")) %>%
addLabelOnlyMarkers(data = centers,
lng = ~x, lat = ~y, label = ~region,
labelOptions = labelOptions(noHide = TRUE, direction = 'top', textOnly = TRUE)) %>%
addLegend(position = "bottomright", pal = mypal, values = mydf$value,
title = "UK value",
opacity = 0.3)
Suppose you have the following data frame:
cities = data.frame( name = c('Madrid','Barcelona','Sevilla'),
country = c('Spain','Spain','Spain'),
region = c('Comunidad de Madrid','Cataluña','Andalucia'),
data = c(100, 200, 300),
lng = c(-3.683333,2.166667,-6.083333),
lat = c(40.433333,41.383333,37.446667))
My idea is to have a map of these cities and labels that could display some relevant information when hovering the corresponding city circles. I'd like to have the label text arranged in several lines. The very first approach below failed:
library( leaflet )
map = leaflet( cities ) %>%
addTiles() %>%
addCircles( lng = ~lng, lat = ~lat, fillColor = 'darkBlue', radius = 10000,
stroke = FALSE, fillOpacity = 0.8, label = paste0( cities$name,'\n', cities$region, '\n', cities$country, '\n', cities$data ) )
as well as other similar attempts. After googling a while, I found a possible solution by involving the htmltools package:
library( htmltools )
map2 = leaflet( cities ) %>%
addTiles() %>%
addCircles( lng = ~lng, lat = ~lat, fillColor = 'darkBlue', radius = 10000,
stroke = FALSE, fillOpacity = 0.8,
label = HTML( paste0( '<p>', cities$name, '<p></p>', cities$region, ', ', cities$country,'</p><p>', cities$data, '</p>' ) ) )
In this case, the information is displayed as I'd like but, within the same label, there is an entry for each city of the dataset. How could I do to have the text of a single city arranged in multiple lines? Any help would be really appreciated
First, create a character vector of html content for each city and then wrap that in a lapply call to set the HTML attribute for correct display when defining the label attribute in adCircles
labs <- lapply(seq(nrow(cities)), function(i) {
paste0( '<p>', cities[i, "name"], '<p></p>',
cities[i, "region"], ', ',
cities[i, "country"],'</p><p>',
cities[i, "data"], '</p>' )
})
map2 = leaflet( cities ) %>%
addTiles() %>%
addCircles(lng = ~lng, lat = ~lat, fillColor = 'darkBlue', radius = 10000,
stroke = FALSE, fillOpacity = 0.8,
label = lapply(labs, htmltools::HTML))
map2
The following also works for two labels:
labels <- sprintf(
"<strong>%s</strong><br/>%g people / mi<sup>2</sup>",
states$name, states$density
) %>% lapply(htmltools::HTML)
m <- m %>% addPolygons(
fillColor = ~pal(density),
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto"))
m
see here for further info.
p.s: I wanted to use it for three labels but couldn't manage to.