Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
201 lines (148 sloc) 10 KB
title: "Salt Spring Island Tutorial"
toc: true
fig_caption: true
self_contained: yes
fontsize: 11pt
documentclass: article
bibliography: references.bib
csl: reference-style.csl
vignette: >
%\VignetteIndexEntry{Salt Spring Island Tutorial}
```{r, include = FALSE}
h <- 3.5
w <- 3.5
is_check <- ("CheckExEnv" %in% search()) || any(c("_R_CHECK_TIMINGS_",
"_R_CHECK_LICENSE_") %in% names(Sys.getenv()))
knitr::opts_chunk$set(fig.align = "center", eval = !is_check)
## Introduction
This aim of this tutorial is to show how raster data can used to build conservation problems with the _prioritizr R_ package. The data used here is a subset of a much larger data set for the Georgia Basin obtained as part of an online _Marxan_-based planning tool created for the Coastal Douglas-fir Conservation Partnership [CDFCP; @r29]. For simplicity, we focus only on Salt Spring Island, British Columbia. Salt Spring Island is central to the region and supports a diverse and globally unique mix of dry forest and savanna habitats. Today, these habitats are critically threatened due to land conversion, invasive species, and altered disturbance regimes. Known broadly as the Georgia Depression-Puget Lowlands, this region includes threatened Coastal Douglas-fir forest and Oak-Savannah habitats, also referred to as Garry oak ecosystems.
![_Extent of Coastal Douglas-fir Conservation Partnership Tool area and location of Salt Spring Island_](figures/map.jpg)
For more information on the data set refer to the [Marxan tool portal]( and the [tool tutorial](
Please note that this tutorial uses data from the _prioritizrdata R_, so ensure that it is installed before trying out the code yourself.
## Exploring the data
This data set contains two items. First, a single-band raster planning unit layer where each one hectare pixel represents a planning unit and contains its corresponding cost [@r28]. Second, a raster stack containing ecological community feature data. Field and remote sensed data were used to calculate the probability of occurrence of five key ecological communities found on Salt Spring island. Each layer in the stack represents a different community type. In order these are; Old Forest, Savannah, Wetland, Shrub, and a layer representing the inverse probability of occurrence of human commensal species. For a given layer, the cell value indicates the composite probability of encountering the suite of bird species most commonly associated with that community type.
First, load the required packages and the data.
# load packages
# load planning unit data
# load conservation feature data
Let's have a look at the planning unit data. Note that we log-transformed the raster to better visualize the variation in planning unit cost.
```{r, fig.width = w, fig.height = h}
# print planning unit data
# plot histogram of the planning unit costs
hist(values(salt_pu), main = "Distribution of costs",
xlab = "Planning unit costs")
```{r, fig.width = w, fig.height = h}
# plot map showing the planning units costs on a log-scale
plot(log(salt_pu), main = "Planning unit costs (log)")
Next, let's look at the feature data.
```{r, fig.width = 4.5, fig.height = 4.5}
# print features
# plot map showing the distribution of the features
plot(salt_features, main = names(salt_features))
## Formulating the Problem
In this tutorial, we will only cover a few of the different ways that conservation planning problems can be formulated. The examples used here are provided to highlight how different parameters can substantially---or only slightly---alter solutions. Here, we use the minimum set objective to fulfill all targets and constraints for the smallest cost. This objective is similar to that used in the _Marxan_ decision support tool. To keep this simple, we will set biodiversity targets at 17 % to reflect the [Aichi Biodiversity Target 11]( Because properties on Salt Spring Island can either be acquired in their entirety or not at all, we leave the decision framework as the default; binary decision making. This means that planning units are either selected in the solution or not selected in the solution---planning units cannot be partially acquired.
Now we will formulate the conservation planning problem.
# create problem
p1 <- problem(salt_pu, salt_features) %>%
add_min_set_objective() %>%
add_relative_targets(0.17) %>%
# print problem
Note that the `%>%` notation is used to attach the objectives, targets, and decisions to the problem. Since binary-type decisions are the default decision-type, we don't have to explicitly specify the decision-type, but we specify it here for clarity.
## Solving the problem
The _prioritizr R_ package supports three different integer linear programming solver packages: _gurobi_, _Rsymphony_, and _lpsymphony_. There are costs and benefits associated with each of these solvers, but the solver itself should have little impact on the actual solution returned (though certain solvers may take longer to return solutions than others).
First, remember that the solvers must be installed. You can check if these packages are installed by running the code below. Note that the _gurobi_ package is distributed with the [_Gurobi_ commercial software suite](, and is not available on the Comprehensive R Archive Network (CRAN). Please refer to the [_Gurobi Installation Guide_](gurobi_installation.html) for more information on installing the _gurobi R_ package.
```{r, eval = FALSE}
Now we will try solving the problem using the different solvers. We will also experiment with limiting the maximum amount of time that can be spent looking for each solution when solving the problem (using the `time_limit` parameter), and see how this alters the solutions.
```{r, message = FALSE, results = "hide"}
titles <- c() # create vector to store plot titles
s1 <- stack() # create empty stack to store solutions
# create new problem object with added solver
if (require("Rsymphony")) {
titles <- c(titles, "Rsymphony (5s)")
p2 <- p1 %>% add_rsymphony_solver(time_limit = 5)
s1 <- addLayer(s1, solve(p2))
if (require("Rsymphony")) {
titles <- c(titles, "Rsymphony (10s)")
p3 <- p1 %>% add_rsymphony_solver(time_limit = 10)
s1 <- addLayer(s1, solve(p3))
if (require("gurobi")) {
titles <- c(titles, "Gurobi (5s)")
p4 <- p1 %>% add_gurobi_solver(time_limit = 5)
s1 <- addLayer(s1, solve(p4))
if (require("lpsymphony")) {
titles <- c(titles, "lpsymphony (10s)")
p5 <- p1 %>% add_lpsymphony_solver(time_limit = 10)
s1 <- addLayer(s1, solve(p5))
Now let's visualize the solutions.
```{r, fig.height = 5.5, fig.width = 5}
plot(s1, main = titles, breaks = c(0, 0.5, 1), col = c("grey70", "darkgreen"))
We can see that all of the solutions are very similar. Therefore it would appear that for this particular problem, the solution is not highly sensitive to solver choice. For larger and more complex problems, however, we would expect the solution from _Gurobi_ to be far superior when setting time limits. At a glance, it also appears that the time limit settings did not largely impact the solutions (2 seconds vs. 5 seconds), but a more rigorous analysis is needed to investigate this.
## Adding connectivity
Isolated and fragmented populations are often more vulnerable to extinction. As a consequence, landscape connectivity is a key focus of many conservation planning exercises. There are a number of methods that can be used to increase connectivity in prioritizations. These methods typically involve adding constraints to a problem to ensure that solutions exhibit a specific property (e.g. selected planning units that form a contiguous reserve), or adding penalties to a problem to penalize solutions that exhibit specific properties (e.g. high levels of fragmentation). Here we will explore a couple different strategies for increasing connectivity in solutions. For brevity, we will use default solver which is automatically added to a problem if a solver is not manually specified.
# basic problem formulation
p6 <- problem(salt_pu, salt_features) %>%
add_min_set_objective() %>%
add_relative_targets(0.17) %>%
# print problem
```{r, results = "hide"}
titles2 <- c() # create vector to store plot titles
s2 <- stack() # create empty stack to store solutions
# no connectivity requirement
titles2 <- c(titles2, "No connectivity")
s2 <- addLayer(s2, solve(p6))
# require at least two for each selected planning unit
titles2 <- c(titles2, "Neighbor constraints (two)")
p7 <- p6 %>% add_neighbor_constraints(2)
s2 <- addLayer(s2, solve(p7))
# impose small penalty for fragmented solutions
titles2 <- c(titles2, "Boundary penalty (low)")
p8 <- p6 %>% add_boundary_penalties(50, 0.5)
s2 <- addLayer(s2, solve(p8))
# impose high penalty for fragmented solutions
titles2 <- c(titles2, "Boundary penalty (high)")
p9 <- p6 %>% add_boundary_penalties(500, 0.5)
s2 <- addLayer(s2, solve(p9))
```{r, fig.height = 5.5, fig.width = 5}
# plot solutions
plot(s2, main = titles2, breaks = c(0, 0.5, 1), col = c("grey70", "darkgreen"))
Here we can see that adding the constraints and penalties to the problem has a small, but noticeable effect on the solutions. We would expect to see larger difference between the solutions for problems that contain more than five conservation features. You may also wish to explore the `add_connectivity_penalties` and `add_feature_contiguity_constraints` functions. These functions use additional data on landscape resistance to provide a more accurate parametrization of connectivity and, in turn, deliver more effective solutions.
## References