leaflet map of the world - exclude Antarctica - r

The code below is reproducible - it builds the map of the world using leaflet.
I am really not interested in Antarctica and I am more interested in Scandinavia :)
Any way to cut Antarctica or at least force it to be always at the bottom of the map - so that the center of the map is farther north?
Thanks a lot for any pointers!
library(leaflet)
library(rnaturalearth)
countries <- rnaturalearth::countries110
goodnames <- countries$name
goodnames[goodnames %in% goodnames[32]] <- "Ivory Coast"
countries$name[32] <- goodnames[32]
mymap <- leaflet(countries, options = leafletOptions(minZoom = 2))
myvalues <- 1:177
mycolors <- colorNumeric(palette = c("#fee6ce","#e6550d"),
domain = myvalues)(myvalues)
mymap %>%
addPolygons(stroke = FALSE, smoothFactor = 0.2, fillOpacity = 1,
color = ~mycolors,
label = countries$name)

You can use setView to set the initial viewing point to any location of your choosing. If you want this map to focus on Scandinavia on opening, you can do...
mymap <- leaflet(countries, options = leafletOptions(minZoom = 2)) %>% setView(lng=18.6435,lat=60.1282,zoom=2)
The coordinates are simply from searching 'Sweden coordinates' on Google. You can use a site such as https://www.latlong.net/ to help you pick an appropriate center point.

Unfortunately 'rnaturalearth' is not (yet) available fpr R 3.4.2 and I have just updated one second ago so I can't prove my answer. But as you're asking for any pointer -
I use the 'rworldmap' package and take out Antarctica by excluding it after the map is defined by the package.
According to this my suggestion to your code would be:
mymap <- mymap[-which(row.names(mymap)=='Antarctica'),]

Related

Crosstalk: filter Polylines in Leaflet

