TITLE: Making a geoJSON powered Leaflet map
DATE: 2018-04-18
AUTHOR: John L. Godlee
====================================================================


I made a website for my labgroup using Jekyll and Github-pages. It
can be seen here at seosaw.github.io. The bit I want to show off
about is the interactive map I made for the page on data and sites,
which can be seen here.

 [seosaw.github.io]: https://seosaw.github.io
 [here]: https://seosaw.github.io/data.html

The map is powered using leaflet, which is a Javascript library
specifically for making maps.

 [leaflet]: http://leafletjs.com

This is how I got our data to run on the map.

First I have to generate the geoJSON files for the location of our
sites as points, and also for a polygon layer showing the extent of
savannas in Africa. I used R to generate these files because that
is the platform I have the most experience with GIS stuff in. This
is a stripped down version of the script I used to transform the
original data .csv and .shp into geoJSON outputs:

For the plot data:

   # Packages ----
   library(dplyr)
   library(geojsonio)
   library(readr)


   # Read in plot data
   plots <- read.csv("plots.csv")

   # Create intermediate data frame ----
   plots_export <- plots %>%
       filter(!is.na(longitude_of_centre) &
!is.na(latitude_of_centre)) %>%
       mutate(name = paste(name, "-", plotcode),
                    lon =
as.numeric(as.character(longitude_of_centre)),
                    lat =
as.numeric(as.character(latitude_of_centre)),
                    area_of_plot = round(as.numeric(area_of_plot)
* 10000, digits = 2)) %>%
       select(name, country,
                    area_of_plot,
                    lon, lat) %>%
       filter(!is.na(lon), !is.na(lat))

   # Export to json ----
   geojson_write(input = plots_export,
       lat = "lat",
       lon = "lon",
       file = "plots_export")

And for the polygon data:

   # Packages ----
   library(rgdal)
   library(rgeos)
   library(geojsonio)

   # Read shapefile ----
   white_veg <- readOGR(dsn="whitesveg",
       layer="Whites vegetation")

   # Attempting to transform CRS to wgs84 ----
   ## No CRS given
   proj4string(white_veg)
   white_veg <- spTransform(white_veg,
       CRS("+proj=longlat +datum=WGS84"))

   white_veg_sub <- white_veg[which((white_veg$DESCRIPTIO ==
"Moist-infertile savanna") |
       (white_veg$DESCRIPTIO == "Mosaics of forest") |
       (white_veg$DESCRIPTIO == "Mopane savanna") |
       (white_veg$DESCRIPTIO == "Montane Forest") |
       (white_veg$DESCRIPTIO == "Hydropmorphic grassland") |
       (white_veg$DESCRIPTIO == "Arid-fertile savanna") |
       (white_veg$DESCRIPTIO == "Sedge and reed swamp")),]


   white_woodlands_poly <- gUnaryUnion(white_veg_sub)

   # Output to geojson ----
   # Export to json ----
   geojson_write(input = white_woodlands_poly,
       file = "miombo_po")

The polygon data comes from White's 1983 vegetation map of Africa,
which remains the best approximation of the biomes of Africa, even
though it was constructed in a very non-systematic fashion.

Next I have to convert these geoJSON files to .js files and name
them as variables by adding a variable designation at the top of
the files like this:

   var miombo = [
       {"type": "FeatureCollection",
     "features": [{
       "type": "Feature",

   ...

   var locations = [
   { "type": "Feature", "id": 1, "properties": { "name": "Kruger
Skukuza - SSM-001", "country": "South Africa", "area_of_plot":
40000.0, "lon": 31.4970563, "lat": -25.0197541 }, "geometry": {
"type": "Point", "coordinates": [ 31.4970563, -25.0197541 ] } },
   { "type": "Feature", "id": 2, "properties": { "name":
"Hwange-Farm41 - ZHH-001", "country": "Zimbabwe", "area_of_plot":
1000.0, "lon": 27.90663333, "lat": -18.62653333 }, "geometry": {
"type": "Point", "coordinates": [ 27.90663333, -18.62653333 ] } },

   ...

Then, I need to construct the javascript file which makes the map,
which calls the map tiles (L.tileLayer), and gives the plot
locations and polygons various aesthetic attributes:

   var mymap = L.map('leaf-map').setView([-16.5, 24.7], 4);


L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?ac
cess_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcm
Z3N3gifQ.rJcFIG214AriISLbB6B5aw', {
     maxZoom: 18,
     id: 'mapbox.streets'
   }).addTo(mymap);

   var plotLocOptions = {
     fillOpacity: 0.5,
     weight: 0.2,
     radius: 5,
     fillColor: "#7A0099",
     color: "#7A0099"
   };

   function miomboOptions(feature) {
     return {
       fillOpacity: 0.9,
       fillColor: "#179600",
       color: "#179600",
       weight: 0.1
   };
   }

   L.geoJSON(miombo, {style: miomboOptions}).addTo(mymap);

   L.geoJSON(locations, {
     pointToLayer: function(feature, latlng) {
       return L.circleMarker(latlng, plotLocOptions);
     },
       onEachFeature: function(feature, layer){
           layer.bindPopup("Name: " + feature.properties.name +
"<br>" +
           "Country: " + feature.properties.country + "<br>" +
         "Plot Area: " + feature.properties.area_of_plot + "
m<sup>2</sup>");
       }
   }).addTo(mymap);

The only thing left to do is make sure all of these scripts are
called in the right order in the HTML file:


   <script src="/scripts/plot_loc.js"></script> <!plot locations>
   <script src="/scripts/miombo_po.js"></script> <!polygon
locations>
   <script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet.js"

integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu
9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log=="
       crossorigin="">
   </script> <!leaflet script>
   <script src="/scripts/leaf-map.js"></script> <!map construction
script>

 ![Leaflet map](https://johngodlee.xyz/img_full/geojson/map.png)