Integrating tiled WFS into R Leaflet Map - r

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

Related

Using leaflet with large data - ACS data for all counties in U.S

I'm plotting ACS data (counts of low-income children) for each county across the entire U.S. I don't have any markers, just a county shapefile and 6 values for each county that are in separate layers.
Unsurprisingly this is too large for browsers to handle. I've seen some similar questions here that deal with clustering, but since I have nothing to cluster I'm starting a new question.
I've tried breaking it up into 6 regional maps, but even those are too much.
Is there some way to lower the footprint, but still have all the county specific data?
I've looked at tilemill and other options for only loading the data the user is currently viewing and based on the zoom level, but I can't find any information on how to go from an R generated leaflet map to something like that. Alternatives using this route are useful as well.
You can try to simplify the polygons using the rmapshaper package and then try visualising it with mapview. The former will help get rid of 'unnecessary' polygon vertices, while the latter has dedicated functions to enable leaflet rendering of large data (ballpark around 100k features - depending on complexity).
You might also consider the tigris package, which gets you direct access to low-resolution county shapefiles within R:
library(tigris)
library(leaflet)
cty <- counties(cb = TRUE, resolution = "20m")
leaflet(cty) %>% addTiles() %>% addPolygons()
This should allow your Leaflet map to perform well in-browser as the polygons are pre-simplified, if you choose to go this route.

How to obtain koppen-geiger climate map for ggmap

I would like to use ggmap to plot several data points on top of a koppen-geiger climate map.
The kopper-geiger data and GIS/KMZ maps can be downloaded here:
http://koeppen-geiger.vu-wien.ac.at/present.htm
I've managed to have a code to plot the points on regular maps, obtained through the get_map function but I fail to use other maps such as koppen-geiger.
Any help will be appreaciated!
Your basic problem is that the map you are attmepting to use is an image file that is not georeferenced. So unless you want to go through the unnecessary and probably time consuming process of georeferencing this image yourself, you will be better taking an alternative approach. There are perhaps a few ways to do this. But, unless you have very few data points to overlay on the map which you can place manually using the lat-long grid of the image, then the least painful method will certainly be to redraw the map yourself using the shapefile.
This is not the right place to give you an introductory lesson on GIS, but the basic steps are to
Download shapefile (which is available at the same website as the image you linked)
Project map to desired coordinate system
Plot map, coloring by climate class
Color the ocean layer
Add labels, legend, and graticule, as desired
Overplot with your own climate data, and legend for these.
If you are unsure how to approach any of these steps, then take an introductory course on GIS, and search the Web for instructional materials. You may find this resource useful.
https://cran.r-project.org/doc/contrib/intro-spatial-rl.pdf

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
)

Raster map vs alternative

I recently found this web page Crime in Downtown Houston that I'm interested in reproducing. This is my first learning experience with mapping in R and thus lack the vocabulary and understanding necessary to make appropriate decisions.
At the end of the page David Kahle states:
One last point might be helpful. In making these kinds of plots, one
might tempted to use the map raster file itself as a background. This
method can be used to make map plots much more quickly than the
methods described above. However, the method has one very significant
disadvantage which, if not handled properly, can destroy the entire
purpose of using the map.
In very plain English what is the difference between the raster file
approach and his approach?
Does the RgoogleMaps package have the ability to produce these types
of high quality maps as seen on the page I referenced above that
calls a google map into R?
I ask not because I lack information but the opposite. There's too much and I want to make a good decision(s) about the approach to pursue so I'm not wasting my time on outdated or inefficient techniques.
Feel free to pass along any readings you think would benefit me.
Thank you in advance for your direction.
Basically, you had two options at the time this plot was made:
draw the map as a layer using geom_tile, where each pixel of the image is mapped onto the x,y axes (slow but accurate)
add a background image to the plot, as a purely "cosmetic" annotation. This method is faster, because you can use grid.raster which draws images more efficiently, but the image is not constrained by the axes of the plotting region. In other words, you have to manually adjust the x and y axes limits to make sure that the image corresponds to the actual positions on the plot.
Now, I would suggest you look at the new annotation_raster in ggplot2 v. 0.9.0. It should have the advantage of speed and leaner output files, and still conform to the data space of the plot. I believe that this function, as well as geom_raster and annotation_map did not exist when David made those plots.

