I want to sync two maps in an R shiny web app(zooming in on one map should zoom in on the other map and panning etc), I managed to do this interactively using the code shown below but I can't figure out how to do this in a Shiny web app. Any help would be appreciated
my_map <- function(x){
m <- leaflet() %>%
addTiles() %>% # Add default OpenStreetMap map tiles
addMarkers(lng=x[1], lat=x[2], popup="The birthplace of R")
m
}
y <- c(174.968, 37.852)
x <- c(0.112281, 51.523001)
sync(my_map(x), my_map(y), no.initial.sync = TRUE)
Using sync() as an UI output, not as leafletOutput worked for me.
In ui:
uiOutput("synced_maps")
In server:
output$synced_maps <- renderUI({
m1 <- leaflet() %>% addTiles() %>% addMarkers(~lon1, ~lat1)
m2 <- leaflet() %>% addTiles() %>% addMarkers(~lon2, ~lat2)
sync(m1, m2)
})
Will the maps always be made prior to user interface creation? If so:
library(leaflet)
library(leafsync)
library(shiny)
my_map <- function(x){
m <- leaflet() %>%
addTiles() %>% # Add default OpenStreetMap map tiles
addMarkers(lng=x[1], lat=x[2], popup="The birthplace of R")
m
}
y <- c(174.968, 37.852)
x <- c(0.112281, 51.523001)
ui <- sync(my_map(x), my_map(y), no.initial.sync = TRUE)
server = function(input,output){
}
shinyApp(ui, server)
Edit:
In response to your comment, I have looked at options to sync maps including a javascript approach (https://github.com/jieter/Leaflet.Sync) and syncWith (https://github.com/rte-antares-rpackage/leaflet.minicharts). I have not spent time with these.
A quick workaround could be this below (one map's bounds matches the other map's bounds, but not vice versa). It requires adding observe to the server function and setting the bounds from one map to the other. From http://rstudio.github.io/leaflet/shiny.html:
input$MAPID_bounds provides the latitude/longitude bounds of the
currently visible map area; the value is a list() that has named
elements north, east, south, and west
library(leaflet)
library(leafsync)
library(shiny)
my_map <- function(x){
m <- leaflet() %>%
addTiles() %>% # Add default OpenStreetMap map tiles
addMarkers(lng=x[1], lat=x[2], popup="The birthplace of R")
m
}
y <- c(174.968, 37.852)
x <- c(0.112281, 51.523001)
ui <- fluidPage(
leafletOutput("mymap1"),
leafletOutput("mymap2")
)
server = function(input, output){
output$mymap1 = renderLeaflet({
my_map(x)
})
output$mymap2 = renderLeaflet({
my_map(y)
})
observe({
coords <- input$mymap1_bounds
if (!is.null(coords)) {
leafletProxy("mymap2") %>%
fitBounds(coords$west,
coords$south,
coords$east,
coords$north)
}
})
}
shinyApp(ui, server)
Related
below is my code. I have a working map that zooms into each county when clicked on but I want the map to be shaded darker or lighter based on how many zip codes are in a certain place and the count of data in each state.
Any help would be much appreciated!
require(leaflet)
require(maps)
require(maptools)
require(sp)
require(rgeos)
zipdata=data2$LossZipCode
statedata=data2$LossStateAbbreviation
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) {
#leafletOutput("myMap"),br(),leafletOutput("myMap2")
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)
})
})
})
I am trying to figure out how to zoom into a map based on user inputs. I have started with the map of the US and then trying zooming into a specific location based on zip code and number of miles:
shinyUI(fluidPage(
# Application title
titlePanel("Starbucks Locator"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
textInput("zip","Zip Code:", value = "18101"),
sliderInput("radius",
"Radius",
min = 1,
max = 25,
value = 15),
actionButton("go", "Submit")
),
# Show a plot of the generated distribution
mainPanel(
leafletOutput("myMap")
)
)
))
This is the Server Code:
library(shiny)
library(ZipRadius)
library(leaflet)
shinyServer(function(input, output) {
data <- reactive({x <- readRDS("Starbucks.rds")})
output$myMap <- renderLeaflet({
df <- data()
m <- leaflet(data = df) %>%
addTiles() %>%
addMarkers(lng = ~Lon, lat = ~Lat)
})
eventReactive(input$go, {
zip_include <- zipRadius(input$zip, input$radius)
})
leafletProxy("myMap") %>% fitBounds(~min(zip_include$longitude), ~min(zip_include$latitude),
~max(zip_include$longitude), ~max(zip_include$latitude))
})
I am using the ZipRadius package to find the which zip codes are input$distance away from input$zip. Then I want to zoom into the input zip code as the center and the bounds defined by the radius (input$distance). The original leaflet map works, but the leafletProxy is where I am having my issue. Any thoughts on how to do this? I am trying to use fitbounds since it can take into account minimum and maximum latitudes and longitudes. I think the issue may be with the eventReactive, but not sure how to test it. The dataset is available here at github.
There are a few issues with your server code.
You don't need to create your data in a reactive expression. As you only upload it once (I guess you won't change the coords or add another row).
Your renderLeaflet function can be simplified
Instead of using eventReactive use observeEvent. This function is triggered when you press the go button. In the observer you have to add all the actions that should be triggered by the button click. So you also have to insert the leafletProxy function here.
Remove the ~ symbol in the fitBounds function. You are already pointing to the zip_include dataset in fitBounds.
Working server (with provided csv)
shinyServer(function(input, output) {
data <- read.csv("c:/starbucks_us_locations.csv")
names(data) <- c('Lon', 'Lat')
output$myMap <- renderLeaflet({leaflet(data) %>%
addTiles() %>%
addMarkers(lng = ~Lon, lat = ~Lat)
})
observeEvent(input$go, {
zip_include <- zipRadius(input$zip, input$radius)
print(zip_include)
leafletProxy("myMap") %>% fitBounds(min(zip_include$longitude), min(zip_include$latitude),
max(zip_include$longitude), max(zip_include$latitude))
})
})
I solved my problem as Lauren.
Changing styles when selecting and deselecting multiple polygons with Leaflet/Shiny
The only difference is that I use polylines instead of polygons. I want to select multiple polylines und deselect them at click again. But it doesn't work..it deletes the reselected from the table but not from the map and after a line was deleted from my selected lines I can't select it anymore.
Can someone help me please!
Data
Here is my code:
library(shiny)
library(leaflet)
library(geojsonio)
url <- "pathTogeojson"
geojson <- geojsonio::geojson_read(url, what = "sp")
shinyApp(
ui <- fluidRow(
leafletOutput("map")),
server <- function(input, output, session) {
click_list <- reactiveValues(ids = vector())
output$map <- renderLeaflet({
leaflet() %>%
addTiles() %>%
setView(lng=16.357795000076294, lat=48.194883921677935, zoom = 15) %>%
addPolylines(data=geojson, layerId = geojson#data$name_1, group = "selected", color="red", weight=3,opacity=1)
})
observeEvent(input$map_shape_click, {
click <- input$map_shape_click
proxy <- leafletProxy("map")
click_list$ids <- c(click_list$ids, click$id)
sel_lines <- geojson[geojson#data$name_1 %in% click_list$ids, ]
if(click$id %in% sel_lines#data$id)
{
nameMatch <- sel_lines#data$name_1[sel_lines#data$id == click$id]
click_list$ids <- click_list$ids[!click_list$ids %in% click$id]
click_list$ids <- click_list$ids[!click_list$ids %in% nameMatch]
proxy %>% removeShape(layerId = click$id)
}
else
{
proxy %>% addPolylines(data = sel_lines, layerId = sel_lines#data$id, color="#6cb5bc", weight=5,opacity=1)
}
})
})
I found the solution by my own..my data and my incomprehension were the problem. It only works, when all used columns are type character...so i had to do a type conversion with as.character()
Working code:
ui <- shinyUI(bootstrapPage(
leafletOutput("map")
))
server <- shinyServer(function(input, output, session) {
## Make your initial map
output$map <- renderLeaflet({
leaflet() %>%
setView(lng = -86.779633, lat = 33.543682, zoom = 11) %>%
addTiles(options = providerTileOptions(noWrap = TRUE))
})
## Observe mouse click
observeEvent(input$map_click, {
## Get the click info like had been doing
click <- input$map_click
clat <- click$lat
clng <- click$lng
address <- revgeocode(c(clng,clat))
## Add the marker to the map proxy
leafletProxy('map') %>% # use the proxy to save computation
addMarkers(lng=clng, lat=clat,
popup=address)
})
})
shinyApp(ui=ui, server=server)
I would like to enhance the code above by calculating a statistic within a 5000m buffer of the clicked address...everything I try does not work. Am I missing something?
ui <- shinyUI(bootstrapPage(
leafletOutput("map")
))
server <- shinyServer(function(input, output, session) {
## Make your initial map
output$map <- renderLeaflet({
leaflet() %>%
setView(lng = -86.779633, lat = 33.543682, zoom = 11) %>%
addTiles(options = providerTileOptions(noWrap = TRUE))
})
## Observe mouse clicks and add circles
observeEvent(input$map_click, {
## Get the click info like had been doing
click <- input$map_click
clat <- click$lat
clng <- click$lng
address <- revgeocode(c(clng,clat))
I want to create a SPDF of the lng and lat from the click:
coords<-c(clat, clng)
crs <- "+init=epsg:26930" #' this is E Alabama
x_spdf <- spTransform(coords, CRSobj = crs)
Here I want to create a 5000m buffer around the clicked point
b_dist <- 5*1000
buffer_spdf <- gBuffer(x_spdf, width=b_dist, byid=T)
buffer <- gBuffer(x_spdf, width=b_dist)
This is my SPDF of office addresses I have on my computer that I want to convert to CRS for E Alabama
dent_spdf <- spTransform(split_dentist, CRSobj = crs)
Identify # of offices within buffer
office_in_buffer <- split_office[!is.na(sp::over(split_office, buffer)),]
office_in_buffer <- spTransform(dent_in_office, CRS=crs)
Count # of offices in buffer
num_office <- nrow(office_in_buffer)
Calculate statistic based on # offices in buffer
expenditure <-office_in_buffer#data$variable/ (num_office + 1)
output$expenditure <- renderText(revenue) #' tell Shiny to display this number
leafletProxy('map') %>% # use the proxy to save computation
addMarkers(lng=clng, lat=clat,
popup=address)
})
})
shinyApp(ui=ui, server=server)
I would like to build an animated map with a time cursor in R.
I have time series (xts) that I would like to represent on map.
library(xts)
library(leaflet)
date<-seq(as.POSIXct("2015-01-01"), as.POSIXct("2015-01-10"), by=86400)
a<-xts(1:10,order.by=date)
b<-xts(5:14,order.by=date)
df = data.frame(Lat = 1:10, Long = rnorm(10),Id=letters[1:10])
leaflet() %>% addCircles(data = df,popup =df$Id)
#popup =paste(df$Id, xts value) time cursor on the map
Is there a way to do this with the leaflet package?
I didn't try rmaps package yet.
Thanks
EDIT:https://github.com/skeate/Leaflet.timeline
There is a simple example
Library:
library(shiny)
library(xts)
library(leaflet)
library(dplyr)
Data:
date<-seq(as.Date("2015-01-01"), as.Date("2015-01-10"), by="day")
a<-xts(1:10,order.by=date)
df = data.frame(Lat = rnorm(1)+10, Long = rnorm(1),Id=a)
data_a<-data.frame(a)
data_a1<-data_a %>%
mutate("Lat" =as.numeric(df[1,1]),"Long"=as.numeric(df[2,1]),"Date"=rownames(data_a))
shinyapp:
ui <- fluidPage(
sliderInput("time", "date",min(date),
max(date),
value = max(date),
step=1,
animate=T),
leafletOutput("mymap")
)
server <- function(input, output, session) {
points <- reactive({
data_a1 %>%
filter(Date==input$time)
})
output$mymap <- renderLeaflet({
leaflet() %>%
addMarkers(data = points(),popup=as.character(points()$a))
})
}
shinyApp(ui, server)
If you add the following in the formula above, you can see the tiles
#in data
tilesURL <- "http://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}"
#in server replace
output$mymap <- renderLeaflet({
leaflet() %>%
addTiles(tilesURL)%>%
addMarkers(data = points(),popup=as.character(points()$a))
})