addPolygons in leaflet in R shiny destroys reactivity - r

I am trying to overlay a heatmap of polygons on my map and then be able to zoom into different parts of it depending on user input.
The code works fine when I remove the heatmap. The user is able to jump around from place to place (based on a dropdown list).
With the polygons it works the first time fully,
the second dropdown choice causes just a map to show with no polygons and the location does not shift,
and the third dropdown choice nothing shows.
output$HMmapstation <- renderLeaflet({
x <- NA
x <- input$HMstation #picking the place to view
x <- leaflet_map %>% setView(preloaded_stations[which(preloaded_stations$name == x),]$longitude,
preloaded_stations[which(preloaded_stations$name == x),]$latitude,
zoom = 14) %>% clearShapes()
x <- x %>% addPolygons(data=polys_dat, color = ~pal(polys_dat#plotOrder),
smoothFactor=.1, stroke = FALSE, fillOpacity = 0.1)
x
})
The leaflet map is created globally above the server and is as follows:
leaflet_map <- (leaflet() %>%
addProviderTiles("OpenStreetMap.BlackAndWhite",
options = providerTileOptions(noWrap = TRUE,minZoom=9)) %>%#~pal(seq(1,537,1))~rainbow(50, start=0,end=.3, alpha = NULL)
setMaxBounds(-0.715485, 51.252031, 0.514984, 51.745313))
I just cant seem to figure out why it would work once and then stop. Especially since without the polygon it works as expected.
Thank you in advance for any direction you can give me.

Leaflet is an amazing addition to R's quiver, I am starting to use it quite a bit at work and at times I also struggle with lost functionality as layers build. I do not have an answer for you working directly in R, but I have a suggestion.
One of the things that I am discovering as I become a Javascript D3 developer is that the last object into a JS visualization is on top.
So this means as you stack polygons, lines, and other objects and data onto a map, it is possible to BLOCK the visibility/functionality of objects below it.
If you are familiar with Javascript, you could open the devtools in chrome and look to see how the layers are being applied to the map.
As you do this, try to think about how R will call out to JS to compile the web graphic it makes and then see if you can re-order something in your R stack, or turn a shape into an outline so that the shape below retains function.
And it is possible after the graphic is "extruded' from R to go in and manually tweak the javascript controlling the features you are using with a lot more control than you have in R itself. I have done some editing on the resulting file set successfully.
There is a LOT more help in working on leaflet in JS directly here and around the web. You may be able to find a quicker answer that way.

The fix ended up being to put the leaflet in a reactive rather than a renderLeaflet.
I also re-ordered based on bethanyP's response so thank you!

Related

How do I use pictures as custom icons in Leaflet?

I am trying to create an interactive map of football stadiums in the UK with the leaflet package in R. I understand that I can use a custom image as the icon on the map. For a given stadium, I would like to use the badge of the club that plays there as the icon. Initially I am trying to solve the simpler problem of just using one custom image for all the stadiums with the hope that once I can solve this, I will be able to generalise and have one custom image per stadium. I will provide a simplified data set of just two stadiums for the purposes of this question.
So far I have tried using this picture (https://upload.wikimedia.org/wikipedia/en/e/e5/AFC_Bournemouth_%282013%29.svg) of the Bournemouth badge however it does not appear on the map when run. I think R cannot properly access this image but I am not sure what types it can access or how it accesses them.
So far my code looks like this
library(leaflet)
# Create Data
finalData <- data.frame(Club = c("A.F.C. Bournemouth", "A.F.C. Wimbledon"), Latitude = c("50.7352","51.4051"), Longitude = c("-1.83839","-0.281984"), stringsAsFactors = FALSE)
# Create map using leaflet
m <- leaflet() %>%
addTiles()
# Attempt to create custom icon using the linked picture
BournemouthIcon = makeIcon("https://upload.wikimedia.org/wikipedia/en/e/e5/AFC_Bournemouth_%282013%29.svg", iconWidth = 8, iconHeight = 8)
m %>% addMarkers(lat = as.numeric(finalData$Latitude),
lng = as.numeric(finalData$Longitude),
clusterOptions = markerClusterOptions(),
icon = BournemouthIcon)
I expect to see the 2 stadiums plotted on the map with the Bournemouth badge as the marker but instead the markers are blank.1 It appears R knows where to plot the points (since if you zoom out it detects the cluster of points), however it does not know what to mark the point with.2 This links back to my misunderstanding of how R is reading the picture I supplied. Any help with how to properly build a custom marker and then pass it to addMarkers would be greatly appreciated. Furthermore some guidance on generalising this to having a unique custom picture for each marker would also be great!

Integrating tiled WFS into R Leaflet Map

This is more of a general question regarding R Leaflet than a specific coding problem. Google hasn't been too helpful for me this morning so I'm reaching out to the SO community in the hope that someone can help.
I know that it is possible to include tiled WMS data into a leaflet map using addWMSTiles(). This is useful if the aim is to understand the spatial distribution of your data without reference to any information associated with that spatial data (e.g. the area that a rendered shape takes up, or the name of that shape etc.). To resolve this, it's possible to specify a shapefile polygon instead using addPolygons(). This allows Leaflet to display data associated with each polygon using a click/mouse over (e.g. mousing over a polygon could tell you the name of that feature, it's area and even a hyperlink to external data).
The problem with shapefiles is that they're computationally expensive to render when the area of extent becomes large, even if the polygons are simplified (e.g. using st_simplify() or similar process). In addition, if your mapping application has several shapefile layers, the render time increases as some function of the number of layers and it can quickly get out of hand.
I am therefore wondering if there is a way to render polygons on-screen in a similar way to rendering tiles? That is, the polygons are only rendered when the user is focussed on a particular area. This way, you have all of the benefits of polygons and associated data but with the substantially faster rendering times of tiled datasets.
I stumbled across WFS in R during my research (e.g. here) which I initially thought would be my saviour, but in the few examples I've come across, it seems that it's necessary to first download all the spatial data (e.g. using st_read()) before plotting it on a map, which doesn't seem to address the loading/rendering time issue that I have detailed previously.
As there is no addWFSTiles() function within leaflet(), I suspect it's not possible to have my cake and eat it too. However, if there is some reasonably robust 'hacky' way to solve the rendering time issue, I am certainly all-ears. For context, my ultimate aim is to present my maps within an R Shiny application so fast rendering times and reduced bandwidth requirements via tiling would be an optimal solution for me. I'm not sure whether caching could be a viable solution so would be keen to discuss this aspect further if someone thinks it might be useful.
Based on the comments associated with this question, I have copied some basic code below which displays the distribution of ancient woodland in England. It uses WMS data provided by Natural England (source here.)
library(leaflet)
library(leaflet.extras)
leaflet() %>%
setView(zoom=11, lng=-1.19, lat=52.8) %>%
# Defines open-source base maps
addProviderTiles(group = "OpenSM", providers$OpenStreetMap) %>%
# Defines ancient woodland WMS from Natural England
addWMSTiles(group = "Ancient Woodland",
baseUrl = "https://environment.data.gov.uk/spatialdata/ancient-woodland-england/wms?",
layers = "Ancient_Woodland_England",
options = WMSTileOptions(format = "image/png", transparent = TRUE, crs = "EPSG:4326", interactive = TRUE, minZoom = 7, maxZoom = 15)) %>%
addLayersControl(
baseGroups = c("OpenSM"),
overlayGroups = c("Ancient Woodland"),
options = layersControlOptions(collapsed = FALSE)
)
For now, it would be interesting to see whether this data can be 'interactive' in the sense that upon clicking a patch of woodland, its name/area etc. can be displayed as a popup. If WMS is able to do this, I can test adding 10-20 different layers to assess performance across the UK. However, as I mentioned in the original iteration of this question, I don't think it's possible to have this functionality in WMS (but could potentially be viable with WFS).
For now, it would be interesting to see whether this data can be 'interactive' in the sense that upon clicking a patch of woodland, its name/area etc. can be displayed as a popup. If WMS is able to do this [...]
Yes, WMS is able to do this, but not all WMS layers enable this. This is called WMS GetFeatureInfo, and optional.
You can check if the layer is queryable in the WMS GetCapabilities: <Layer queryable="1" >
However, the GetFeatureInfo requests have not been integrated in r leaflet. This was an issue in the leaflet.extras package, but not (yet) implemented. See https://github.com/bhaskarvk/leaflet.extras/issues/84

Can't figure out how to plot data in leaflet r with a gall-stereographic projection

I have a spatial polygons data frame whose coordinates I've transformed into gall-stereographic type. But I can't map that spdf with leaflet() now. I'm not sure whether it's a problem with the resolutions I'm providing (because I have no clue what those are or do), or whether it's something to do with the tiled maps I provide via addTiles(), or whether it's something else altogether.
So, before transforming the data to a gall-stereographic projection, everything was fine, I could plot it easily. The output was gorgeous. After... not so much.
I don't have the data on hand to show you what I'm doing, exactly, but the following lines of code should be reproducible with any spdf. I'm pretty sure I'm doing something very obviously wrong -- obvious to anyone familiar with leaflet() -- but the online resources on projections is limited and my familiarity with map projections and the package - even more so. Anyway, here's what I'm doing:
spdf2 <- spTransform(spdf, CRS = CRS("+proj=gall"))
sp::proj4string(spdf2)
leaflet(spdf2, options =
leafletOptions(
crs=leafletCRS(crsClass="L.Proj.CRS",
code="ESRI:54016",
proj4def= "+proj=gall +ellps=WGS84",
resolutions = c(65536, 32768, 16384, 8192, 4096, 2048)
))) %>% addTiles()
Also tried
addGraticule(sphere = TRUE, style= list(color= '#777', weight= 1, opacity= 0.25))
instead of addTiles, but I'm not sure what it does and it didn't help. Obviously, I'd want to addPolygons after, but for now I just want the map; I can figure out the polygons myself.
EXPECTED:
A pretty map in gall-stereographic format
RESULT:
An empty white nothing.
I expect this is due to the addTiles function, which isn't supposed to give you a map with gall projections. If so, could anyone direct me to a solution, like where to find a map that uses gall projections?
Thanks, guys, I really appreciate it, I've been trying to get it to work for hours and seem to have done everything short of sacrificing my dog to Satan. I'm sorry if I'm wasting your time a bit, I'm just new to leaflet() and crs in general. It's a really cool package though.

Leaflet package in R: why are the labels misplaced when plotting them with noHide=T?

I am trying to plot gas stations in Spain, and I would like the plot to show the names or brand names of each station. So far I have struggled a little bit with this, but I finally got my way around it:
pal2<- colorRampPalette(brewer.pal(11,"RdBu"))(diff(range(b$Price.Gas)))
myMap<- leaflet() %>%
addTiles() %>%
addCircleMarkers(lat=lati, lng=long, fillColor = pal2,
label=as.character(rotulo),labelOptions = lapply(1:length(rotulo), function(x) {
labelOptions(opacity=0.9,noHide = T)
}),
clusterOptions=markerClusterOptions())
But as you can see from the picture below, some labels are way off from where they're supposed to be.
Why does this happen? Also, and this is another issue, when I try to color the circle markers with fillColor=pal2, nothing happens, they all remain the same...
So... after playing with it for a while, I realised that it's not that it doesn't work.
What actually happens is:
When you zoom in on a spot on the map, the circles appear, but the label is misplaced to where the circles used to lay before we zoomed in
If one moves the map with the pointer (drag and drop), leaving those points out of the window view ("drop" with the pointer), and then moves the map back to where those points were... tadaaa! The labels are where they should be!
I guess it is due to the fact that this is a large leaflet map and that rendering must be heavy for the computer... nonetheless I will post the issue on the Leaflet github page. Thanks to anyone that read the question and took time to think about it, hope my answer helps someone else!

Can anyone suggest a good world map visualization for use in Shiny?

Sorry in advance for the wall of text. I am creating a sort of novel type of choropleth map, in which countries are shaded based on different categorical variables. The way I've set up the app, I assign each country an RGB value based on its levels of each of the underlying variables and I want the map to show that RGB value--seems simple, right?
Unfortunately, most of the map visualizations seem to want to do the color selection for me, rather than letting me choose. The best I've been able to do is to treat the data as categorical and I end up with the same number of categories as countries. This worked fairly well for rworldmap. The problem is, I'm developing this for web use, and I'd really like to have tooltips so that you can hover over a particular country and this doesn't work with rworldmap, as it's just a basic plot. Also, the rworldmap output is not particularly nice looking.
Here's the code I used with that:
mapjoin <- joinCountryData2Map(db, joinCode="ISO3",
nameJoinColumn="iso", mapResolution="high")
mapCountryData(mapjoin, nameColumnToPlot="iso", addLegend=FALSE,
catMethod="categorical", colourPalette=db$rgb, mapTitle=input$year)
I have experimented with googleVis, but I was having a lot of trouble with that--the map would just disappear for no reason and I'd have to reload the page, which I believe was an issue with the Shiny bindings in the googleVis package. I ultimately went with googleCharts (https://github.com/jcheng5/googleCharts), which clears up the problems with the bindings.
However, I'm still having problems.
Here's the reactive function:
output$mapviz <- reactive({
db <- genRgb()
list(
data=googleDataTable(db[c("country", "id")]),
options=list(legend="none", projection="kavrayskiy-vii", colors=db$rgb)
)
)}
and here's the output call:
googleGeoChart("mapviz", width="100%", height="780px")
As you can see, there's not a specific way to clue the JS app that it's categorical data, so as a result, it's making a choropleth with 182 different gradient stop points. Usually this works fine, but occasionally something weird happens and a country mysteriously ends up in an intermediate place between colors. I can always tell that there's a problem because certain countries are supposed to be specific colors (for instance, the U.S. will show as #0000FF, and it's pretty obvious when it's not). I've found that I can go to a different chart type (the app uses other googleCharts types) and then return to the map and usually it's fixed. So it's completely inconsistent.
So with that in mind, can anyone suggest a better mapping tool that I can implement in Shiny that would work well for this purpose?
Thanks!
Check out leaflet:
https://rstudio.github.io/leaflet/
It will allow you to:
have pop-ups for each shapefile with more data
explicitly set the colour of shapefiles in R, based on data in your dbf file.
use an open map background
Some example code (not all may be relevant):
map <- leaflet()%>%
addTiles(urlTemplate = url, attribution = HTML(attrib))%>%
addPolygons(data = sub_shape,
fill = TRUE,
fillColor = colors$color, #set color here
fillOpacity = .8,
stroke = TRUE,
weight = 3,
color = "white",
dashArray = c(5,5),
popup = pops
)

Resources