where could we get such a landscape GIS layer

Here, I found a landscape GIS layer is really attractive, especially for presenting species/samples distributions. I would like to know if it can be reached in R or any other resources?
The GIS layer were used in Fig 1. in this article (http://onlinelibrary.wiley.com/doi/10.1111/j.1469-8137.2010.03479.x/full).
This Fig 1 image is here:
http://onlinelibrary.wiley.com/store/10.1111/j.1469-8137.2010.03479.x/asset/image_t/NPH_3479_f1_thumb.gif?v=1&t=gsk5sbhs&s=e5e2e4bbb194f799f7ab9bec85a416e295405784
I have ever tried to submit this question in R-sig-geo. But, I failed. I expect to get some helps/directions here.
Thanks a lots for any directions.
Best wishes,
It is very possible to download this file and read it in with R, configure it to have the correct geo-coordinates so that overplotting works easily, and showing the image with the right colour scheme and so on. But, automating getting all of the data you need is not so easy.
You need the colour table from the GIF file so that you can plot the correct set of RGB values for each pixel (the information is in the file, but I'm not sure if this can be obtained directly with R, I will check - it certainly can be with GDAL, but extracting those values in an automated way depends on various tools being available).
UPDATE: It turns out that the raster package gets hold of the colour information correctly and plots it, see below.
You also need the geo-spatial information, i.e. the coordinates of a reference pixel (say, the top left pixel corner), and the scale (the geographic width and height of the pixels) and this information is not stored in the file. Also, the coordinate system of the file is not in the file, and very likely not provided explicitly with the image data.
If the colours and the coordinate system were stored with the file, then it would all be easy and something like the following would be enough.
(Note this worked for me once, but then I think subsequent requests are blocked by the server, so try to only download the file one time).
u <- "http://onlinelibrary.wiley.com/store/10.1111/j.1469-8137.2010.03479.x/asset/image_n/NPH_3479_f1.gif?v=1&t=gskxvi17&s=0f13fa9dae78bd6837aeee594065c6ca112864d2"
imfile <- paste(tempfile(), ".gif", sep = "")
download.file(u, imfile, mode = "wb")
library(raster) ## rgdal also required for this file format
library(rgdal)
im <- raster(imfile)
plot(im)
This looks fine but now see that there is no "real-world" coordinate system, this is just an axis from pixel 1 to the number in the X dimension (and same for Y).
axis(1, pos = 2)
So, still we need manually work to discover appropriate reference coordinates for the image - and guesses here can work fine, but still they are only guesses and you may end up creating a lot of pain for something seemingly simple.
If plot points interactively is enough for you, then you might use locator in conjunction with points and lines and text, and related plotting functions.
Feng,
if I read the Google docs correctly, you can modify the labels and displayed features with the extra parameters style and element.
I did not include custom parameters for these in the RgoogleMaps package, however, you can easily pass ANY addition parameters via the path argument !
If you read the help file for GetMap carefully, you will note the following example:
note that since the path string is just appended to the URL you can "abuse" the path argument to pass anything to the query, e.g. the style parameter:
#The following example displays a map of Brooklyn where local roads have been changed to bright green and the residential areas have been changed to black:
## Not run: GetMap(center='Brooklyn', zoom=12, maptype = "roadmap", path = "&style=feature:road.local|element:geometry|hue:0x00ff00|saturation:100&style=feature:landscape|element:geometry|lightness:-100", sensor='false', destfile = "MyTile4.png", RETURNIMAGE = FALSE);
Hope this helps,
Markus Loecher
If you just want data like this image, then there are packages to access imagery directly, again utilizing the tools in sp and rgdal. This example is close using gmap in the dismo package.
library(dismo)
e <- extent(-7, 5, 38, 44)
gm <- gmap(e, type = "terrain")
plot(gm)
Note that while we specify the extents in "longlat" the image comes back in its native (Google) Mercator.
print(gm)
See ?gmap for more options on transforming your own data to match the image's projection, or the broader function set in raster, rgdal and sp for other options. There are other imagery providers that might be preferable, and quite a few options in the R suite of contributed packages.

Resources