Good afternoon everyone, I think a screenshot will tell better than words:
I would like a real marker instead of what is actually printed...
Here is the corresponding server.R part of the code (where fixed_points is a nrow(fixed_points) x 2 matrix with lat/lon coordinates
library(shiny); library(rCharts); library(leaflet)
output$baseMap <- renderMap({
baseMap <- Leaflet$new()
baseMap$setView(c(lng = 2.812500, lat = 46.732331), zoom = 6)
baseMap$tileLayer(provider = "Stamen.TonerLite")
for (i in 1:nrow(fixed_points)) {baseMap$marker(c(fixed_points[i, "lat"], fixed_points[i, "lon"]))}
baseMap$fullScreen(TRUE)
baseMap
})
and the ui.R
showOutput("baseMap", "leaflet") // or chartOuput(...), it works the same
Thanks in advance!
Related
I have a global database of grid ID, lat and long at 100-km resolution and associated
data for each 100-km grid. Something like this
grid_ID Lat Lon data1 data2 data3 ... data4
I want to develop a shiny app that allows the user to:
click anywhere on the map
return corresponding lat and lon
based on the returned lat and lon, find which 100-km grid does it fall into
show the data associated with that 100-km grid as a pop-up window or as a table (either will do)
library(shiny)
library(leaflet)
library(shinythemes)
ui <- fluidPage(theme = shinytheme('superhero'),
leafletOutput("map"),
verbatimTextOutput("out")
)
server <- function(input, output, session) {
output$map <- renderLeaflet({
leaflet() %>% addProviderTiles('Esri.WorldImagery')
})
output$out <- renderPrint({
validate(need(input$map_click, FALSE))
str(input$map_click)
})
}
shinyApp(ui, server)
This is now returning lat and long of the location that I clicked on which is my
step 1 and 2. How do I go about doing step 3 and 4. For step 3, usually if it was not an shiny app, I would do
coordinates(dat) <- ~ Longitude + Latitude
proj4string(dat) <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
GRID <- over(dat, grid_shp)
where grid_shp is my global 100-km grid shapefile and dat has the returned lat lon from the click.
Probably not the most elegant solution and also not sure if it's in leaflet for R, but you could define each grid rectangle as a polygon, loop through the polygons and do if(Polygon.getBounds().contains(LatLng) == true); then you know which grid square you're in. Then return the feature properties of the grid square aka polygon object.
I assume your dataset is called "data". You have to find the grid which intersects with the coordinates of the click.
library(shiny)
library(leaflet)
library(shinythemes)
ui <- fluidPage(theme = shinytheme('superhero'),
leafletOutput("map"),
verbatimTextOutput("out"))
server <- function(input, output, session) {
output$map <- renderLeaflet({
leaflet() %>% addProviderTiles('Esri.WorldImagery')
})
output$out <- renderPrint({
validate(need(input$map_click, FALSE))
str(input$map_click)
# create a dataframe from the clicked point
xy <-
data.frame(longitude = input$map_click$lng,
latitude = input$map_click$lat)
# transform this dataframe to spatialpointsdataframe
spdf <-
SpatialPointsDataFrame(
coords = xy,
data = xy,
proj4string = CRS("+proj=longlat +datum=WGS84 +no_defs")
)
# find the grid that intersects with the point
selected_raster <- spdf %over% data
# here you will see the information you need
as.data.frame(selected_raster)
})
}
shinyApp(ui, server)
I would like to add local tiles for leaflet to render them offline in a shiny application.
Although there are solutions to this on SO for example here and here , I am still ending up with grey map with no tiles. It would really help me to see some reproducible example.
Thanks.
My example code:
library(shiny)
library(dplyr)
library(RgoogleMaps)
#downloads tiles for a given regions, saves it to C:/Users/.../mapTiles/OSM
for (zoom in 0:16)
GetMapTiles(center = c(lat = 52.431635, lon = 13.194773),
zoom = zoom,
nTiles = round(c(20,20)/(17-zoom)))
#shiny ui
ui = fluidPage(leafletOutput("map"))
#create basic map, load tiles from directory and set view to centre of downloaded tiles
server = function(input, output, server){
addResourcePath(prefix = "OSM", "C:/Users/.../mapTiles")
output$map = renderLeaflet({
leaflet() %>%
addTiles( urlTemplate = "/OSM/{z}_{x}_{y}.png") %>%
setView(52.431635, 13.194773 , zoom = 10) %>% #set to the location with tiles
addMarkers(52.431635, 13.194773 )
}
)
}
shinyApp(ui, server)
In my case, I create my own tiles via gdal2tiles, which takes your data and automatically creates a {z}/{x}/{y}.png folder structure. Please see this link for a nice tutorial and what i mean about the file structure;
+---14
| +---8185
| +---5460.png
| +---5461.png
| +---etc.png
| \---8186
# I use the following server (see how my addTiles has a folder structure)
server <- function(input, output,session) {
addResourcePath("mytiles", "C:/.../tiles")
output$tilemap <- renderLeaflet({
leaflet() %>%
setView(lng = -4.4, lat = 52, zoom = 12) %>%
addTiles(urlTemplate = "mytiles/{z}/{x}/{y}.png")
})
}
Now, as you are downloading tiles from Google Maps to your hard drive, you'll want a slightly different approach as the files are downloaded in a {z}_{x}_{y}.png format, and not produced into a file structure like gdal creates;
+---11_1098_671.png
etc.
so you need to adjust your addTiles code to reflect this, using underscores, like the Google filenames;
server <- function(input, output,session) {
addResourcePath("mytiles", "C:/.../OSM")
output$tilemap <- renderLeaflet({
leaflet() %>%
setView(lng = 13.194773, lat = 52.431635, zoom = 11) %>%
addTiles(urlTemplate = "mytiles/{z}_{x}_{y}.png")
})
}
Lastly, my setView arguments are in a different order to yours but i'm not sure whether that makes a difference or not.
i tried this solution but it could not work,the topic is old but it really helped me to achieve what i wanted to do, i found another solution for those of you in the same case by creating two ports :
just define two differents ports for your shiny server( 3838) and for the server hosting the tiles (8000)
servr::httd(dir="C:/TestApp/data_hydrepat/tiles_hydrepat/mapTiles/mytiles",daemon=TRUE,port=8000)
options(shiny.port = 3838)
to close the server hosting the tiles, just put a reactive on an input or something.. and close
(servr::daemon_stop(which = daemon_list())
hope it'll help !
I'm using the leaftlet.extras R package to add Gps control inside a map.
I'm using the extension addControlGPS inside my code :
... %>%
addControlGPS(options = gpsOptions(position = "topleft", activate = TRUE,
autoCenter = TRUE, maxZoom = 60,
setView = TRUE)) %>%
...
The controller works ok.
I need to extract the Gps coordinates to re-use in my code as arguments for other functions. Is there any way to do that ?
Every time the gps location updates, the coordinates are written to map.id+'_gps_located'. You can find all leaflet.extras bindings in the htmlwidgets/bindings folder in their git.
Working example
library(leaflet)
library(leaflet.extras)
library(shiny)
ui <- fluidPage(
leafletOutput('map')
)
server <- function(input, output, session) {
output$map <- renderLeaflet({ leaflet()%>%addTiles() %>%
addControlGPS(options = gpsOptions(position = "topleft", activate = TRUE,
autoCenter = TRUE, maxZoom = 60,
setView = TRUE))})
observe(
print(input$map_gps_located)
)
}
shinyApp(ui, server)
I've recently had a similar problem with an app I was working on.
You can extract the gps coordinates from a leaflet map by using the _marker_click feature, where is the map label you specify as an output for the leaflet rendering statement.
In my case here's the chunk of code I used to retrieve the coords. In my case the output name of the map object was parksMap therefore the full input to consider in the event observation was parksMap_marker_click. This statement can be saved in a variable (in my case pin), that stores the coordinates data. Finally you need to wrap it all in a reactive expression to be able to save every coordinate when clicking on a point in the leaflet map.
# code to load the park card once the click event on a marker is intercepted
observeEvent(input$parksMap_marker_click, {
pin <- input$parksMap_marker_click
#print(Sys.time()) #uncomment to log coords
#print(pin) #uncomment to log coords
selectedPoint <- reactive(parks[parks$Latitude == pin$lat & parks$Longitude == pin$lng,])
leafletProxy("parksMap", data = selectedPoint()) %>% clearPopups() %>%
addPopups(~Longitude,
~Latitude,
popup = ~park_card(selectedPoint()$ParkName, selectedPoint()$ParkCode, selectedPoint()$State, selectedPoint()$Acres, selectedPoint()$Latitude, selectedPoint()$Longitude)
)
})
The full github repo of the app is available here.
I am making an R Shiny app where users will enter their city, state, and zip code, press a button, and then their location (Lat, Lon) will become the new center of the map. The inputs are collected via this section of code in the server.R:
output$ntextCounter <- eventReactive(input$goButton, {
citySelected <- as.character(input$city)
stateSelected <- as.character(input$state)
zipCodeSelected <- as.character(input$zipCode)
location2 <- stri_detect(paste(as.character(input$city),
as.character(input$state), as.character(input$zipCode), sep=", "), fixed = locationData$Location, opts_regex=stri_opts_regex(case_insensitive=TRUE))
counter <<- counter + 1
lat1 <- as.numeric(locationData[which(location2),]$latitude)
lon1 <- as.numeric(locationData[which(location2),]$longitude)
return(c(lat1, lon1))
})
I am able to easily view the new latitude/longitude values in the UI using:
verbatimTextOutput("ntextCounter")
But I need to be able to pass these values, "return(c(lat1, lon1))", to the center = c(Lat, Lon) in the leaflet map in the ui.r:
leafletMap("map", "100%", 365,
initialTileLayer = "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
initialTileLayerAttribution = HTML('© OpenStreetMap contributors, CC-BY-SA'),
options=list(center = c(38.25, -93.85), zoom = 4, maxBounds = list(list(1, -180), list(78, 180))
)),
I have an initial map center at c(38.25, -93.85), but ultimately I want to be able to pass it changing values from ntextCounter. I'm not sure if this is a scoping issue or what but I need help getting the new lat/lon values into the leaflet map center.
Any assistance would be greatly appreciated. Thanks in advance.
It seems you are creating your leaflet on the ui-side. If you want it to be responsive to inputs you've got to do that on the server side with renderLeaflet.
Your coordinates could be stored in a reactiveValues and you'd update them with a observeEvent:
location <- reactiveValues(lat = 38.25, lon = -93.85)
observeEvent(input$goButton, {
city <- as.character(input$city)
state <- as.character(input$state)
zipCode <- as.character(input$zipCode)
newloc <- stri_detect(paste(city, state, zipCode, sep=", "),
fixed = locationData$Location,
opts_regex=stri_opts_regex(case_insensitive=TRUE))
location$lat <- as.numeric(locationData[which(newloc),]$latitude)
location$lon <- as.numeric(locationData[which(newloc),]$longitude)
})
How do I add polygons from Global Administrative areas, so they are clickable.
The simple way describe in the docs that I tried is
adm <- getData('GADM', country='UKR', level=1)
leaflet() %>% addTiles() %>% addPolygons(data=adm, weight = 3, fillColor = col)
But imagine I want a leaflet map that will have onClick actions later.
Based on SuperZip, I need to have something similar to
map <- createLeafletMap(session, "map")
session$onFlushed(once=TRUE, function() {
map$addPolygon(...)
})
However, there is no addPolygon method and I am confused how will it work for SpartialPolygons.
I also tried converting to geoJSON, similar to https://ropensci.org/blog/2013/10/23/style-geojson-polygon/ or this SO question, but doing
polys <- fromJSON(<json data file>)
map <- createLeafletMap(session, "map")
session$onFlushed(once=TRUE, function() {
map$geoJson(polys)
})
Gives me an error
Error in func() : attempt to apply non-function
Is there a way to do it? Or what am I doing wrong?
I am not sure I really understand the problem, although I read through the question a couple of times. However the code below seems to work for me, as it can easily be combined with a simple onClick event, like a pop up displaying the name of each adm. unit:
---
title: "Ukraine"
runtime: shiny
output: html_document
---
```{r, echo=FALSE, message=F, warning=F}
library(leaflet)
library(raster)
adm <- getData('GADM', country='UKR', level=1)
popup <- paste0("<strong>Name: </strong>",
adm$NAME_1)
leaflet() %>%
addTiles() %>%
addPolygons(data=adm, weight = 2, fillColor = "yellow", popup=popup)
```