tmap is a package for making thematic maps. In this
Notebook, we’ll use tmap to make a map that includes the
Yosemite:
- park boundary
- roads
- cell towers
- campgrounds
We’ll make two versions of the map - a traditional static map and an
interactive map.
Import all the layers
First, import the park boundary, cell towers, and roads. At the same
time, we’ll (re)project everything into UTM 11N WGS 84.
library(sf)
library(dplyr)
epsg_utm11n_wgs84 <- 32611
## Park boundary
yose_bnd_utm <- st_read(dsn="./data", layer="yose_boundary") |>
st_transform(epsg_utm11n_wgs84)
Reading layer `yose_boundary' from data source
`D:\Workshops\R-Spatial\rspatial_mod\outputs\rspatial_scgis23\exercises\data' using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 11 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: -119.8864 ymin: 37.4947 xmax: -119.1964 ymax: 38.18515
Geodetic CRS: North_American_Datum_1983
## Roads
yose_roads_utm <- st_read("./data/yose_roads.gdb", "Yosemite_Roads") |>
st_transform(epsg_utm11n_wgs84)
Reading layer `Yosemite_Roads' from data source
`D:\Workshops\R-Spatial\rspatial_mod\outputs\rspatial_scgis23\exercises\data\yose_roads.gdb' using driver `OpenFileGDB'
Simple feature collection with 823 features and 40 fields
Geometry type: MULTILINESTRING
Dimension: XY
Bounding box: xmin: 234658.1 ymin: 4139484 xmax: 324852.6 ymax: 4250252
Projected CRS: NAD83 / UTM zone 11N
## Cell towers
gdb_fn <- "./data/yose_communications.gdb"; file.exists(gdb_fn) ## two commands separated by ;
[1] TRUE
yose_celltwrs_utm <- st_read(gdb_fn, "Cell_Towers") |>
st_transform(epsg_utm11n_wgs84)
Reading layer `Cell_Towers' from data source
`D:\Workshops\R-Spatial\rspatial_mod\outputs\rspatial_scgis23\exercises\data\yose_communications.gdb'
using driver `OpenFileGDB'
Simple feature collection with 5 features and 6 fields
Geometry type: POINT
Dimension: XY
Bounding box: xmin: 251532.4 ymin: 4158756 xmax: 293307.2 ymax: 4194328
Projected CRS: NAD83 / UTM zone 11N
## Campsites
yose_campgrounds_utm <- st_read(dsn="./data", layer="yose_poi") |>
st_transform(epsg_utm11n_wgs84) |>
filter(POITYPE == "Campground")
Reading layer `yose_poi' from data source
`D:\Workshops\R-Spatial\rspatial_mod\outputs\rspatial_scgis23\exercises\data' using driver `ESRI Shapefile'
Simple feature collection with 2720 features and 30 fields
Geometry type: POINT
Dimension: XY
Bounding box: xmin: 246416.2 ymin: 4153717 xmax: 301510.7 ymax: 4208419
Projected CRS: NAD83 / UTM zone 11N
CHALLENGE: How many cell towers & campgrounds
How many cell towers are there? How many campgrounds are there? Answer
# Your answer here
Map the Park Boundary
Let’s start with a simple map of just the park boundary:
library(tmap)
tmap_mode("plot")
tmap mode set to plotting
tm_shape(yose_bnd_utm) + tm_polygons()

Now make the fill and outline dark green, the fill 20% transparent
(alpha = 0), the border line a little thicker (lwd = 2):
tm_shape(yose_bnd_utm) +
tm_polygons(col = "darkgreen", alpha = 0.2, border.col = "darkgreen", lwd = 2)

Next, we’ll add a title by adding tm_layout() to our
tmap object:
tm_shape(yose_bnd_utm) +
tm_polygons(col = "darkgreen", alpha = 0.2, border.col = "darkgreen", lwd = 2) +
tm_layout(main.title = "Yosemite NP Cell Towers")

CHALLENGE: Add a scale bar
Add a scale bar to the map. Hint: add tm_scale_bar() to
the map. Answer
# Your answer here
Add the Roads and the Cell Towers
Next we’ll add the roads. This requires tacking on another
tm_shape(), followed by a function that draws lines.
tm_shape(yose_bnd_utm) +
tm_polygons(col = "darkgreen", alpha = 0.2, border.col = "darkgreen", lwd = 2) +
tm_shape(yose_roads_utm) +
tm_lines(col = "gray50")

