Coming back from a bicycle ride in Tarn, I wanted to have a look at the trip. This gave me the opportunity to learn how to use the R package leafletR to obtain an HTML map using leaflet and the great projects OpenStreetMap or Thunderforest (among others).

Introduction

To use leaflet over R, two packages (at least) exist: leafletR or leaflet (developed by RStudio). After a few tests, I chose the first which directly exports a HTML/Java file that can easily been integrated in a webpage. leaflet however seems to have a nice integration for shiny.

The track was recorded through a Garmin device and I saved the six different GPX files recorded during the six different days of the ride in a directory which will be named gpx. GPX can be obtained from the web interface Garmin Connect or the web application strava (which allows you to save your tracks with a simple smartphone). I used the second one.

Installation

Installation of packages is described for (X)Ubuntu 14.04 LTS.

To obtain the desired map, I needed the following packages:

  • plotKML which was useful to read GPX files. This package depended on rgdal and sp. sp was installed using the rutteR repository as explained in this post and running the command line:
    sudo apt-get install r-cran-sp
    

    Then, rgdal (not available in the rutteR repository) needed the installation of the Ubuntu package libgdal-dev. This was performed running the following command line in a terminal:

    sudo apt-get install libgdal-dev
    

    Then, the standard R command

    install.packages(c("rgdal","plotKML"))
    

    was sufficent to finish the installation of plotKML.</li>

  • leafletR was easily installed with:
    install.packages("leafletR")
    
  • </ul>

    Creating the map

    The map is creating using three main steps:

    1. first, the GPX data are imported with plotKML. With them (and my personnal comments), I created two data frames: the first one contained the latitude and longitude of all points in the GPX files and the second one contained indications about the stop at the end of each days (latitude, longitude and elevation as indicated in the GPX files, as well as other information such as the place where we ate and slept). This is performed with the following command lines:
      library(plotKML)
      # informations about the places where we stoped at the end of each day
      stopNames = c("Toulouse", "Lac de St Ferreol", "Brassac", "Murat-Sur-Vèbre",
                    "Ambialet", "Puycelsi")
      stopDates = c("", "26-27/07", "27-28/07", "28-29/07", "29-30/07", "30/07-01/08")
      stopSleep = c("maison :)", "chez Yves et Brigitte ***","camping municipal **",
                    "Hôtel Durand **", "La Parenthèse **", "Ancienne Auberge ****")
      stopEat = c("maison :)", "Le café du lac *", "Snack étape du vieux pont *",
                  "Hôtel Durand **", "La Parenthèse **", "Le jardin des Lys ***")
      # collecting the list of all GPX files
      allGPXfiles = dir("gpx")
      myGPX = readGPX(paste0("gpx/",allGPXfiles[1]))
      # initializing the two data frames
      allPoints = data.frame(long=myGPX$tracks[[1]][[1]]$lon,
                             lat=myGPX$tracks[[1]][[1]]$lat)
      allStops = data.frame(x=myGPX$tracks[[1]][[1]]$lat[1],
                            y=myGPX$tracks[[1]][[1]]$lon[1],
                            altitude=as.numeric(myGPX$tracks[[1]][[1]]$ele[1]),
                            halte=stopNames[1], dates=stopDates[1],
                            hébergement=stopSleep[1], restauration=stopEat[1])
      # loop over GPX files to collect informations and update the data frames
      for (ind in setdiff(seq_along(allGPXfiles),1)) {
        myGPX = readGPX(paste0("gpx/",allGPXfiles[ind]))
        allPoints = rbind(allPoints, data.frame(long=myGPX$tracks[[1]][[1]]$lon,
                                                lat=myGPX$tracks[[1]][[1]]$lat))
        allStops = rbind(allStops, data.frame(x=myGPX$tracks[[1]][[1]]$lat[1],
                                              y=myGPX$tracks[[1]][[1]]$lon[1],
                                              altitude=
                           as.numeric(myGPX$tracks[[1]][[1]]$ele[1]),
                         halte=stopNames[ind], dates=stopDates[ind],
                         hébergement=stopSleep[ind], restauration=stopEat[ind]))
      }
      
    2. then, using the function styleSingle, two styles are created: the first one is for the lines that will show the ride itself (red lines) and the second one is for the stops (blue dots):
      styTrack = styleSingle(col="darkred", lwd=3)
      styStops = styleSingle(col="darkblue", fill.alpha=1, rad=5)
      
    3. finally, using these data, the map is created. With the functions SpatialLines and Line(s) from the R package sp and the function toGeoJSON a JSON file which contains information about the track is created:
      library(sp)
      tarnTour = SpatialLines(list(Lines(list(Line(allPoints)),"line1")),
                              proj4string = CRS("+proj=longlat +ellps=WGS84"))
      tarnTDat1 = toGeoJSON(data=tarnTour, name="itinéraire", dest="maps/")
      

      (a file is created in the directory maps, which is named itinéraire.geojson). Then, another file that contains the informations about the stops is created with:

      tarnTDat2 = toGeoJSON(data=allStops, name="arrêts", dest="maps/")
      

      (this file is named maps/arrêts.geojson).

      And finally, the map is created using:

      tarnTMap = leaflet(list(tarnTDat1, tarnTDat2), dest="maps/",
                         style=list(styTrack, styStops),
                         title="Tour du Tarn à Vélo - Juillet 2015", 
                         base.map=list("osm","tls"), 
                         popup=c("altitude", "halte", "dates", "hébergement",
                                 "restauration"), incl.data=TRUE)
      

      (it can be visualized opening the file maps/Tour_du_Tarn_à_Vélo_-_Juillet_2015/Tour_du_Tarn_à_Vélo_-_Juillet_2015.html). It contains a select tool to select the map style (OpenStreetMap or Thunderforest), and a popup menu at each stop with various informations provided about the stop. The option incl.data=TRUE allows the data to be include in the HTML file so that this file is self-content.</li> </ol>

      The resulting HTML page can be visualized here!

      The result is dedicated to my beloved husband who organized the whole trip.

      </div>