I can't get crosstalk to work with leaflet and Polylines - here is an MWE:
library(crosstalk)
library(leaflet)
theta <- seq(0, 2*pi, len = 100)
dat <- data.frame(
lon = cos(theta),
lat = sin(theta),
t = 1:100
)
sd <- SharedData$new(dat)
map <- leaflet() %>%
addTiles() %>%
addCircleMarkers(data = sd, lat = ~lat, lng = ~lon, color = "blue") %>%
addPolylines(data = sd, lat = ~lat, lng = ~lon, color = "blue")
bscols(
filter_slider("t", "Time", sd, column = ~t),
map
)
The time filter_slider applies to the circle markers but not the polylines.
Happy to having a go at fixing this in the R leaflet package if someone can point me in the right direction. I.e. what would be required to change / implement? I assume the support is missing on the javascript side as of now?
UPDATE: Good News!
#dmurdoch has submitted a pull request to add support for polylines and polygons.
Using his version of crosstalk, you can now filter leaflet lines/polygons if they're sp objects (note, it doesn't seem to work with sf yet).
First you will need to install this version of crosstalk:
devtools::install_github("dmurdoch/leaflet#crosstalk4")
Then you will need to make sure your features are Spatial objects, easy using rgdal or raster:
shapes_to_filter <- raster::shapefile("data/features.shp") # raster import to 'Spatial Object'
shapes_to_filter <- rgdal::readOGR("data/features.shp") # rgdal import to 'Spatial Object'
Or, if you use sf and dplyr for most spatial tasks (like me) convert an sf object to Spatial:
library(dplyr)
library(sf)
shapes_to_filter <- st_read("data/features.shp") %>% as('Spatial') # sf import to 'Spatial Object'
Then create an sd object for leaflet, and a data frame copy for the filters (IMPORTANT: note how the group for sd_df is set using the group names from the sd_map) :
library(crosstalk)
sd_map <- SharedData$new(shapes_to_filter)
sd_df <- SharedData$new(as.data.frame(shapes_to_filter#data), group = sd_map $groupName())
Create crosstalk filters using sd_df:
filter_select("filterid", "Select Filter Label", sd_df, ~SomeColumn)
Create the map using the sd_map object:
library(leaflet)
leaflet() %>%
addProviderTiles("OpenStreetMap") %>%
addPolygons(data = sd_map)
And any linked tables/charts need to also use the sd_df object:
library(DT)
datatable(sd_df)
Here's all of the sources for the solution:
GitHub Issue
Github pull request from dmurdoch to add support for polygons/lines
Original solution - with outdated method "sd$transform"
Updated example - with the new "group" method, but I couldnt get their RMD to work
As previously mentioned by Bhaskar Karambelkar:
"crosstalk for now works only with markers and not polylines/polygons"
I hope this changes soon.

How to plot polylines in multiple colors in R?

I'm working on a custom route planner in R at the moment. I'm using the output of the Google Maps Directions API. I want to show the route on a map between two places. Everything is going great so far. The only problem is that I don't know how to give the route multiple colors based on Speed at the moment. I searched the internet for a few days and I couldn't find something that fits my goal. That's why I made this post.
Then I visualized it in Leafet with te following code:
#install.packages("leaflet")
library(leaflet)
pal <- colorNumeric(
palette = unique(polyline$Col),
domain = polyline$Speed,
na.color = "#FFFFFF"
)
rm(map)
map <- leaflet()
map <- addTiles(map)
a <- 1
for(a in length(unique(polyline$Step_ID))){
map <- addPolylines(map,lng = polyline$Lon,
lat = polyline$Lat,
data = polyline[polyline$Step_ID==a,],
color = polyline$col)
a <- a + 1
}
map <- addLegend(map,"bottomright", pal = pal, values = polyline$Speed,
title = "Speed",
opacity = 1)
map
So far I think you have to create multiple PolyLines(correct me if I'm wrong) to plot multiple colors in the route. That's why I made a for loop, to add ever PolyLine into the map.
Everthing is just how want it. The only problem is the coloring of the line. I want the coloring of the lines just like Google does with traffic.
Can someone help me out with this please?
To fully replicate your question you need to provide us with the actual data for polyline (i.e, not a screenshot). Until then, I'm going to create my own data set and show you how to create the coloured lines.
And, as you're using Google's API to get the directions, I'm assuming you'll have an API key, so I'm going to show you how to do it using my googleway package
library(googleway)
api_key <- "your_api_key"
directions <- google_directions(origin = "St Kilda, Melbourne, Australia",
destination = "Geelong, Victoria, Australia",
key = api_key)
## the results of the API give you distance in metres, and time in seconds
## so we need to calculate teh speed
spd <- (directions$routes$legs[[1]]$steps[[1]]$distance$value / 1000) / (directions$routes$legs[[1]]$steps[[1]]$duration$value/ 60 / 60)
## then we can start to build the object to use in the plot
## and as we are staying within Google's API, we can use the encoded polyline to plot the routes
## rather than extracting the coordinates
df <- data.frame(speed = spd,
polyline = directions$routes$legs[[1]]$steps[[1]]$polyline)
df$floorSpeed <- floor(df$speed)
colours <- seq(1, floor(max(df$speed)))
colours <- colorRampPalette(c("red", "yellow","green"))(length(colours))
df <- merge(df,
data.frame(speed = 1:length(colours),
colour = colours),
by.x = "floorSpeed",
by.y = "speed")
map_key <- "your_map_api_key"
google_map(key = map_key) %>%
add_polylines(data = df, polyline = "points", stroke_colour = "colour",
stroke_weight = 5, stroke_opacity = 0.9)
See this answer for a way of making the route planner in Shiny.

Remove unused GEOID in geo_join

I am attempting to plot profitability on top of counties in Minnesota, Iowa, and Nebraska. Using leaflet and tigris, I have been able to plot ALL counties, whether or not I have data for it. This leaves me with a few counties with colors and the rest labeled as NA. Is there a way for me to remove all NA's from my geo_join data so that it just isn't used ala unused Wisconsin areas? I have tried using fortify, but I can't figure out how to determine what county boundaries I'm looking at when I merge the TIGER boundary lines with my County FIPS file in order to remove them.
Here is what my leaflet currently looks like:
My code to get the map is this:
library(tigris)
library(leaflet)
pal <- colorNumeric(c("yellow","dark red"),county$Construction.Cost,na.color="white")
IA_counties <- counties(state="IA", cb=TRUE, resolution ="20m")
MN_counties <- counties(state="MN",cb=TRUE,resolution="20m")
NE_counties <- counties(state="NE",cb=TRUE,resolution="20m")
IA_merged <- geo_join(IA_counties,county,"GEOID", "GEOID")
MN_merged <- geo_join(MN_counties,county,"GEOID","GEOID")
NE_merged <- geo_join(NE_counties,county,"GEOID","GEOID")
popupIA <- paste0("County Projects: ", as.character(paste('$',formatC(format(round(IA_merged$Construction.Cost, 0), big.mark=',', format = 'f')))))
popupMN <- paste0("County Projects: ", as.character(paste('$',formatC(format(round(MN_merged$Construction.Cost, 0), big.mark=',', format = 'f')))))
popupNE <- paste0("County Projects: ", as.character(paste('$',formatC(format(round(NE_merged$Construction.Cost, 0), big.mark=',', format = 'f')))))
leaflet() %>%
addProviderTiles("MapQuestOpen.OSM") %>%
addLegend(pal = pal,
values = IA_merged$Construction.Cost,
position = "bottomright",
title = "County Projects",
labFormat=labelFormat(prefix="$")) %>%
addCircles(lng=yup2$lon, lat=yup2$lat,weight=.75,fillOpacity=0.01,color="red",
radius = 96560) %>%
addCircles(lng=yup2$lon, lat=yup2$lat,weight=.75,fillOpacity=0.01,color="blue",
radius = 193121) %>%
addPolygons(data = IA_counties,
fillColor = ~pal(IA_merged$Construction.Cost),
layerId=1,
fillOpacity = .25,
weight = 0.05,
popup = popupIA)%>%
addPolygons(data=MN_counties,
fillColor=~pal(MN_merged$Construction.Cost),
fillOpacity=0.25,
weight=0.05,
popup = popupMN) %>%
addPolygons(data=NE_counties,
fillColor=~pal(NE_merged$Construction.Cost),
fillOpacity=0.25,
weight=0.05,
popup = popupNE)
I apologize for not including reproducible data, but if needed, please ask. I'm hoping that this is more of a simple na.color= formula solution. The map looks "okay" as of now, but I'd like it if it's possible to not have to make the fillOpacity so light so the NA counties don't stand out.
Thanks for any and all help and please, let me know if you have any questions!
I'm the creator of the tigris package. Thanks so much for using it! In the development version of tigris on GitHub (https://github.com/walkerke/tigris), I've added an option to geo_join to accommodate inner joins, which would remove the unmatched data entirely from the resultant spatial data frame (if this is what you are looking for). You can also supply a common merge column name as a named argument to the new by parameter if you want. For example:
IA_merged <- geo_join(IA_counties, county, by = "GEOID", how = "inner")
should work. I'm still testing but I'll probably submit this update to CRAN in January.
So, embarrassingly, the answer to this question was as simple as I had hoped. I tweaked the following na.color code and it worked exactly as I wanted.
pal <- colorNumeric(c("yellow","dark red"),county$Construction.Cost,na.color="transparent")

R Leaflet doesn't add all markers

I'm trying to follow the example in the link below to create a map with all the markers
Tutorial: How to put dots on a Leaflet map with R
The source file is below
https://www.dropbox.com/s/az1yolknqwoxhb4/test_file.csv?dl=0
And the code that I tried
library(dplyr)
library(leaflet)
test_map <- read.csv("test_file.csv", header = TRUE, stringsAsFactors = FALSE)
m <- leaflet(test_map) %>% addTiles('http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
attribution='Map tiles by Stamen Design, CC BY 3.0 — Map data © OpenStreetMap')
m %>% setView()
m %>% addCircles(~long, ~lat,
popup=test_map$index,
weight = 3,
color="#ffa500", stroke = TRUE, fillOpacity = 0.8)
I was able to create the map
However, the map only shows a fraction of points, since the data I have has locations all over Canada. When I tried to sub-select a city say like Toronto then some of the missing points shows up.
I'm not sure if i'm doing anything wrong or if this is a bug.I wonder if there's anyway for me to fix this problem or is there an alternative way to achieve a similar map?
Thank you :)
There are NA values in test_map variable.
add
test_map <- na.omit(test_map)
after reading csv.
By this method i have more markers than your image.

Zooming into State to view ZipCode using R Leaflet

I am using R leaftlet package to create a interactive choropleth of the U.S.
There are several tutorials online and I am able to create interactive state level map with popups and zooming. Also I was also able to create a separate zip code level map again with popups.
I would like both views in one map itself but make zip code visible as I zoom in a state or double click on a state. Like If I double click on New York, the New York Zip Code opens up. Is there a package/function in R that can help me do this?
Here are static screenshots of both to make things clear what I plan to integrate.
I agree with Yehoshapat Schellekens that in R one might not have the flexibility of a web programming language. But seldom R is not flexible enough to achieve fancy results! :) Here you go with a "vanilla" example of what you basically need. You can customize the windows popup with some JS.
library(shiny)
library(leaflet)
library(maps)
library(maptools)
library(sp)
library(rgeos)
mapStates = map("state", fill = TRUE, plot = FALSE)
mapCounty = map("county", fill = TRUE, plot = FALSE)
shinyApp(
ui = fluidPage(leafletOutput('myMap'),
br(),
leafletOutput('myMap2')),
server <- function(input, output, session) {
output$myMap <- renderLeaflet({
leaflet() %>%
addProviderTiles("Stamen.TonerLite",
options = providerTileOptions(noWrap = TRUE)) %>%
addPolygons(lng = mapStates$x,
lat = mapStates$y,
fillColor = topo.colors(10, alpha = NULL),
stroke = FALSE)
})
observeEvent(input$myMap_shape_click, {
click <- input$myMap_shape_click
if(is.null(click))
return()
lat <- click$lat
lon <- click$lng
coords <- as.data.frame(cbind(lon, lat))
point <- SpatialPoints(coords)
mapStates_sp <- map2SpatialPolygons(mapStates, IDs = mapStates$names)
i <- point [mapStates_sp, ]
selected <- mapStates_sp [i]
mapCounty_sp <- map2SpatialPolygons(mapCounty, IDs = mapCounty$names)
z <- over(mapCounty_sp, selected)
r <- mapCounty_sp[(!is.na(z))]
output$myMap2 <- renderLeaflet({
leaflet() %>%
addProviderTiles("Stamen.TonerLite",
options = providerTileOptions(noWrap = TRUE)) %>%
addPolygons(data=r,
fillColor = topo.colors(10, alpha = NULL),
stroke = FALSE)
})
})
})
NOTE: The datasets used in the example seem to have different accuracies (not perfect overlap for states and counties). Therefore the spatial matching is accounting for more counties than expected (those inside plus those intersecting the state borders). Use the name as ID instead to achive the perfect match.
I've created the same type of app working off of G. Cocca's code, and after a few months of fiddling with it over and over, I've come up with a more elegant solution to your problem. For simple reproducibility, I'm using Rwanda shapefiles as an example (because they're much smaller than GADM's USA shapefiles, but you can always just replace these with your own US shapefiles).
library(raster)
library(shiny)
library(leaflet)
library(RColorBrewer)
#load in shapefiles for state and county level
states <- getData("GADM", country = "rwa", level = 1)
counties <- getData("GADM", country = "rwa", level = 2)
#define color palettes for states
pal <- brewer.pal(8, "Dark2")
statePal <- colorFactor(pal, states#data$NAME_1)
shinyApp(
ui = fluidPage(
leafletOutput('myMap', width = "100%"),
br(),
leafletOutput("myMap2", width = "100%")
), #END UI
server <- function(input, output, session){
#default state level map output
output$myMap <- renderLeaflet({
leaflet() %>%
addTiles() %>%
addPolygons(data = states,
fillColor = ~statePal(states#data$NAME_1),
fillOpacity = 1,
color = "white",
stroke = T,
weight = 1,
layerId = states#data$NAME_1) #this sets the click id, very important!
}) #END RENDERLEAFLET OUTPUT
observeEvent(input$myMap_shape_click, {
#define click object
click <- input$myMap_shape_click
#subset counties shapefile so that only counties from the clicked state are mapped
selected <- counties[counties$NAME_1 == click$id,]
#define color palette for counties
countyPal <- colorFactor(pal, selected#data$NAME_2)
#if click id isn't null (i.e. if ANY polygon is clicked on), draw map of counties
if(!is.null(click$id)){
output$myMap2 <- renderLeaflet({
leaflet() %>%
addTiles() %>%
addPolygons(data = selected,
fillColor = ~countyPal(selected#data$NAME_2),
fillOpacity = 1,
color = "white",
stroke = T,
weight = 1)
}) #END RENDERLEAFLET
} #END CONDITIONAL
}) #END OBSERVE EVENT
}) #END SHINYAPP
The first output is your state level map. With this code, when you click on a state of interest, a click object is created that has a click$id corresponding the name of that state (which is established in the layerId definition in the addPolygons call). With the click$id as the selected state name, you can then subset your county level polygon by that state and plot it as a map.
The options for designing this map are endless, really. Hope this helps!
You wont be able to create this through R, you need to run this through good old java Script, and specifically leaflet.
Keep in mind that R does not run the map, all it does is to create a java-script template of an HTML file, your Web browser runs the rest (Not R interpreter)
The professional word you are looking for is event binding, which on one click will trig both zooming in your original US map, and open a new map of a state with its zip code.
General instructions (this is all java script, no R!):
go to http://leafletjs.com/reference.html and find events, you need the dblclick event.
Then you'll need to create a function that opens up a new map.
keep in mind that if you want to do sophisticated stuff, R will give you very limited solutions, so my advice is when you need nice java script visualizations just go straight to the source :)
Your requirement needs lot of customization. If you are good in JavaScript just check geojson2svg that gives lot of flexibility. Basically it converts GeoJSON to SVG, that's all then rest you can achieve with plain HTML and JavaScript. Here are some examples.

Resources