This package implements algorithms to compute commonly used indices to assess river networks fragmentation. All those indices assume a conceptualization of the river networks as a graph \(L = (E,V)\), where vertices (nodes) \(V\) represent single reaches, and edges (links) \(E\) represent either confluences or longitudinal barriers.
For example, the graphs below represents a river with ten reaches. The graph on the left is directed, i.e. edges are defined for ordered pair of vertices. The graph on the right is undirected, as the order of vertices for the definition of edges is unimportant. Both graph have a 'tree-like' structure, since no loops exist (acyclic graphs): this structure can be used to describe a river system. In both examples, both barriers and confluences are present. The edges between nodes 1 and 2 and 3 and 2 are confluences. The edge between node 2 and 4 is a barrier.
river networks-level connectivity can be expressed in terms of coincidence probability (Pascual-Hortal and Saura, 2006), i.e. the probability that two random points in a river network are connected. Once the coincidence probability \(I_{ij}\) is defined for each couple of \(i,j\) nodes in the graph, generalized connectivity indices for catchment and reach scales can be calculated.
Given this conceptualization, a catchment-scale connectivity index (CCI) can be calculated as:
\[ \ CCI = \sum_{i = 1}^{n} \sum_{j = 1}^{n} I_{ij} \frac{w_i w_j}{W^2} \] Where \(w_i\) and \(w_j\) are some node-level attributes (weights), and \(W\) is the sum of sum of the nodes weights for the whole river networks.
A reach-scale connectivity index (RCI) can be calculated by limiting the summation to all the connections to the single node \(i\). \[ \ RCI_i = \sum_{j = 1}^{n} I_{ij} \frac{w_j}{W} \]
Nodes weights can be arbitrarily chosen. Common features used are the reach length (\(l_i\)), area(\(A_i\)), or volume(\(V_i\)). Alternatively, the habitat suitability index (HSI) can be used, defined as the ratio of length/area that is suitable for a specific organism. \[ \ HSI_i = \frac{l_i,suitable}{l_i} \mbox{ ; } HSI_i = \frac{A_i,suitable}{A_i} \] Here \(l_i,suitable\) and \(A_i,suitable\) are the fractions of length/area of reach \(i\) that are suitable, and are usually refferred to as weighted suitable length or weighted suitable area.
The coincidence probability depends on several factors: the presence of barriers between nodes \(i\) and \(j\) , the presence of suitable habitats in nodes \(i\) and \(j\), the distance between \(i\) and \(j\), and the quality of the habitat alongside the connection. The value of \(I_{ij}\) is thus determined by several contributions. The harmonic mean of such contributions is used to follow a 'one-bad-all-bad' approach:
\[ \ I_{ij} = c_{ij}B_{ij} \] where \(c_{ij}\) is a 'barrier coincidence probability' depending on the presence of barriers between nodes \(i\) and \(j\), \(f_{ij}\) is a 'landscape coincidence probability' depending on the landscape friction in the movement between nodes \(i\) and \(j\), and \(B_{ij}\) is a 'dispersal coincidence probability' depends on the distance between nodes \(i\) and \(j\).
The barriers factor depends on the presence of barriers between nodes \(i\) and \(j\), and can be expressed as a function of the types of barriers present in the path expressed as a sequence of passability values. The passability \(p_m\) for the \(m\)-th barrier is defined as the probability that the reaches immediately upstream and downstream the barrier \(m\) are connected.
If the flow directionality is not relevant (i.e. the river graph is undirected),
\[ \ c_{ij} = \prod_{m = 1}^{k} p_m^u p_m^d \] Where the product extends over the \(k\) nodes that are part of the path connecting reaches \(i\) and \(j\), \(p_m^u\) is the upsstream passability of the \(m\)-th barrier and \(p_m^u\) is the upstream passability of the \(m\)-th barrier. This definition based solely on products yields a symmetric coincidence probability (i.e. \(c_{ij} = c_{ji}\)).
A directional version of \(c_{ij}\) can be defined as: \[ \ c_{ij} = \prod_{m = 1}^{k} p_m^{eq} \] \[ p_m^{eq} = \begin{cases} p_m^u & \mbox{if barrier m is encountered moving upstream in the path from i to j } \ p_m^d & \mbox{if barrier m is encountered moving downstream in the path from i to j } \end{cases} \] If \(i\) and \(j\) are located in different sub-catchments, the path from i to j will be moving downstream in some sections and upstream in some other secions: this \(p_m^{eq}\) definition ensures the retained passability value is consistent with the directionality of the path from \(i\) to \(j\) (i.e. \(c_{ij} \ne c_{ji}\))
The dispersal coincidence probability can be calculated as a function of the distance between reaches. An exponential dispersal kernel can be used:
\[ \ B_{ij} = PD^{d_{ij}} \] where \(PD\) is in the \((0,1)\) interval (smaller values mean more restricted movement), and \(d_{ij}\) is the distance between reaches \(i\) and \(j\). Alternatively, a threshold based probability can be used: \[ \ B_{ij} = \begin{cases} 0 & \mbox{when } d_{ij}>d_{tr} \ 1 & \mbox{when } d_{ij}<=d_{tr} \end{cases} \] Both definitions can be easily adapted to asymmetric dispersal by defining \(PD_{d}\), \(PD_{u}\), \(d_{tr,u}\), and \(d_{tr,d}\), and calculating \(B_{ij} = B_{ij}^u B_{ij}^d\) where \(B_{ij}^u\) and \(B_{ij}^d\) are the index \(B_{ij}\) contribution calculated for the 'downstream moving' and 'upstream moving' sections in the path from reach \(i\) to \(j\).
The distance \(d_{ij}\) can be either the geometric distance, or any other measure of effective distance (e.g. \(d_{ij} / (1-HSI)\) provides an estimate of effective distance that depends on the habitat suitability index between reaches \(i\) and \(j\))
All the defined connectivity index can be used to prioritize barriers removal with a 'leave-one-out' approach. For each barrier, the index \(dCCI\) can be defined as: \[ \ dCCI_{m} = 100 \frac{CCI - CCI_{m, removed}}{GCI} \] where \(GCI\) is the generalized connectivity index calculated for the original river networks with all the barriers implemented, and GCI{m, removed} is the index recalculated when barrier \(m\) is removed or its passability is changed ($dRCI{i}$ can be defined similarly) .
An alternative version of the index for prioritizing barriers can be calculated as the decrease in river networks connectivity after a single barrier is implemented, with a 'add-one' approach.
when barriers metadata on the year of construction and the year of implementation of mitigation measures are available, a time trajectory of GCI can be computed (e.g. Segurado et al., 2013).
library(igraph)
library(dplyr)
library(tidyr)
library(ggnetwork)
library(viridis)
library(riverconn)
library(doParallel)
This package relies heavily on the functionalities of the igraph
package. The igraph
package implements routines for simple graphs and network analysis. It can handle large graphs very well and provides functions for generating random and regular graphs, graph visualization, centrality methods and much more. The package allows for easy construction of igraph
objects based on edges and vertices lists or adjacency matrices. The book 'Statistical Analysis of Network Data with R' by Kolaczyk and Csardi (2014) offers a comprehensive tutorial on the possibilities offered by the 'igraph' package.
A more comprehensive tutorial, including a real-world case study can be found here: https://damianobaldan.github.io/riverconn_tutorial/
All the functions implemented in this package use as main input an object of class igraph
. There are different ways an object of class igraph
can be created. A symbolic sequence of edges can be used with the function graph_from_literal
for small, toy graphs.
g <- graph_from_literal(1-+2, 2-+5, 3-+4, 4-+5, 6-+7, 7-+10, 8-+9, 9-+10,
5-+11, 11-+12, 10-+13, 13-+12, 12-+14, 14-+15, 15-+16)
g
## IGRAPH f56b1ae DN-- 16 15 --
## + attr: name (v/c)
## + edges from f56b1ae (vertex names):
## [1] 1 ->2 2 ->5 5 ->11 3 ->4 4 ->5 6 ->7 7 ->10 10->13 8 ->9 9 ->10
## [11] 11->12 12->14 13->12 14->15 15->16
Note that when a graph is defined this way, edged and vertices attributes are not defined.
# Edges
E(g)
## + 15/15 edges from f56b1ae (vertex names):
## [1] 1 ->2 2 ->5 5 ->11 3 ->4 4 ->5 6 ->7 7 ->10 10->13 8 ->9 9 ->10
## [11] 11->12 12->14 13->12 14->15 15->16
# vertices
V(g)
## + 16/16 vertices, named, from f56b1ae:
## [1] 1 2 5 3 4 6 7 10 8 9 11 12 13 14 15 16
The graph can be converted to data frame with the function as_data_frame
, specifying if edges or vertices are to be exported. Accordingly, the function graph_from_data_frame
can be used to create an igraph object from a data frame.
igraph::as_data_frame(g, what = "edges")
## from to
## 1 1 2
## 2 2 5
## 3 5 11
## 4 3 4
## 5 4 5
## 6 6 7
## 7 7 10
## 8 10 13
## 9 8 9
## 10 9 10
## 11 11 12
## 12 12 14
## 13 13 12
## 14 14 15
## 15 15 16
igraph::as_data_frame(g, what = "vertices")
## name
## 1 1
## 2 2
## 5 5
## 3 3
## 4 4
## 6 6
## 7 7
## 10 10
## 8 8
## 9 9
## 11 11
## 12 12
## 13 13
## 14 14
## 15 15
## 16 16
Finally, an igraph object can be exported to and generated from adjacency matrices using the functions as_adjacency_matrix
and graph_from_adjacency_matrix
, specifying if edges or vertices are to be exported.
igraph::as_adjacency_matrix(g)
## 16 x 16 sparse Matrix of class "dgCMatrix"
##
## 1 . 1 . . . . . . . . . . . . . .
## 2 . . 1 . . . . . . . . . . . . .
## 5 . . . . . . . . . . 1 . . . . .
## 3 . . . . 1 . . . . . . . . . . .
## 4 . . 1 . . . . . . . . . . . . .
## 6 . . . . . . 1 . . . . . . . . .
## 7 . . . . . . . 1 . . . . . . . .
## 10 . . . . . . . . . . . . 1 . . .
## 8 . . . . . . . . . 1 . . . . . .
## 9 . . . . . . . 1 . . . . . . . .
## 11 . . . . . . . . . . . 1 . . . .
## 12 . . . . . . . . . . . . . 1 . .
## 13 . . . . . . . . . . . 1 . . . .
## 14 . . . . . . . . . . . . . . 1 .
## 15 . . . . . . . . . . . . . . . 1
## 16 . . . . . . . . . . . . . . . .
Once the structure of the network is defined, the graph can be decorated with edges and vertices attributes. Attributes can be either added directly to the graph or joined to the edges and vertices data frame. edges and vertices attributes are saved as vectors, so common, data.frame-like operations are possible.
Here we add the dam information as edge attribute, including the field 'id_dam', and the reach information data as vertices attributes, including the length and the corresponding habitat suitability index.
# Decorate edges
E(g)$id_dam <- c("1", NA, "2", "3", NA, "4", NA, "5", "6", NA, NA, NA, NA, "7", NA)
E(g)$type <- ifelse(is.na(E(g)$id_dam), "joint", "dam")
E(g)
## + 15/15 edges from f56b1ae (vertex names):
## [1] 1 ->2 2 ->5 5 ->11 3 ->4 4 ->5 6 ->7 7 ->10 10->13 8 ->9 9 ->10
## [11] 11->12 12->14 13->12 14->15 15->16
# Decorate vertices
V(g)$length <- c(1, 1, 2, 3, 4, 1, 5, 1, 7, 7, 3, 2, 4, 5, 6, 9)
V(g)$HSI <- c(0.2, 0.1, 0.3, 0.4, 0.5, 0.5, 0.5, 0.6, 0.7, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8)
V(g)$Id <- V(g)$name
V(g)
## + 16/16 vertices, named, from f56b1ae:
## [1] 1 2 5 3 4 6 7 10 8 9 11 12 13 14 15 16
The ggnetwork
library can be used to plot a igraph object with tidyverse
-friendly functions. The function ggnetwork
is used to fortify igraph
objects with a specified layout. Here the tree layout is used, but for real river networks the coordinates of the reaches centroids can be used.
gg0 <- ggnetwork(g, layout = layout_as_tree(g %>% as.undirected, root = 16), scale = FALSE)
ggplot(gg0, aes(x = x, y = y, xend = xend, yend = yend)) +
geom_nodes(alpha = 0.3) +
geom_edges(alpha = 0.5,
arrow = arrow(length = unit(10, "pt"), type = "closed"),
aes(color = type)) +
scale_color_viridis(discrete = TRUE)+
geom_nodetext(aes(label = name), fontface = "bold") +
theme_blank()
This function can be used to display all the graph attributes.
ggplot(gg0, aes(x = x, y = y, xend = xend, yend = yend)) +
geom_edges(alpha = 0.5,
arrow = arrow(length = unit(10, "pt"), type = "open")) +
geom_nodes(aes(size = length, color = HSI)) +
scale_color_viridis()+
theme_blank()
The riverconn
package implements the function set_graph_directionality
that allows to assign the directionality of the graph once an outlet is defined.
oldpar <- par(mfrow = c(1,1))
par(mfrow=c(1,3))
g1 <- set_graph_directionality(g, field_name = "Id", outlet_name = "16")
g2 <- set_graph_directionality(g, field_name = "Id", outlet_name = "5")
plot(as.undirected(g), layout = layout_as_tree(as.undirected(g), root = 8, flip.y = FALSE))
plot(g1, layout = layout_as_tree(as.undirected(g1), root = 16, flip.y = FALSE))
plot(g2, layout = layout_as_tree(as.undirected(g2), root = 5, flip.y = FALSE))
par(oldpar)
The function index_calcualtion
is used to calculate all the nuances of the CCI and RCI
Before calculation, the information on the barriers passability are needed.
# Check edged and nodes attributes, add pass_u and pass_d fields
g_v_df <- igraph::as_data_frame(g, what = "vertices")
g_v_df
## name length HSI Id
## 1 1 1 0.2 1
## 2 2 1 0.1 2
## 5 5 2 0.3 5
## 3 3 3 0.4 3
## 4 4 4 0.5 4
## 6 6 1 0.5 6
## 7 7 5 0.5 7
## 10 10 1 0.6 10
## 8 8 7 0.7 8
## 9 9 7 0.8 9
## 11 11 3 0.8 11
## 12 12 2 0.8 12
## 13 13 4 0.8 13
## 14 14 5 0.8 14
## 15 15 6 0.8 15
## 16 16 9 0.8 16
g_e_df <- igraph::as_data_frame(g, what = "edges") %>%
mutate(pass_u = ifelse(!is.na(id_dam),0.1,NA),
pass_d = ifelse(!is.na(id_dam),0.7,NA))
g_e_df
## from to id_dam type pass_u pass_d
## 1 1 2 1 dam 0.1 0.7
## 2 2 5 <NA> joint NA NA
## 3 5 11 2 dam 0.1 0.7
## 4 3 4 3 dam 0.1 0.7
## 5 4 5 <NA> joint NA NA
## 6 6 7 4 dam 0.1 0.7
## 7 7 10 <NA> joint NA NA
## 8 10 13 5 dam 0.1 0.7
## 9 8 9 6 dam 0.1 0.7
## 10 9 10 <NA> joint NA NA
## 11 11 12 <NA> joint NA NA
## 12 12 14 <NA> joint NA NA
## 13 13 12 <NA> joint NA NA
## 14 14 15 7 dam 0.1 0.7
## 15 15 16 <NA> joint NA NA
# Recreate graph
g <- igraph::graph_from_data_frame(d = g_e_df, vertices = g_v_df)
g
## IGRAPH fa11ade DN-- 16 15 --
## + attr: name (v/c), length (v/n), HSI (v/n), Id (v/c), id_dam (e/c),
## | type (e/c), pass_u (e/n), pass_d (e/n)
## + edges from fa11ade (vertex names):
## [1] 1 ->2 2 ->5 5 ->11 3 ->4 4 ->5 6 ->7 7 ->10 10->13 8 ->9 9 ->10
## [11] 11->12 12->14 13->12 14->15 15->16
Index with default settings.
index_calculation(g, param = 0.9)
## num den index
## 1 562.6092 3721 0.1511984
Index with default settings, only \(c_{ij}\) or \(B_{ij}\) contributions
index_calculation(g, B_ij_flag = FALSE)
## num den index
## 1 791.8553 3721 0.2128071
index_calculation(g, param = 0.9, c_ij_flag = FALSE)
## num den index
## 1 1210.583 3721 0.325338
Index with default settings, only \(B_{ij}\) contributions with threshold on the distance
index_calculation(g, c_ij_flag = FALSE,
dir_distance_type = "asymmetric",
disp_type = "threshold", param_u = 0, param_d = 5)
## num den index
## 1 413 3721 0.1109917
index_calculation(g, c_ij_flag = FALSE,
dir_distance_type = "asymmetric",
disp_type = "threshold", param_u = 5, param_d = 10)
## num den index
## 1 1045 3721 0.2808385
index_calculation(g, c_ij_flag = FALSE,
dir_distance_type = "symmetric",
disp_type = "threshold", param = 10)
## num den index
## 1 1301 3721 0.3496372
Index for reach, inbound connections used, only \(B_{ij}\) contributions with threshold on the distance
index_calculation(g, c_ij_flag = FALSE,
index_type = "reach", index_mode = "to",
dir_distance_type = "asymmetric",
disp_type = "threshold", param_u = 0, param_d = 5)
## name num den index
## 1 1 7 61 0.11475410
## 2 2 6 61 0.09836066
## 5 5 7 61 0.11475410
## 3 3 7 61 0.11475410
## 4 4 6 61 0.09836066
## 6 6 6 61 0.09836066
## 7 7 6 61 0.09836066
## 10 10 5 61 0.08196721
## 8 8 7 61 0.11475410
## 9 9 8 61 0.13114754
## 11 11 5 61 0.08196721
## 12 12 7 61 0.11475410
## 13 13 6 61 0.09836066
## 14 14 5 61 0.08196721
## 15 15 6 61 0.09836066
## 16 16 9 61 0.14754098
index_calculation(g, c_ij_flag = FALSE,
dir_distance_type = "asymmetric",
index_type = "reach", index_mode = "to",
disp_type = "threshold", param_u = 5, param_d = 10)
## name num den index
## 1 1 17 61 0.2786885
## 2 2 22 61 0.3606557
## 5 5 22 61 0.3606557
## 3 3 14 61 0.2295082
## 4 4 20 61 0.3278689
## 6 6 18 61 0.2950820
## 7 7 25 61 0.4098361
## 10 10 29 61 0.4754098
## 8 8 14 61 0.2295082
## 9 9 24 61 0.3934426
## 11 11 18 61 0.2950820
## 12 12 22 61 0.3606557
## 13 13 17 61 0.2786885
## 14 14 13 61 0.2131148
## 15 15 15 61 0.2459016
## 16 16 9 61 0.1475410
index_calculation(g, c_ij_flag = FALSE,
index_type = "reach", index_mode = "to",
dir_distance_type = "symmetric",
disp_type = "threshold", param = 10)
## name num den index
## 1 1 16 61 0.2622951
## 2 2 25 61 0.4098361
## 5 5 25 61 0.4098361
## 3 3 14 61 0.2295082
## 4 4 16 61 0.2622951
## 6 6 18 61 0.2950820
## 7 7 20 61 0.3278689
## 10 10 28 61 0.4590164
## 8 8 14 61 0.2295082
## 9 9 27 61 0.4426230
## 11 11 26 61 0.4262295
## 12 12 41 61 0.6721311
## 13 13 31 61 0.5081967
## 14 14 24 61 0.3934426
## 15 15 22 61 0.3606557
## 16 16 15 61 0.2459016
The function index_calcualtion
allows to calculate the CCI and RCI changes when barriers are removed. Metadata on which dams are to be removed and how the passability changes are to be provided in the 'dams_metadata' object. Parallel calculations can be activated.
dams_metadata <- data.frame("id_dam" = c("1", "2", "3", "4", "5", "6", "7"),
"pass_u_updated" = c(1, 1, 1, 1, 1, 1, 1),
"pass_d_updated" = c(1, 1, 1, 1, 1, 1, 1))
dams_metadata
## id_dam pass_u_updated pass_d_updated
## 1 1 1 1
## 2 2 1 1
## 3 3 1 1
## 4 4 1 1
## 5 5 1 1
## 6 6 1 1
## 7 7 1 1
d_index_calculation(g,
barriers_metadata = dams_metadata,
id_barrier = "id_dam",
parallel = FALSE, ncores = 3,
param_u = 10, param_d = 10, param = 0.5,
index_type = "full",
dir_distance_type = "asymmetric",
disp_type = "threshold")
## id_dam num den index index_bl d_index
## 1 1 761.3266 3721 0.2046027 0.2006519 1.968976
## 2 2 906.0160 3721 0.2434872 0.2006519 21.348084
## 3 3 787.2481 3721 0.2115690 0.2006519 5.440798
## 4 4 771.3265 3721 0.2072901 0.2006519 3.308324
## 5 5 986.0332 3721 0.2649915 0.2006519 32.065261
## 6 6 837.7657 3721 0.2251453 0.2006519 12.206919
## 7 7 824.7457 3721 0.2216463 0.2006519 10.463074
Calculated index can be joined with the original graph and plotted to check spatial patterns.
d_index <- d_index_calculation (g,
barriers_metadata = dams_metadata,
id_barrier = "id_dam",
parallel = FALSE, ncores = 3,
param_u = 10, param_d = 10,
index_type = "full",
B_ij_flag = FALSE)
# Check edged and nodes attributes
g_v_df <- igraph::as_data_frame(g, what = "vertices")
g_v_df
## name length HSI Id
## 1 1 1 0.2 1
## 2 2 1 0.1 2
## 5 5 2 0.3 5
## 3 3 3 0.4 3
## 4 4 4 0.5 4
## 6 6 1 0.5 6
## 7 7 5 0.5 7
## 10 10 1 0.6 10
## 8 8 7 0.7 8
## 9 9 7 0.8 9
## 11 11 3 0.8 11
## 12 12 2 0.8 12
## 13 13 4 0.8 13
## 14 14 5 0.8 14
## 15 15 6 0.8 15
## 16 16 9 0.8 16
g_e_df <- igraph::as_data_frame(g, what = "edges") %>%
left_join(d_index, by = "id_dam")
g_e_df
## from to id_dam type pass_u pass_d num den index index_bl
## 1 1 2 1 dam 0.1 0.7 807.3490 3721 0.2169710 0.2128071
## 2 2 5 <NA> joint NA NA NA NA NA NA
## 3 5 11 2 dam 0.1 0.7 1008.4973 3721 0.2710286 0.2128071
## 4 3 4 3 dam 0.1 0.7 837.5552 3721 0.2250887 0.2128071
## 5 4 5 <NA> joint NA NA NA NA NA NA
## 6 6 7 4 dam 0.1 0.7 818.9726 3721 0.2200947 0.2128071
## 7 7 10 <NA> joint NA NA NA NA NA NA
## 8 10 13 5 dam 0.1 0.7 1184.2933 3721 0.3182729 0.2128071
## 9 8 9 6 dam 0.1 0.7 976.2077 3721 0.2623509 0.2128071
## 10 9 10 <NA> joint NA NA NA NA NA NA
## 11 11 12 <NA> joint NA NA NA NA NA NA
## 12 12 14 <NA> joint NA NA NA NA NA NA
## 13 13 12 <NA> joint NA NA NA NA NA NA
## 14 14 15 7 dam 0.1 0.7 1223.1558 3721 0.3287170 0.2128071
## 15 15 16 <NA> joint NA NA NA NA NA NA
## d_index
## 1 1.956632
## 2 NA
## 3 27.358782
## 4 5.771242
## 5 NA
## 6 3.424522
## 7 NA
## 8 49.559308
## 9 23.281074
## 10 NA
## 11 NA
## 12 NA
## 13 NA
## 14 54.467087
## 15 NA
# Recreate graph
g <- igraph::graph_from_data_frame(d = g_e_df, vertices = g_v_df)
g
## IGRAPH fefe7fd DN-- 16 15 --
## + attr: name (v/c), length (v/n), HSI (v/n), Id (v/c), id_dam (e/c),
## | type (e/c), pass_u (e/n), pass_d (e/n), num (e/n), den (e/n), index
## | (e/n), index_bl (e/n), d_index (e/n)
## + edges from fefe7fd (vertex names):
## [1] 1 ->2 2 ->5 5 ->11 3 ->4 4 ->5 6 ->7 7 ->10 10->13 8 ->9 9 ->10
## [11] 11->12 12->14 13->12 14->15 15->16
# Fortify and plot graph
gg0 <- ggnetwork(g, layout = layout_as_tree(g %>% as.undirected, root = 16), scale = FALSE)
ggplot(gg0, aes(x = x, y = y, xend = xend, yend = yend)) +
geom_edges(alpha = 0.5, size = 3,
arrow = arrow(length = unit(10, "pt"), type = "open"),
aes(color = d_index)) +
geom_nodes() +
scale_color_viridis()+
theme_blank()
Belletti, Barbara, et al. “More than one million barriers fragment Europe’s rivers.” Nature 588.7838 (2020): 436-441.
Cote, D., Kehler, D. G., Bourne, C., & Wiersma, Y. F. (2009). A new measure of longitudinal connectivity for stream networks. Landscape Ecology, 24(1), 101-113.
Kolaczyk, E. D., & Csárdi, G. (2014). Statistical analysis of network data with R (Vol. 65). New York: Springer.
Jumani, S., Deitch, M. J., Kaplan, D., Anderson, E. P., Krishnaswamy, J., Lecours, V., & Whiles, M. R. (2020). River fragmentation and flow alteration metrics: a review of methods and directions for future research. Environmental Research Letters.