WMS in R? Yes, Please!

WMS
R code
leaflet
Sydney
Australia
Author

José R. Ferrer-Paris

Published

May 20, 2024

Maps are like cakes!

Creating a dynamic map very often requires combining several layers of information. Sometimes I feel like a baker in a competition for the most creative cake: carefully choosing the raw data and how to control size, shape and colours to highlight information in each layer, and then composing a balanced combination of layers to convey a message for the viewer to explore.

But sometimes it is just easier to go to go to shop and buy a box of cake mix and start from there. Web Map Service (WMS) provides prerendered map tiles at different scales. You can add them as useful background images or as additional information layers to complement other data sources.

Today I want to show you a minimal example of the use of WMS services within R scripts using the leaflet package.

What is WMS?

WMS stands for Web Map Service and is a standard protocol developed by the Open Geospatial Consortium in 1999 for serving georeferenced map images over the Internet.1

This service is based on a server-client connection: the client connects to the server using a specific query structure and the server provides a results. All communication is served through HTTP.

A WMS serve GIS data as images with fixed styles and quick rendering speeds, and allows basic querying, zooming and panning.2

This is how it’s done

Short and sweet in seven (or so) lines of code:

library(leaflet)

wms_src <- 
  "https://mapprod2.environment.nsw.gov.au/arcgis/services/UHGC/UHGC/MapServer/WMSServer?"
wms_layers <- "0"

leaflet() |>
  setView(lng = 151.21, lat = -33.867, zoom = 13) |>
  addTiles() |>
  addWMSTiles(wms_src, 
              layers = wms_layers, 
              options = WMSTileOptions(format = "image/png", 
                                       transparent = TRUE))

Step by step guide

Ok, that was short and fast! Let’s slow down and describe the steps in more detail. This will help you understand the process better and provide more info on how to adapt this example to your needs.

So what do we actually need to create a dynamic map with R and WMS?

If you have been paying attention, you might have realised that somebody mention a server-client connection. The WMS server will be our server providing the data and R will be (sort of) the client requesting the data and handling it to create the visual display of the map.

The client

Leaflet JS https://leafletjs.com/ is probably the most popular open-source JavaScript library for mobile- and web-friendly interactive maps. With an easy to use and well-documented API, many developers have contributed libraries, modules, plug-ins and interfaces to implement leaflet maps from your favourite programming languages and development platforms. Here we are using the R package https://rstudio.github.io/leaflet/ to integrate these JS functions in R.

But actually R is not really a Geographic Information System (or is it?). In order to use geospatial data in R we need some specific libraries. Here we will try to create the most basic map with a minimum number of libraries. So we are going to start by loading this library called leaflet:

library(leaflet)

The server side of things

Now, we need to find the WMS server. There are so many options out there, you just need to start exploring in your area of interest. For example, if you are in Australia you might have heard of New South Wales’ SEED portal or the Common Wealths’ <data.gov.au>. These data repositories contain links to many data sources, some of which are available as WMS layers.

For example, take a look at this dataset:

  • NSW Urban Vegetation Cover to Modified Mesh Block 2016
    • Provides both an area and percentage of vegetation for city blocks and infrastructure corridors in the Sydney Greater Metropolitan Area as of 2016.
    • Dataset metadata, description and links from dataset@seed.nsw.gov.au
    • WMS link: https://mapprod2.environment.nsw.gov.au/arcgis/services/UHGC/UHGC/MapServer/WMSServer

Requesting data from a WMS

The relevant info here is the WMS link that will receive our requests to the server. The first request that we will make is called GetCapabilities, for example if you copy this in your browser:

https://mapprod2.environment.nsw.gov.au/arcgis/services/UHGC/UHGC/MapServer/WMSServer?request=GetCapabilities&service=WMS

In this example the browser is our client and the response is like a catalogue of the available functions and layers!

You will get a response in xml format. The output might look undecipherable at first, but if you are familiar with xml, you will be able navigate the tags with relevant information. For example we need to locate the queryable layers and find their Name tag. In this case if we are interested in the Percent Tree Canopy for 2019, we need the layer with name 0:

...
<Layer queryable="1">
<Name>0</Name>
<Title>
<![CDATA[ Urban Veg Cover - Percent Tree Canopy 2019 ]]>
</Title>
</Abstract>
...

To actually get the data we are looking for, we normally have to create a more specific request like GetMap. This is where a good client would help us to create that specific request, read the data and provide the extra interactive functionality for zooming and panning. This is usually handled by packages in our Geographic Information Systems (GIS) software.

In our case, we will let leaflet handle this for us, so for now we only need to know the address of the server:

wms_src <- 
  "https://mapprod2.environment.nsw.gov.au/arcgis/services/UHGC/UHGC/MapServer/WMSServer?"

And the name of the layer or layers we are going to use

wms_layers <- "0"

Creating Simple Maps with leaflet

We can create a basic map with R and leaflet by concatenating commands using the pipe symbol |>. First, initialize the map with leaflet(), then define the map view with setView(), providing longitude, latitude coordinates, and a zoom level. Then use addTiles() to add default background base maps.

leaflet() |>
  setView(lng = 151.21, lat = -33.867, zoom = 13) |>
  addTiles() 

Now we are ready to add the WMS layers to the leaflet map using the addWMSTiles() function and usign the values of the baseUrl and layers described above. Like this:

leaflet() |>
  setView(lng = 151.21, lat = -33.867, zoom = 13) |>
  addTiles() |>
  addWMSTiles(baseUrl = wms_src, 
              layers = wms_layers, 
              options = WMSTileOptions(format = "image/png", 
                                       transparent = TRUE))

There are much more things you can do with WMS in R3, but this simple approach is very useful as a starting point for most common examples.

Where is the data?

When you work with WMS layers, you do not have direct access to the GIS database (vector features or raster bands), but rather to a pre-rendered image or product derived from such data. We do not download anything, it is all provided by a server and processed by a client.

Ok, but what is the legend for that layer?

Good question, you can get a legend from the WMS using another request: GetLegendGraphic. So you can build a request like this:

https://mapprod2.environment.nsw.gov.au/arcgis1041/services/UHGC/UHGC/MapServer/WmsServer?request=GetLegendGraphic%26version=1.3.0%26format=image/png%26layer=0

and you will get a graphic like this:

It would be nice to embed this legend in the map, right? I will come back to that in another post…

Conclusion

Making feature rich dynamic maps with R, leaflet and WMS services is a piece of cake!

Here the basic recipe:

  • Find the WMS server,
  • Identify the layer of interest,
  • Build your WMS request,
  • Add the layer to your map,
  • Enjoy!

Now is time for you to explore different WMS sources and enhance your spatial projects by reusing existing layers to create captivating visualizations.