In a similar fashion, we’ll add the cell towers as little blue
dots:
tm_shape(yose_bnd_utm) +
tm_polygons(col = "darkgreen", alpha = 0.2, border.col = "darkgreen", lwd = 2) +
tm_shape(yose_roads_utm) +
tm_lines(col = "gray50") +
tm_shape(yose_celltwrs_utm) +
tm_symbols(col = "blue", size = 0.5)

CHALLENGE: Add the campgrounds
Add the campgrounds to the map as little red dots. Hint: you can
render point layers with tm_symbols() or
tm_dots(). Answer
# Your answer here
Make an interactive map
Note: interactive maps created by tmap can cause
problems when you save a R Notebook to HTML. It is recommended that you
run the following code in an R script rather than a Notebook.
We can switch to ‘interactive map mode’ by running
tmap_mode():
## tmap_mode("view")
## tmap_mode("plot") # go back to plot mode
Now that we’re in ‘view’ mode, tmap objects be rendered as little
interactive maps. We can ‘redraw’ the last tmap object using
tmap_last():
tmap_last()
Switch-out the basemap:
tm_shape(yose_bnd_utm |> st_geometry()) +
tm_polygons(col = "darkgreen", alpha = 0.2, border.col = "darkgreen", lwd = 2) +
tm_shape(yose_roads_utm |> st_geometry()) +
tm_lines(col = "gray50") +
tm_shape(yose_celltwrs_utm |> st_geometry()) +
tm_symbols(col = "blue", size = 0.5) +
tm_shape(yose_campgrounds_utm |> st_geometry()) +
tm_symbols(col = "red", size = 0.5) +
tm_basemap("Esri.WorldTopoMap")
End
Congratulations, you have completed the Notebook!
To view your Notebook at HTML, save it (again), then click the
‘Preview’ button in the RStudio toolbar.
LS0tDQp0aXRsZTogIk1ha2UgYSBNYXAgb2YgWW9zZW1pdGUiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCi0tLQ0KDQpgdG1hcGAgaXMgYSBwYWNrYWdlIGZvciBtYWtpbmcgdGhlbWF0aWMgbWFwcy4gSW4gdGhpcyBOb3RlYm9vaywgd2UnbGwgdXNlIGB0bWFwYCB0byBtYWtlIGEgbWFwIHRoYXQgaW5jbHVkZXMgdGhlIFlvc2VtaXRlOg0KDQotIHBhcmsgYm91bmRhcnkgIA0KLSByb2FkcyAgDQotIGNlbGwgdG93ZXJzICANCi0gY2FtcGdyb3VuZHMNCg0KV2UnbGwgbWFrZSB0d28gdmVyc2lvbnMgb2YgdGhlIG1hcCAtIGEgdHJhZGl0aW9uYWwgc3RhdGljIG1hcCBhbmQgYW4gaW50ZXJhY3RpdmUgbWFwLg0KDQojIyBJbXBvcnQgYWxsIHRoZSBsYXllcnMNCg0KRmlyc3QsIGltcG9ydCB0aGUgcGFyayBib3VuZGFyeSwgY2VsbCB0b3dlcnMsIGFuZCByb2Fkcy4gQXQgdGhlIHNhbWUgdGltZSwgd2UnbGwgKHJlKXByb2plY3QgZXZlcnl0aGluZyBpbnRvIFVUTSAxMU4gV0dTIDg0Lg0KDQpgYGB7ciBjaHVuazAxfQ0KbGlicmFyeShzZikNCmxpYnJhcnkoZHBseXIpDQoNCmVwc2dfdXRtMTFuX3dnczg0IDwtIDMyNjExDQoNCiMjIFBhcmsgYm91bmRhcnkNCnlvc2VfYm5kX3V0bSA8LSBzdF9yZWFkKGRzbj0iLi9kYXRhIiwgbGF5ZXI9Inlvc2VfYm91bmRhcnkiKSB8PiANCiAgc3RfdHJhbnNmb3JtKGVwc2dfdXRtMTFuX3dnczg0KQ0KDQojIyBSb2Fkcw0KeW9zZV9yb2Fkc191dG0gPC0gc3RfcmVhZCgiLi9kYXRhL3lvc2Vfcm9hZHMuZ2RiIiwgIllvc2VtaXRlX1JvYWRzIikgfD4gDQogIHN0X3RyYW5zZm9ybShlcHNnX3V0bTExbl93Z3M4NCkNCg0KIyMgQ2VsbCB0b3dlcnMNCmdkYl9mbiA8LSAiLi9kYXRhL3lvc2VfY29tbXVuaWNhdGlvbnMuZ2RiIjsgZmlsZS5leGlzdHMoZ2RiX2ZuKSAgIyMgdHdvIGNvbW1hbmRzIHNlcGFyYXRlZCBieSA7DQp5b3NlX2NlbGx0d3JzX3V0bSA8LSBzdF9yZWFkKGdkYl9mbiwgIkNlbGxfVG93ZXJzIikgfD4gDQogIHN0X3RyYW5zZm9ybShlcHNnX3V0bTExbl93Z3M4NCkNCg0KIyMgQ2FtcHNpdGVzDQp5b3NlX2NhbXBncm91bmRzX3V0bSA8LSBzdF9yZWFkKGRzbj0iLi9kYXRhIiwgbGF5ZXI9Inlvc2VfcG9pIikgfD4gDQogIHN0X3RyYW5zZm9ybShlcHNnX3V0bTExbl93Z3M4NCkgfD4gDQogIGZpbHRlcihQT0lUWVBFID09ICJDYW1wZ3JvdW5kIikNCmBgYA0KDQojIyBDSEFMTEVOR0U6IEhvdyBtYW55IGNlbGwgdG93ZXJzICYgY2FtcGdyb3VuZHMNCg0KSG93IG1hbnkgY2VsbCB0b3dlcnMgYXJlIHRoZXJlPyBIb3cgbWFueSBjYW1wZ3JvdW5kcyBhcmUgdGhlcmU/IFtBbnN3ZXJdKGh0dHBzOi8vYml0Lmx5LzNreUZNT1QpDQoNCmBgYHtyIGNodW5rMDJ9DQojIFlvdXIgYW5zd2VyIGhlcmUNCg0KYGBgDQoNCiMjIE1hcCB0aGUgUGFyayBCb3VuZGFyeQ0KDQpMZXQncyBzdGFydCB3aXRoIGEgc2ltcGxlIG1hcCBvZiBqdXN0IHRoZSBwYXJrIGJvdW5kYXJ5Og0KDQpgYGB7ciBjaHVuazAzfQ0KbGlicmFyeSh0bWFwKQ0KdG1hcF9tb2RlKCJwbG90IikNCg0KdG1fc2hhcGUoeW9zZV9ibmRfdXRtKSArIHRtX3BvbHlnb25zKCkNCmBgYA0KDQpOb3cgbWFrZSB0aGUgZmlsbCBhbmQgb3V0bGluZSBkYXJrIGdyZWVuLCB0aGUgZmlsbCAyMCUgdHJhbnNwYXJlbnQgKGFscGhhID0gMCksIHRoZSBib3JkZXIgbGluZSBhIGxpdHRsZSB0aGlja2VyIChsd2QgPSAyKToNCg0KYGBge3IgY2h1bmswNH0NCnRtX3NoYXBlKHlvc2VfYm5kX3V0bSkgKyANCiAgdG1fcG9seWdvbnMoY29sID0gImRhcmtncmVlbiIsIGFscGhhID0gMC4yLCBib3JkZXIuY29sID0gImRhcmtncmVlbiIsIGx3ZCA9IDIpDQpgYGANCg0KTmV4dCwgd2UnbGwgYWRkIGEgdGl0bGUgYnkgYWRkaW5nIGB0bV9sYXlvdXQoKWAgdG8gb3VyIHRtYXAgb2JqZWN0Og0KDQpgYGB7ciBjaHVuazA1fQ0KdG1fc2hhcGUoeW9zZV9ibmRfdXRtKSArIA0KICB0bV9wb2x5Z29ucyhjb2wgPSAiZGFya2dyZWVuIiwgYWxwaGEgPSAwLjIsIGJvcmRlci5jb2wgPSAiZGFya2dyZWVuIiwgbHdkID0gMikgKw0KdG1fbGF5b3V0KG1haW4udGl0bGUgPSAiWW9zZW1pdGUgTlAgQ2VsbCBUb3dlcnMiKQ0KYGBgDQoNCiMjIENIQUxMRU5HRTogQWRkIGEgc2NhbGUgYmFyDQoNCkFkZCBhIHNjYWxlIGJhciB0byB0aGUgbWFwLiBIaW50OiBhZGQgYHRtX3NjYWxlX2JhcigpYCB0byB0aGUgbWFwLiBbQW5zd2VyXShodHRwczovL2JpdC5seS8zaFdtRFZ2KQ0KDQpgYGB7ciBjaHVuazA2fQ0KIyBZb3VyIGFuc3dlciBoZXJlDQoNCmBgYA0KDQojIyBBZGQgdGhlIFJvYWRzIGFuZCB0aGUgQ2VsbCBUb3dlcnMNCg0KTmV4dCB3ZSdsbCBhZGQgdGhlIHJvYWRzLiBUaGlzIHJlcXVpcmVzIHRhY2tpbmcgb24gYW5vdGhlciBgdG1fc2hhcGUoKWAsIGZvbGxvd2VkIGJ5IGEgZnVuY3Rpb24gdGhhdCBkcmF3cyBsaW5lcy4NCg0KYGBge3IgY2h1bmswN30NCnRtX3NoYXBlKHlvc2VfYm5kX3V0bSkgKyANCiAgdG1fcG9seWdvbnMoY29sID0gImRhcmtncmVlbiIsIGFscGhhID0gMC4yLCBib3JkZXIuY29sID0gImRhcmtncmVlbiIsIGx3ZCA9IDIpICsNCnRtX3NoYXBlKHlvc2Vfcm9hZHNfdXRtKSArDQogIHRtX2xpbmVzKGNvbCA9ICJncmF5NTAiKQ0KYGBgDQoNCkluIGEgc2ltaWxhciBmYXNoaW9uLCB3ZSdsbCBhZGQgdGhlIGNlbGwgdG93ZXJzIGFzIGxpdHRsZSBibHVlIGRvdHM6DQoNCmBgYHtyIGNodW5rMDh9DQp0bV9zaGFwZSh5b3NlX2JuZF91dG0pICsgDQogIHRtX3BvbHlnb25zKGNvbCA9ICJkYXJrZ3JlZW4iLCBhbHBoYSA9IDAuMiwgYm9yZGVyLmNvbCA9ICJkYXJrZ3JlZW4iLCBsd2QgPSAyKSArDQp0bV9zaGFwZSh5b3NlX3JvYWRzX3V0bSkgKw0KICB0bV9saW5lcyhjb2wgPSAiZ3JheTUwIikgKw0KdG1fc2hhcGUoeW9zZV9jZWxsdHdyc191dG0pICsNCiAgdG1fc3ltYm9scyhjb2wgPSAiYmx1ZSIsIHNpemUgPSAwLjUpDQpgYGANCg0KIyMgQ0hBTExFTkdFOiBBZGQgdGhlIGNhbXBncm91bmRzIA0KDQpBZGQgdGhlIGNhbXBncm91bmRzIHRvIHRoZSBtYXAgYXMgbGl0dGxlIHJlZCBkb3RzLiBIaW50OiB5b3UgY2FuIHJlbmRlciBwb2ludCBsYXllcnMgd2l0aCBgdG1fc3ltYm9scygpYCBvciBgdG1fZG90cygpYC4gW0Fuc3dlcl0oaHR0cHM6Ly9iaXQubHkvM2hRanZkRCkNCg0KYGBge3IgY2h1bmswOX0NCiMgWW91ciBhbnN3ZXIgaGVyZQ0KDQpgYGANCg0KIyMgTWFrZSBhbiBpbnRlcmFjdGl2ZSBtYXANCg0KKl9fTm90ZV9fOiBpbnRlcmFjdGl2ZSBtYXBzIGNyZWF0ZWQgYnkgdG1hcCBjYW4gY2F1c2UgcHJvYmxlbXMgd2hlbiB5b3Ugc2F2ZSBhIFIgTm90ZWJvb2sgdG8gSFRNTC4gSXQgaXMgcmVjb21tZW5kZWQgdGhhdCB5b3UgcnVuIHRoZSBmb2xsb3dpbmcgY29kZSBpbiBhbiBSIHNjcmlwdCByYXRoZXIgdGhhbiBhIE5vdGVib29rLioNCg0KV2UgY2FuIHN3aXRjaCB0byAnaW50ZXJhY3RpdmUgbWFwIG1vZGUnIGJ5IHJ1bm5pbmcgYHRtYXBfbW9kZSgpYDoNCg0KYGBgDQojIyB0bWFwX21vZGUoInZpZXciKQ0KDQojIyB0bWFwX21vZGUoInBsb3QiKSAgIyBnbyBiYWNrIHRvIHBsb3QgbW9kZQ0KYGBgDQoNCk5vdyB0aGF0IHdlJ3JlIGluICd2aWV3JyBtb2RlLCB0bWFwIG9iamVjdHMgYmUgcmVuZGVyZWQgYXMgbGl0dGxlIGludGVyYWN0aXZlIG1hcHMuIFdlIGNhbiAncmVkcmF3JyB0aGUgbGFzdCB0bWFwIG9iamVjdCB1c2luZyBgdG1hcF9sYXN0KClgOg0KDQpgYGANCnRtYXBfbGFzdCgpDQpgYGANCg0KU3dpdGNoLW91dCB0aGUgYmFzZW1hcDoNCg0KYGBgDQp0bV9zaGFwZSh5b3NlX2JuZF91dG0gfD4gc3RfZ2VvbWV0cnkoKSkgKyANCiAgdG1fcG9seWdvbnMoY29sID0gImRhcmtncmVlbiIsIGFscGhhID0gMC4yLCBib3JkZXIuY29sID0gImRhcmtncmVlbiIsIGx3ZCA9IDIpICsNCnRtX3NoYXBlKHlvc2Vfcm9hZHNfdXRtIHw+IHN0X2dlb21ldHJ5KCkpICsNCiAgdG1fbGluZXMoY29sID0gImdyYXk1MCIpICsNCnRtX3NoYXBlKHlvc2VfY2VsbHR3cnNfdXRtIHw+IHN0X2dlb21ldHJ5KCkpICsNCiAgdG1fc3ltYm9scyhjb2wgPSAiYmx1ZSIsIHNpemUgPSAwLjUpICsNCnRtX3NoYXBlKHlvc2VfY2FtcGdyb3VuZHNfdXRtIHw+IHN0X2dlb21ldHJ5KCkpICsNCiAgdG1fc3ltYm9scyhjb2wgPSAicmVkIiwgc2l6ZSA9IDAuNSkgKw0KICB0bV9iYXNlbWFwKCJFc3JpLldvcmxkVG9wb01hcCIpDQpgYGANCg0KIyMgQ29uZmlndXJlIFBvcC11cHMNCg0KTGFzdGx5IHdlJ2xsIGRpc2FibGUgaW50ZXJhY3Rpdml0eSAoaS5lLiwgaG92ZXItb3ZlciB0ZXh0IGFuZCBwb3B1cCB3aW5kb3dzKSBvbiBhbGwgbGF5ZXJzIGV4Y2VwdCBmb3IgdGhlIGNhbXBncm91bmRzOiANCg0KYGBgDQp0bV9zaGFwZSh5b3NlX2JuZF91dG0gfD4gc3RfZ2VvbWV0cnkoKSkgKyANCiAgdG1fcG9seWdvbnMoY29sID0gImRhcmtncmVlbiIsIGFscGhhID0gMC4yLCBib3JkZXIuY29sID0gImRhcmtncmVlbiIsIGx3ZCA9IDIsIGludGVyYWN0aXZlID0gRkFMU0UpICsNCnRtX3NoYXBlKHlvc2Vfcm9hZHNfdXRtIHw+IHN0X2dlb21ldHJ5KCkpICsNCiAgdG1fbGluZXMoY29sID0gImdyYXk1MCIsIGludGVyYWN0aXZlID0gRkFMU0UpICsNCnRtX3NoYXBlKHlvc2VfY2VsbHR3cnNfdXRtIHw+IHN0X2dlb21ldHJ5KCkpICsNCiAgdG1fc3ltYm9scyhjb2wgPSAiYmx1ZSIsIHNpemUgPSAwLjUsIGludGVyYWN0aXZlID0gRkFMU0UpICsNCnRtX3NoYXBlKHlvc2VfY2FtcGdyb3VuZHNfdXRtIHw+IHNlbGVjdChQT0lOQU1FKSkgKw0KICB0bV9zeW1ib2xzKGNvbCA9ICJyZWQiLCBzaXplID0gMC41LCBpZCA9ICJQT0lOQU1FIikgKw0KICB0bV9iYXNlbWFwKCJFc3JpLldvcmxkVG9wb01hcCIpDQpgYGANCg0KVGlwOiBmb3IgbW9yZSBjb250cm9sIG92ZXIgcG9wLXVwcywgdXNlIGxlYWZsZXQuDQoNCiMjIEVuZA0KDQpDb25ncmF0dWxhdGlvbnMsIHlvdSBoYXZlIGNvbXBsZXRlZCB0aGUgTm90ZWJvb2shIA0KDQpUbyB2aWV3IHlvdXIgTm90ZWJvb2sgYXQgSFRNTCwgc2F2ZSBpdCAoYWdhaW4pLCB0aGVuIGNsaWNrIHRoZSAnUHJldmlldycgYnV0dG9uIGluIHRoZSBSU3R1ZGlvIHRvb2xiYXIuDQoNCg0K