Estimating hiking velocity with rHike

April 13, 2020
r sf gdistance rHike

updated: May 13, 2020 (replaced Laplace with Lorentz distribution at Campbell’s suggestion)

I wanted to learn how to write an R package and I had this recurrent use-case (estimating cost-distance on a grid), so I made rHike. It’s a super-lightweight package that builds on Jacob van Etten’s gdistance by implementing both Tobler’s (1993) and Campbell’s (2019) hiking functions, though others could be added. Mainly, it just simplifies the user interface. Development mostly followed the workflow suggested by Hadley Wickham and Jenny Bryan in their R Packages book. Mostly…

Where are we going? Intuitively, walking speed should vary as a function of slope. Campbell’s Hiking Function reflects this using an empirically derived version of the Lorentz distribution:

\[ f(x) = \frac{c}{\pi\, b\left(1+\left[\frac{x-a}{b}\right]^{2}\right)} + d + e\, x \]

where \(x\) is the slope at a location measured in degrees. The idea here is first to get an estimate of slope, then use a hiking function like Campbell’s to calculate velocity, and finally to use velocity to estimate travel time (among other cost-distances).

slope <- seq(-50, 50, by = 1)

velocity <- hf_campbell(slope, decile = 10)

R Preamble


Coordinate Reference System (CRS):

utm12 <- st_crs(26912)

It should really be emphasized that

the unit of projection should match the unit of the stored values.

In this case, elevation is in meters, so the projection should be in meters too.

Data Wrangling

First, we read in a DEM of the foothills in Salt Lake City, Utah:

dem <- raster(system.file("extdata/slc.tif", package = "rHike"))

dem <- projectRaster(dem, crs = utm12$proj4string)

Next we generate an arbitrary point pattern.

start_points <- st_sf(id = 1:3,
                      typ = "start",
                      geometry = st_sfc(st_point(c(424350, 4514200)),
                                        st_point(c(426000, 4515000)),
                                        st_point(c(429000, 4516500)),
                                        crs = utm12))

end_points <- st_sf(id = 1:2,
                    typ = "end",
                    geometry = st_sfc(st_point(c(426200, 4516400)),
                                      st_point(c(427600, 4515600)),
                                      crs = utm12))

Now we use the elevation data to generate a slope raster and calculate a velocity surface for the average hiker using Campbell’s Hiking Function.

slope <- hf_slope(dem)

velocity <- hf_velocity(slope, hf = "campbell", decile = 10)

Calculating Accumulated Cost

Accumulated cost-distance is the total time it takes to travel from one location to another; in this case, to all other locations in the landscape of interest.

cost <- hf_accCost(velocity, 
                   fun = function(x) 1/mean(x), 
                   points = start_points)

# convert seconds to minutes
cost <- cost/60

That looks about right, twenty’ish minutes for the average hiker to walk a half-mile or so around the SLC foothills.

Calculating Least-Cost Path

short_paths <- hf_shortPath(velocity, start_points, end_points)

Future Work

In this post, conversion between different units was done on the fly. It would be nice to introduce methods to do that in a more rigorous way, so I might look into integrating the units package at some point.


Tobler, Waldo R. (1993). “Three Presentations on Geographical Analysis and Modeling: Non-Isotropic Geographic Modeling, Speculations on the Geometry of Geography, and Global Spatial Analysis.” 93-1.

Campbell, Michael J., Philip E. Dennison, Bret W. Butler, and Wesley G. Page (2019). "Using crowdsourced fitness tracker data to model the relationship between slope and travel rates. 106, 93-107.

Plotting fieldwork with mapview

April 7, 2020
r sf mapview fieldwork