R is a statistical and computing language first developed in the early 1990s. Ever since then, it has grown in leaps and bounds in terms of development and usage. Apart from statistics, R can also be used for cartography and spatial analyses. This is where the RStudio comes in. RStudio is an Integrated Development Environment (IDE) for the R Language, in other words, the GUI for writing R code. You can consider RStudio as the more ‘beautiful’ site for writing the R language. Don’t take my word for it, just judge the book by its cover for yourself by counterchecking the interfaces of R versus RStudio yourself!
Did we mention you can do spatial analyses in R? Not only spatial analyses but also making webmaps out of them. Today, we will look at creating webmaps in R and also include a few GIS operations. When we mention R, take it as the R languages appearing in RStudio. Time to spin the decks with our RStudio.
The most famous tool used for creating webmaps in RStudio is the leaflet package. This package is powered by Javascript and is called into R using the library function. One can also create a webmap using the tmap package but that’s a story for another day.
Today, we will create a webmap of Kenyan wards showcasing dummy electoral results. To also demonstrate a few functionalities, a raster map will be loaded as well. For the political diehards, the numbers used herein are in no way representative or reflective of the true results to be counted on the voting day.
In R, packages
are a collection of functions that run certain processes or produce
certain outputs. Packages in R are stored in a directory
called library. For those packages not installed in
R by default, they are called into the R
environment using library(). An example of this will be the
packages which we need for spatial operations as shown below.
NB: If installing a package for the first time, use
install.packages() and thereafter load it into R with
library(package name).
library(sp)
library(sf)
## Linking to GEOS 3.9.1, GDAL 3.2.1, PROJ 7.2.1; sf_use_s2() is TRUE
library(rgeos)
## rgeos version: 0.5-9, (SVN revision 684)
## GEOS runtime version: 3.9.1-CAPI-1.14.2
## Please note that rgeos will be retired by the end of 2023,
## plan transition to sf functions using GEOS at your earliest convenience.
## GEOS using OverlayNG
## Linking to sp version: 1.4-6
## Polygon checking: TRUE
library(rgdal)
## Please note that rgdal will be retired by the end of 2023,
## plan transition to sf/stars/terra functions using GDAL and PROJ
## at your earliest convenience.
##
## rgdal: version: 1.5-28, (SVN revision 1158)
## Geospatial Data Abstraction Library extensions to R successfully loaded
## Loaded GDAL runtime: GDAL 3.2.1, released 2020/12/29
## Path to GDAL shared files: C:/Users/User/Documents/R/win-library/4.1/rgdal/gdal
## GDAL binary built with GEOS: TRUE
## Loaded PROJ runtime: Rel. 7.2.1, January 1st, 2021, [PJ_VERSION: 721]
## Path to PROJ shared files: C:/Users/User/Documents/R/win-library/4.1/rgdal/proj
## PROJ CDN enabled: FALSE
## Linking to sp version:1.4-6
## To mute warnings of possible GDAL/OSR exportToProj4() degradation,
## use options("rgdal_show_exportToProj4_warnings"="none") before loading sp or rgdal.
## Overwritten PROJ_LIB was C:/Users/User/Documents/R/win-library/4.1/rgdal/proj
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.1.3
This is just for starters. More packages will be added. In fact, more
often than not, you will be using library to add more
packages as you progress in handling more sophisticated tasks. In short,
the more complex the task, the more packages that might be needed. There
might arise a need where you may have to create one yourself!
For a description of each of the above packages, click on the hyperlinks below. 1. sp
Let’s load the shapefile we will use for making our webmap. The shapefile is available from here. Save and extract it in your directory.
kenya_wards <- readOGR(dsn = "D:/gis-articles-800/leaflet/kenya_wards.shp")
## OGR data source with driver: ESRI Shapefile
## Source: "D:\gis-articles-800\leaflet\kenya_wards.shp", layer: "kenya_wards"
## with 1450 features
## It has 5 fields
## Integer64 fields read as strings: gid
We earlier mentioned leaflet package is used to make
webmaps. Let’s see how it looks without any data parsed into it.
# make a leaflet widget
leaflet()
A plain gray cold looking map.
leaflet, according to the help menu, is a function to
create a Leaflet map widget. This is what you see above.
Our map can’t be blank. We will spice things up by adding some
basemaps. Basemaps are added using addTiles(), part of the
functions within the leaflet package. addTiles() adds maptiles, which
are collection of joined square boxes of the requested image or vector
data.
leaflet() %>%
addTiles() # you can see a global map appears and all seven continents shown twice in one view
You can see a basemap of the globe has been added. However, it has been replicated thrice! This is because no spatial object, which can reference to a place on the earth’s surface, has been added.
Let’s add a spatial object, our kenya_wards
shapefile.
# add kenya wards map to leaflet
#leaflet() %>%
# addTiles() %>%
#addPolygons(data = kenya_wards) # you can see that the kenya wards shapefile was added to leaflet
# you also note it took some time loading
You may have noticed that it took some time for it to load. That is not good news for something that will go online at some point. Just how long was the delay?
# check loading time
#start_time <- Sys.time()
#leaflet() %>%
# addTiles() %>%
# addPolygons(data = kenya_wards)
#end_time <- Sys.time()
#difference <- end_time - start_time
#difference
Twenty seconds? Enough to do a 100m sprint and back. Let’s reduce the
size of this shapefile using the rmapshaper package. As a
matter of fact, we will reduce it without using library()
to call the package into R. How? A simple :: does the
trick.
# reduce size of shapefile
kenya_wards2 <- rmapshaper::ms_simplify(input = kenya_wards, keep = 0.03, keep_shapes = T)
## Registered S3 method overwritten by 'geojsonlint':
## method from
## print.location dplyr
Let’s reload the leaflet map with the simplified
kenya_wards2 spatial object. We will also check the time it
takes to load for each and know who is faster now.
# compare with kenya_wards2 shapefile
#start_time <- Sys.time()
#leaflet() %>%
# addTiles() %>%
#addPolygons(data = kenya_wards2)
#end_time <- Sys.time()
#difference <- end_time - start_time
#difference
Three seconds?! The loading time just got reduced by more than a half.
# draw leaflet map with kenya_wards2
leaflet() %>%
addTiles() %>%
addPolygons(data = kenya_wards2)
To view the attributes for a shapefile, the @data suffix
is added after the shapefile name. This is unlike working with tables
where simply calling their name displays R displays as many of the
table’s attributes as it can handle.
head(kenya_wards2@data) # show first six attribute rows
## gid pop2009 county subcounty ward
## 1 241 17431 ISIOLO Isiolo Sub County WABERA
## 2 1455 18755 Migori Rongo Sub County North Kamagambo Ward
## 3 1456 27756 Migori Rongo Sub County Central Kamagambo Ward
## 4 1457 27179 Migori Rongo Sub County South Kamagambo Ward
## 5 1458 22874 Migori Awendo Sub County North Sakwa Ward
## 6 1459 36200 Migori Awendo Sub County South Sakwa Ward
Alright. We promised our webmap would show both administrative and electoral result attributes. Looking at it, only administrative attributes can be seen. Luckily, We have a curated table showing the dummy electoral results.
# load the table with voter data
ward_data <- read.csv("D:/gis-articles-800/leaflet/wards_full.csv", header = T)
head(ward_data)
## X gid pop2009 county subcounty ward uid
## 1 1 241 17431 ISIOLO Isiolo Sub County WABERA rIdiIpv9fBt
## 2 2 1455 18755 Migori Rongo Sub County North Kamagambo Ward QC41mItjIzF
## 3 3 1456 27756 Migori Rongo Sub County Central Kamagambo Ward M8rGveWTIMm
## 4 4 1457 27179 Migori Rongo Sub County South Kamagambo Ward DABObbHgPMX
## 5 5 1458 22874 Migori Awendo Sub County North Sakwa Ward EmSsP2C6A3h
## 6 6 1459 36200 Migori Awendo Sub County South Sakwa Ward OpbsijPbYuv
## scuid cuid voters david_waih george_waj raila_odin reuben_kig
## 1 I2LYLqKU6AW bzOfj0iwfDH 1779 39 66 52 79
## 2 fT37q3rXQ35 fVra3Pwta0Q 1682 69 52 17 94
## 3 fT37q3rXQ35 fVra3Pwta0Q 1232 18 94 11 30
## 4 fT37q3rXQ35 fVra3Pwta0Q 1991 21 25 25 59
## 5 ka9Uv3Ckcbd fVra3Pwta0Q 1065 33 33 67 29
## 6 ka9Uv3Ckcbd fVra3Pwta0Q 1986 74 39 84 93
## william_ru
## 1 56
## 2 95
## 3 86
## 4 97
## 5 97
## 6 60
Question is, just how do we take the columns from voters
to william_ru and join them to our spatial
kenya_wards2? In Qgis, we could do it using
joins tool. R also has its own tricks up its sleeve for the
same purpose.
Actually, the original kenya_wards shapefile contains
all the electoral data when viewed in Qgis. It was created in Qgis using
the joins tool alluded to earlier. For some reason,
however, this electoral data columns are not visible when loaded in R.
Nevertheless, we will take the bull by its horns and merge these
electoral attributes with our shapefile so that eventually our shapefile
is in top-notch shape.
The sp package has the merge() function
which is used to merge a spatial object with a data frame –which in our
case is the table above.
kenya_wards3 <- merge(x = kenya_wards2,
y = ward_data, by.x = "gid",
by.y = "gid", # show which column to join by
suffixes = c(".x", ".y")) # add suffixes to differentiate by source
head(kenya_wards3@data)
## gid pop2009.x county.x subcounty.x ward.x X
## 962 241 17431 ISIOLO Isiolo Sub County WABERA 1
## 47 1455 18755 Migori Rongo Sub County North Kamagambo Ward 2
## 48 1456 27756 Migori Rongo Sub County Central Kamagambo Ward 3
## 49 1457 27179 Migori Rongo Sub County South Kamagambo Ward 4
## 50 1458 22874 Migori Awendo Sub County North Sakwa Ward 5
## 51 1459 36200 Migori Awendo Sub County South Sakwa Ward 6
## pop2009.y county.y subcounty.y ward.y uid
## 962 17431 ISIOLO Isiolo Sub County WABERA rIdiIpv9fBt
## 47 18755 Migori Rongo Sub County North Kamagambo Ward QC41mItjIzF
## 48 27756 Migori Rongo Sub County Central Kamagambo Ward M8rGveWTIMm
## 49 27179 Migori Rongo Sub County South Kamagambo Ward DABObbHgPMX
## 50 22874 Migori Awendo Sub County North Sakwa Ward EmSsP2C6A3h
## 51 36200 Migori Awendo Sub County South Sakwa Ward OpbsijPbYuv
## scuid cuid voters david_waih george_waj raila_odin reuben_kig
## 962 I2LYLqKU6AW bzOfj0iwfDH 1779 39 66 52 79
## 47 fT37q3rXQ35 fVra3Pwta0Q 1682 69 52 17 94
## 48 fT37q3rXQ35 fVra3Pwta0Q 1232 18 94 11 30
## 49 fT37q3rXQ35 fVra3Pwta0Q 1991 21 25 25 59
## 50 ka9Uv3Ckcbd fVra3Pwta0Q 1065 33 33 67 29
## 51 ka9Uv3Ckcbd fVra3Pwta0Q 1986 74 39 84 93
## william_ru
## 962 56
## 47 95
## 48 86
## 49 97
## 50 97
## 51 60
You will notice that there are several duplicate columns. We will
remove those that we don’t need. These will be the columns denoted with
the suffix .y since our shapefile already had them even
before the merge operation. They are denoted by the suffix
.y in our table. We will remove them and remain with the
voter data.
kenya_wards4 <- kenya_wards3[ , -c(7:13)] # remove duplicate columns
head(kenya_wards4@data)
## gid pop2009.x county.x subcounty.x ward.x X voters
## 962 241 17431 ISIOLO Isiolo Sub County WABERA 1 1779
## 47 1455 18755 Migori Rongo Sub County North Kamagambo Ward 2 1682
## 48 1456 27756 Migori Rongo Sub County Central Kamagambo Ward 3 1232
## 49 1457 27179 Migori Rongo Sub County South Kamagambo Ward 4 1991
## 50 1458 22874 Migori Awendo Sub County North Sakwa Ward 5 1065
## 51 1459 36200 Migori Awendo Sub County South Sakwa Ward 6 1986
## david_waih george_waj raila_odin reuben_kig william_ru
## 962 39 66 52 79 56
## 47 69 52 17 94 95
## 48 18 94 11 30 86
## 49 21 25 25 59 97
## 50 33 33 67 29 97
## 51 74 39 84 93 60
Now we have our electoral data: the voters and results for each of our named aspirants.
Now, to what we have been waiting for. Let’s load these improved
kenya_wards2 data to our leaflet map. In addition, we will
make the wards clickable. That is, some data will show up on screen when
a particular ward is clicked by the user. The popup
argument within the addPolygons() will enable this.
# make the polygons clickable and showing some data of each ward
leaflet() %>%
addTiles() %>%
addPolygons(
data = kenya_wards4,
popup = paste0("County: ", kenya_wards4@data$county, "<br>",
"Ward: ", kenya_wards4@data$ward, "<br>",
"Voters: ", kenya_wards4@data$voters, "<br>",
"David Waihiga: ", kenya_wards4@data$david_waih, "<br>",
"George Wajackoyah: ", kenya_wards4@data$george_waj, "<br>",
"Raila Odinga: ", kenya_wards4@data$raila_odin, "<br>",
"Reuben Kigame: ", kenya_wards4@data$reuben_kig, "<br>",
"William Ruto: ", kenya_wards4@data$william_ru
)
)
# upon clicking you see ward electoral data
Click on any ward and you will see a popup showing some information about that ward–both political (County name and ward name) and electoral (voters, David Waihiga, George Wajackoyah etc).
Furthermore, we can also change the aesthetics. We want to color code
the wards according to the counties they fall under. This will make it
easy to distinguish one county from another, thus also easening the
navigation experience. Sounds easy, but it is not. To create the
different color codes, we have to create a color function using
colorFactor(). Once the function is created, it can be
parsed to leaflet for display.
# create a color function for coloring map
color_wards <- colorFactor(palette = topo.colors(47), domain = kenya_wards4@data$county.x)
# create a colored map with wards categorized to their counties by color
leaflet() %>%
addTiles() %>%
addPolygons(
data = kenya_wards4,
color = ~color_wards(kenya_wards4@data$county.x), # added the color component
opacity = 0.3, weight = 2, # to make the colors less opaque and not shouting
popup = paste0("County: ", kenya_wards4@data$county, "<br>",
"Ward: ", kenya_wards4@data$ward, "<br>",
"Voters: ", kenya_wards4@data$voters, "<br>",
"David Waihiga: ", kenya_wards4@data$david_waih, "<br>",
"George Wajackoyah: ", kenya_wards4@data$george_waj, "<br>",
"Raila Odinga: ", kenya_wards4@data$raila_odin, "<br>",
"Reuben Kigame: ", kenya_wards4@data$reuben_kig, "<br>",
"William Ruto: ", kenya_wards4@data$william_ru
)
)
How about making the wards highlight upon mouse hover? This can be
done using the highlightOptions() function. As you can see,
most of the function names under the leaflet package also hint to their
purpose(s).
leaflet() %>%
addTiles() %>%
addPolygons(
data = kenya_wards4,
color = ~color_wards(kenya_wards4@data$county.x), # added the color component
opacity = 0.3, weight = 2, # to make the colors less opaque and not shouting
popup = paste0("County: ", kenya_wards4@data$county, "<br>",
"Ward: ", kenya_wards4@data$ward, "<br>",
"Voters: ", kenya_wards4@data$voters, "<br>",
"David Waihiga: ", kenya_wards4@data$david_waih, "<br>",
"George Wajackoyah: ", kenya_wards4@data$george_waj, "<br>",
"Raila Odinga: ", kenya_wards4@data$raila_odin, "<br>",
"Reuben Kigame: ", kenya_wards4@data$reuben_kig, "<br>",
"William Ruto: ", kenya_wards4@data$william_ru
),
highlightOptions = highlightOptions(
stroke = T,
color = "white",
weight = 5,
opacity = 0.5,
bringToFront = T
), # made the wards highlightable on hover
)
The addMarker() would have been a nice complimenter to
the highlightsOptions function in that it would show a
label–such as the name of the ward–upon mouse hover. However, the
addMarker() function needs longitude and latitude
information, not included in our data and thus we prefer to explore it
in another day.
Currently, our map contains only one basemap layer, the default Open
StreetMap (OSM) basemap that comes with the leaflet package. However, we
can add more basemaps using the addProviderTiles()
function.
#
leaflet() %>%
addTiles(
group = "OSM"
) %>% # the default web map layer is OSM, so we put into group name 'OSM'.
addProviderTiles(
providers$CartoDB.Positron, group = "Carto"
) %>% # added an extra webmap layer and called group - CartoDB
addProviderTiles(
providers$OpenStreetMap.France,
group = "OSM France"
) %>% #added an extra webmap layer called group - OSM France
addPolygons(
data = kenya_wards4,
color = ~color_wards(kenya_wards4@data$county.x), # added the color component
opacity = 0.3, weight = 2, # to make the colors less opaque and not shouting
popup = paste0("County: ", kenya_wards4@data$county, "<br>",
"Ward: ", kenya_wards4@data$ward, "<br>",
"Voters: ", kenya_wards4@data$voters, "<br>",
"David Waihiga: ", kenya_wards4@data$david_waih, "<br>",
"George Wajackoyah: ", kenya_wards4@data$george_waj, "<br>",
"Raila Odinga: ", kenya_wards4@data$raila_odin, "<br>",
"Reuben Kigame: ", kenya_wards4@data$reuben_kig, "<br>",
"William Ruto: ", kenya_wards4@data$william_ru),
highlightOptions = highlightOptions(
stroke = T,
color = "white",
weight = 5,
opacity = 0.5,
bringToFront = T
), # made the wards highlightable on hover
)
There is one problem though. We can only see one basemap layer.
Actually, the basemap for ‘OpenStreetMap.France’. For the other two, the
user is at a loss from where to retrieve them, and that will be bad
client experience. This problem is solved by the group
argument included in our script below. The group argument
does what it says - group our layers to a particular unit named by the
user.
This still doesn’t answer our question of being able to retrieve any
of our other two basemaps. For this, we will add a control widget that
allows toggling one layer on or off. The addLayersControl()
function comes into fore.
# we need to add a toggle on or off widget to choose which map layers we want to be visible
leaflet() %>%
addTiles(
group = "OSM"
) %>% # the default web map layer is OSM, so we put into group name 'OSM'.
addProviderTiles(
providers$CartoDB.Positron,
group = "Carto"
) %>% # added an extra webmap layer and called group - CartoDB
addProviderTiles(
providers$OpenStreetMap.France,
group = "OSM France"
) %>% #added an extra webmap layer called group - OSM France
addPolygons(
data = kenya_wards4,
color = ~color_wards(kenya_wards4@data$county.x), # added the color component
opacity = 0.3,
weight = 2, # to make the colors less opaque and not shouting
popup = paste0(
"County: ", kenya_wards4@data$county, "<br>",
"Ward: ", kenya_wards4@data$ward, "<br>",
"Voters: ", kenya_wards4@data$voters, "<br>",
"David Waihiga: ", kenya_wards4@data$david_waih, "<br>",
"George Wajackoyah: ", kenya_wards4@data$george_waj, "<br>",
"Raila Odinga: ", kenya_wards4@data$raila_odin, "<br>",
"Reuben Kigame: ", kenya_wards4@data$reuben_kig, "<br>",
"William Ruto: ", kenya_wards4@data$william_ru
),
highlightOptions = highlightOptions(
stroke = T,
color = "white",
weight = 5,
opacity = 0.5,
bringToFront = T
), # made the wards highlightable on hover
group = "administrative"
) %>% # put our polygons into the 'administrative' group
addLayersControl(
baseGroups = c(
"OSM", "Carto", "OSM France"
), # group names of our OSM layers
overlayGroups = c(
"administrative"
)
) # group name for our polygons
So far, we have worked with vector and raster data. How about raster
data? To work with raster data in R, one has to use the
raster and terra packages.
# load the terra and raster packages
library(terra)
## terra 1.5.21
##
## Attaching package: 'terra'
## The following object is masked from 'package:rgdal':
##
## project
library(raster)
## Warning: package 'raster' was built under R version 4.1.3
We will use the rast function from the
terra package to load the raster data into R Studio.
# load raster into R
landcover <- rast(x = "D:/gis-articles-800/leaflet/kenya_landcover_2017/kenya_landcover_2017.tif")
#landcover #check attributes
However, this raster is too large to work with. It will not only take
much time to load into leaflet, but it will cause errors to appear when
forced into this lightweight (yet powerful) R package tool. Believe me,
when it comes to working with leaflet and any other web
based application, size matters. In R, the aggregate
function reduces the resolution of a raster and subsequently also
reducing the size of the file.
#reduce size of this raster
landcover2 <- terra::aggregate(landcover, fact=100, fun = "mean", overwrite = T)
#landcover2
In RStudio, our landcover2 is registered as a
SpatRaster file. This will cause issues upon loading to
leaflet() which strictly requires a
RasterLayer object. We are not a geniuses to know this
beforehand, rather, we discovered this by experience when we were
parsing the landcover2 to leaflet and R
splashed the following error into our faces, as if to say: “No, thank
you”.
Error in addRasterImage(., landcover2, colors = "Spectral", opacity = 0.8, :
inherits(x, "RasterLayer") is not TRUE
The raster() function will convert our
landcover2 into a RasterLayer object.
# convert to raster layer object
landcover3 <- raster::raster(landcover2)
Time to add the raster to our leaflet map.
###
leaflet() %>%
addTiles(
group = "OSM"
) %>% # the default web map layer is OSM, so we put into group name 'OSM'.
addProviderTiles(
providers$CartoDB.Positron,
group = "Carto"
) %>% # added an extra webmap layer and called group - CartoDB
addProviderTiles(
providers$OpenStreetMap.France,
group = "OSM France"
) %>% #added an extra webmap layer called group - OSM France
addPolygons(
data = kenya_wards4,
color = ~color_wards(kenya_wards4@data$county.x), # added the color component
opacity = 0.3,
weight = 2, # to make the colors less opaque and not shouting
popup = paste0(
"County: ", kenya_wards4@data$county, "<br>",
"Ward: ", kenya_wards4@data$ward, "<br>",
"Voters: ", kenya_wards4@data$voters, "<br>",
"David Waihiga: ", kenya_wards4@data$david_waih, "<br>",
"George Wajackoyah: ", kenya_wards4@data$george_waj, "<br>",
"Raila Odinga: ", kenya_wards4@data$raila_odin, "<br>",
"Reuben Kigame: ", kenya_wards4@data$reuben_kig, "<br>",
"William Ruto: ", kenya_wards4@data$william_ru
),
highlightOptions = highlightOptions(
stroke = T,
color = "white",
weight = 5,
opacity = 0.5,
bringToFront = T
), # make wards highlightable
group = "administrative", # put polygons into a group called 'administrative'
) %>%
addRasterImage(
landcover3,
colors = rainbow(6),
opacity = .8,
group = "landcover",
layerId = "land_cover"
) %>%
addLayersControl(
baseGroups = c(
"OSM", "Carto", "OSM France"
), # the group names of our OSM layers
overlayGroups = c(
"administrative"
)
) # group name for our polygons
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj =
## prefer_proj): Discarded ellps WGS 84 in Proj4 definition: +proj=merc +a=6378137
## +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null
## +wktext +no_defs +type=crs
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj =
## prefer_proj): Discarded datum World Geodetic System 1984 in Proj4 definition
Note that we have updated the addRasterImage() with
group and layerId arguments.
addRasterImage adds a raster into leaflet. As you saw
earlier, group enables the control widget know which layer
to toggle on/off. The layerId is for parsing into an
opacity slider, which we shall work with shortly.
Our raster contains color codes that signify the landcovers of that particular region. The color codes are labelled using numbers. Even though we would prefer realworld names like forestcover, water et cetera to numerical codes, we will use them as they are for today. Numbers don’t lie anyway!
A legend is a map element that elaborates on some map features. In
leaflet, it is added using the addLegend() function.
leaflet() %>%
addTiles(
group = "OSM"
) %>% # the default web map layer is OSM, so we put into group name 'OSM'.
addProviderTiles(
providers$CartoDB.Positron,
group = "Carto"
) %>% # added an extra webmap layer and called group - CartoDB
addProviderTiles(
providers$OpenStreetMap.France,
group = "OSM France"
) %>% #added an extra webmap layer called group - OSM France
addPolygons(
data = kenya_wards4,
color = ~color_wards(kenya_wards4@data$county.x), # added the color component
opacity = 0.3,
weight = 2, # to make the colors less opaque and not shouting
popup = paste0(
"County: ", kenya_wards4@data$county, "<br>",
"Ward: ", kenya_wards4@data$ward, "<br>",
"Voters: ", kenya_wards4@data$voters, "<br>",
"David Waihiga: ", kenya_wards4@data$david_waih, "<br>",
"George Wajackoyah: ", kenya_wards4@data$george_waj, "<br>",
"Raila Odinga: ", kenya_wards4@data$raila_odin, "<br>",
"Reuben Kigame: ", kenya_wards4@data$reuben_kig, "<br>",
"William Ruto: ", kenya_wards4@data$william_ru
),
highlightOptions = highlightOptions(
stroke = T,
color = "white",
weight = 5,
opacity = 0.5,
bringToFront = T
), # make wards highlightable
group = "administrative", # put polygons into a group called 'administrative'
) %>%
addRasterImage(
landcover3,
colors = rainbow(6),
opacity = .8,
group = "landcover",
layerId = "land_cover"
) %>% # add raster layer
addLegend(
data = landcover3,
position = "bottomleft",
colors = rainbow(6),
opacity = 0.5,
labels = c(
'1', '2', '3', '4', '5', '6'
),
title = "Land classes"
) %>% # add legend
addLayersControl(
baseGroups = c(
"OSM", "Carto", "OSM France"
), #group names of our OSM layers
overlayGroups = c(
"administrative"
)
)
In the addLegend function, the number of label names
should match that of the color codes otherwise R will throw an error to
your face!
Despite the excitement of dealing with a raster in a webmap, our new
kid on the block conceals all the underlying layers. One way to solve
this is parsing the raster to the addLayerControl widget
from where it can be toggled on/off like our OSM layers. A second and
preferable option is to create an opacity slider whereby the
transparency or opaqueness of the raster will be controlled. The opacity
slider is not part of the leaflet package and thus has to be installed
separately.
We shall proceed with this second option as it makes our webmap more versatile.
# load the opacity slider package
library(leaflet.opacity)
## Warning: package 'leaflet.opacity' was built under R version 4.1.3
Let’s throw the opacity slider into our leaflet map script. Remember
the layerId we specified for our raster? It is now hereby
put into action.
###
leaflet() %>%
addTiles(
group = "OSM"
) %>% # the default web map layer is OSM, so we put into group name 'OSM'.
addProviderTiles(
providers$CartoDB.Positron,
group = "Carto"
) %>% # added an extra webmap layer and called group - CartoDB
addProviderTiles(
providers$OpenStreetMap.France,
group = "OSM France"
) %>% #added an extra webmap layer called group - OSM France
addPolygons(
data = kenya_wards4,
color = ~color_wards(kenya_wards4@data$county.x), # added the color component
opacity = 0.3,
weight = 2, # to make the colors less opaque and not shouting
popup = paste0(
"County: ", kenya_wards4@data$county, "<br>",
"Ward: ", kenya_wards4@data$ward, "<br>",
"Voters: ", kenya_wards4@data$voters, "<br>",
"David Waihiga: ", kenya_wards4@data$david_waih, "<br>",
"George Wajackoyah: ", kenya_wards4@data$george_waj, "<br>",
"Raila Odinga: ", kenya_wards4@data$raila_odin, "<br>",
"Reuben Kigame: ", kenya_wards4@data$reuben_kig, "<br>",
"William Ruto: ", kenya_wards4@data$william_ru
),
highlightOptions = highlightOptions(
stroke = T,
color = "white",
weight = 5,
opacity = 0.5,
bringToFront = T
), # make wards highlightable
group = "administrative", # put polygons into a group called 'administrative'
) %>%
addRasterImage(
landcover3,
colors = rainbow(6),
opacity = .8,
group = "landcover",
layerId = "land_cover"
) %>% # add raster layer
addLegend(
data = landcover3,
position = "bottomleft",
colors = rainbow(6),
opacity = 0.5,
labels = c(
'1', '2', '3', '4', '5', '6'
),
title = "Land classes"
) %>% # add legend
addLayersControl(
baseGroups = c(
"OSM", "Carto", "OSM France"
), # group names of our OSM layers
overlayGroups = c(
"administrative"
)
) %>% # group name for our polygons
addOpacitySlider(
layerId = "land_cover"
)
Get adventorous and play around with the opacity slider.
Finally, as the icing on the cake, or to cap this long exploration in leaflet, lets give an object name to our leaflet map script.
leaflet_wards <- leaflet() %>%
addTiles(
group = "OSM"
) %>% # the default web map layer is OSM, so we put into group name 'OSM'.
addProviderTiles(
providers$CartoDB.Positron,
group = "Carto"
) %>% # added an extra webmap layer and called group - CartoDB
addProviderTiles(
providers$OpenStreetMap.France,
group = "OSM France"
) %>% #added an extra webmap layer called group - OSM France
addPolygons(
data = kenya_wards4,
color = ~color_wards(kenya_wards4@data$county.x), # added the color component
opacity = 0.3,
weight = 2, # to make the colors less opaque and not shouting
popup = paste0(
"County: ", kenya_wards4@data$county, "<br>",
"Ward: ", kenya_wards4@data$ward, "<br>",
"Voters: ", kenya_wards4@data$voters, "<br>",
"David Waihiga: ", kenya_wards4@data$david_waih, "<br>",
"George Wajackoyah: ", kenya_wards4@data$george_waj, "<br>",
"Raila Odinga: ", kenya_wards4@data$raila_odin, "<br>",
"Reuben Kigame: ", kenya_wards4@data$reuben_kig, "<br>",
"William Ruto: ", kenya_wards4@data$william_ru
),
highlightOptions = highlightOptions(
stroke = T,
color = "white",
weight = 5,
opacity = 0.5,
bringToFront = T
), # made the wards highlightable on hover
group = "administrative", # put polygons into a group called 'administrative'
) %>%
addRasterImage(
landcover3,
colors = rainbow(6),
opacity = .8,
group = "landcover",
layerId = "land_cover"
) %>% # add raster layer
addLegend(
data = landcover3,
position = "bottomleft",
colors = rainbow(6),
opacity = 0.5,
labels = c(
'1', '2', '3', '4', '5', '6'
),
title = "Land classes"
) %>% # add legend
addLayersControl(
baseGroups = c(
"OSM", "Carto", "OSM France"
), # group names of our OSM layers
overlayGroups = c(
"administrative", "landcover"
)
) %>%# group name for our polygons + landcover raster
addOpacitySlider(
layerId = "land_cover"
)
leaflet_wards # all our leaflet map functionalities are encompassed in this name
Like a small bomb that releases its contents to a wide area, so does
our object name leaflet_wards work like so. Imagine all
those scripts and functions we added are encapsulated in that one name!
It’s for a good reason though. When you want to parse this leaflet map
to an app, say like in shiny this one name is does all the
magic needed for the map to appear in your app.
leaflet is an extremely useful tool in creating webmaps
in R, and so far it seems unrivaled. In addition, leaflet
is compatible with other R packages, such as the shiny
package for creating apps. Furthermore, leaflet removes the
need for the user to learn Javascript, since the package does all the
interpretation for the user. Javascript is a programming language used
in most web based applications. Were it not for leaflet, we would have
had to crack Javascript to do the above exercise. With a cup of coffee
of course.