3 - Landscape graph construction and analysis with Graphab and graph4lg

UMR 6049 ThéMA - CNRS - Univ. Marie et Louis Pasteur, Besançon, France

Paul SAVARY

Introduction

The rationale of graph4lg package in R is to make the construction and analysis of genetic and landscape graphs easier for landscape genetic studies (hence the name graph4lg, meaning Graphs for Landscape Genetics). This package provides users with tools for:

Each one of the included vignettes focuses on one of these points. This third vignette will focus on landscape graph construction and analysis. It will describe the package functions allowing users to:

NOTA BENE: The package graph4lg integrates functions making possible the construction and analysis of landscape graphs but most of them are only wrappers that launch computations with Graphab software.

What is Graphab?

Graphab is an open source software tool dedicated to the modelling of landscape networks (Foltête et al. 2012, 2021). It was developed in the ThéMA laboratory (Besançon, France) to make possible the creation of landscape graphs and to integrate a complete set of connectivity analysis functions in a single application.

Integrating Graphab functionalities into graph4lg aims at facilitating the import of Graphab output into R for subsequent analyses, including the comparison of genetic graphs and landscape graphs. All the functions calling Graphab software are described in graph4lg help files. However, users are invited to read the complete documentation manuals as well as other resources on Graphab project website. Some computations are not possible when using graph4lg but are possible when using directly the Graphab software which can be downloaded for free on the same website. Foltête et al. (2012) and Foltête et al. (2021) papers also provide users with a synthetic description of the tool. In 2024, new functionalities were introduced in Graphab 3.0 to make it possible to include several types of habitats into the same habitat graph, creating so-called ‘multiple habitat graphs’. This modelling option is described by Savary et al. (2024) and can now be used in graph4lg (version >= 2.0).

The function get_graphab from graph4lg package automatically downloads Graphab 3.0 in the user’s machine, provided Java is installed on the machine. If it has already been downloaded, a message is displayed. Once Graphab has been downloaded in a machine, it is not necessary to download it again. Note that users familiar with the functions calling graphab-2.8.jar can still use the previous versions of graph4lg by installing them from the gitlab repository of the package.

get_graphab()

In the table below, we present all the functions from graph4lg calling Graphab software:

Function Description
get_graphab Check if Graphab software (graphab-3.0.jar) is in the user’s machine and downloads it if necessary, provided Java is installed.
graphab_project Creates a Graphab project from a raster file (.tif)
graphab_habitat Creates an habitat in the Graphab project from either the raster file or a vector spatial layer
graphab_capacity Modifies the capacity of habitat patches based on additional data or patch neighbourhood raster calculations
graphab_link Creates a set of links (Euclidean or least cost paths, planar or complete)
graphab_graph Creates a graph from a set of links
graphab_merge_graph Merges existing graphs from a set of links
graphab_metric Computes graph-theoretic metrics from a graph
graphab_modul Partition the graph into modules
graphab_corridor Creates corridor surrounding least-cost paths
graphab_interpol Interpolates Graphab metrics over continuous raster fields
graphab_pointset Imports a set of points in the project and relates them to habitat patches and corresponding metrics
graphab_metapatch Creates a new habitat type made of meta-patches, each corresponding to the connected components of a pruned/incomplete graph
graphab_show Lists the elements already included in the Graphab project
graphab_project_desc Describes all the project parameters
get_graphab_metric Imports a table with the metrics computed and the patch properties
get_graphab_linkset Imports a table with the link properties for a given link set
get_graphab_linkset_cost Gets the parameters of a cost-distance based link set
get_graphab_raster_codes Lists the categorical values of the raster used to create the project
graphab_to_igraph Imports a graph created with Graphab as an igraph graph object with node and link attributes

NOTA BENE: This vignette only provides a basic introduction to all the functionalities offered by the Graphab software application. All the cases cannot be covered here and users interested in more options can find more information in the Graphab website and in publications of the Graphab group (in particular in Foltête et al. (2021) and Savary et al. (2024) for multiple habitat graphs).

Data used in this vignette

Here, we do not rely on genetic data sets and will only use Graphab projects already created for the vignettes.

Landscape graph construction

Project creation

When using Graphab, the main input data consists of an 8-bit raster file (.tif) with discrete cell values. One (or several) of these values will correspond to habitat cells on the raster. Contiguous habitat cells will form habitat patches (8-neighbourhood criterion), as soon as they exceed the minimum patch area when specified.

The first step of habitat network modelling with Graphab is the creation of a Graphab project. This project is given a name (proj_name), which will be the name of a directory containing geographical information layers relative to the project as well as a .xml file (“proj_name.xml”), which is the main project file.

The function graphab_project creates the project directory called proj_name either in the current working directory (default) or in the directory whose path is given as a proj_path argument. The function takes as arguments:

The three last arguments are included in almost every function calling Graphab, and won’t be mentioned anymore in the next sections.

As an example, we will create a landscape graph from a simulated landscape raster with 5 land use categories (see map below).

rast <- terra::rast(paste0(system.file('extdata', package = 'graph4lg'), 
                   "/", "rast_simul50.tif"))
# convert the raster into a df while keeping coords
r_df <- as.data.frame(rast,
                      xy = TRUE)
# add a categorical field with the raster codes
r_df$code <- as.factor(r_df$rast_simul50)

# Plot it with ggplot2
g <- ggplot(r_df, aes(x = x, y = y)) +
  geom_tile(aes(fill = code)) + coord_equal()+
  theme_bw()+
  #scale_fill_brewer(palette="Dark2")+
  scale_fill_manual(values = c("#396D35", "#FB9013", "#EDC951", "#80C342", "black", "#396D35"),
                    labels = c("0 - Forest", "1 - Shrublands", "3 - Crops",
                               "4 - Grasslands","5 - Artificial areas", "6 - Forest"),
                    name = "Land use type")+
  labs(x="Longitude",y="Latitude")
g

We can create a project to assess habitat connectivity in this landscape using the following command:

proj_name <- "graphab_example"

graphab_project(proj_name = proj_name,
                raster = "rast_simul50.tif")

Habitat creation

Once the project has been created, we can use the function graphab_habitat to create a new habitat type in the Graphab project (proj_name). As a result, a new repository is created in the project repository, including a geopackage layer with the corresponding habitat patches (polygons). The function takes as arguments:

Here, we create a first habitat type with habitat patches corresponding to contiguous patches of raster cells equal to 0 or 5, as soon as they are larger than 200 hectares. We assume they correspond to forests.

# Habitat creation
graphab_habitat(proj_name = proj_name, 
                name = "forest",
                type = "raster", 
                rast_codes = c(0, 5), 
                minarea = 200)

Since Graphab 3.0, it is possible to include several types of habitats in the same Graphab project. We illustrate that below by creating an habitat type corresponding to shrubland patches.

# Bushland
graphab_habitat(proj_name = proj_name,
                name = "shrubland",
                type = "raster",
                rast_codes = 1,
                minarea = 20)

We can check that the two habitat types have been successfully created by listing the elements of the project, using the graphab_show function. Its only argument is the path to the .xml file storing all the project information:

graphab_show(proj_path = "graphab_example/graphab_example.xml")

Since Graphab 3.0, it is also possible to create habitat types by providing the corresponding patches as point or polygon entities of a geopackage or shapefile vectorial layer. In this case, a column of the attribute table must include the values used to set the capacity of the habitat patches. The name of this column is provided with the argument vec_capa_field. For example:

graphab_habitat(proj_name = proj_name,
                name = "grassland",
                type = "vector",
                vec_layer = "grassland_patches.gpkg",
                vec_capa_field = "capa")

Graph construction

Once we have created at least one habitat and a link set among its patches, we can create a habitat graph (or landscape graph) with graphab_graph. This function takes as arguments:

proj_name is the only mandatory argument. Without any other argument, a non-thresholded graph is created for every link set present in the project. Names are created automatically.

Since a link set is necessarily associated with one or several habitat types, the nodes of the graph will be determined from the link set properties.

In our example, we can create a planar graph with the following command:

graphab_graph(proj_name = proj_name,
              linkset = "forest_link_planar",
              name = "graph_forest")

If we select a linkset linking multiple habitat types, the graph will have nodes corresponding to multiple types of habitats. In the present case, since the only linkset connecting multiple habitat types only includes inter-links among patches of different types, if we want to include both intra- and inter-links in the graph, we can create 1 graph for each of the linksets (2 intra and 1 inter) and then merge the 3 graphs into one using the graphab_merge_graph function (created for that purpose). We would proceed as follows:

# Forest graph
graphab_graph(proj_name = proj_name,
              linkset = "forest_link_planar",
              name = "graph_forest_1")
# Shrub graph
graphab_graph(proj_name = proj_name,
              linkset = "shrub_link_planar",
              name = "graph_shrub_2")
# Inter graph
graphab_graph(proj_name = proj_name,
              linkset = "inter_forest_shrub",
              name = "graph_inter_3")
# Merge the 3 graphs
graphab_merge_graph(proj_name = proj_name,
              name = "graph_multi",
              graphs = c("graph_forest_1",
                         "graph_shrub_2",
                         "graph_inter_3"))

A simpler option consists in creating a linkset connecting multiple habitat types (inter=FALSE, see above) and then a graph using this linkset.

Landscape graph analysis

Once the graph has been created, it can be analysed by computing graph-theoretic connectivity metrics or by partitioning its nodes, among other possibilities.

Metric calculation

Many connectivity metrics can be computed from a landscape graph (see Baranyi et al. (2011) and Rayfield et al. (2011) among other reviews on the subject). The Graphab software includes a large range of connectivity metrics and its manual provides users with a comprehensive description of every one of them (see Graphab 3.0 manual).

The graphab_metric function computes these metrics. It takes as arguments:

Metrics fall into different categories. PC and IIC are global metrics and take only one value for the entire graph, which is returned in R environment when return_val=TRUE.

The other metrics are computed at the node level. When return_val=TRUE, a data.frame is returned in R environment specifying the value of the metric for every graph node.

Importantly, the multihab argument now (since Graphab 3.0) allows users to decompose the value of the metrics into several components when the graph considered for the computation includes several types of habitats. If multihab='all', all the pairwise combinations are considered, including the within-habitat case. If multihab='inter', only the inter-habitat types combinations are considered. Note that this argument is only required if the graph on which you compute the metrics is based on several habitat types. Please find details in Savary et al. (2024).

The description of every metric is beyond the scope of this tutorial. We again invite users to read the help file (?graphab_metric) as well as the Graphab 3.0 user manual.

We will compute metrics on the graph "graph_forest" in our example. First, we will compute the probability of connectivity at the global level. We set the dist and prob parameter such that: \(p(10km)=e^{-\alpha \times d_{ij}}=0.05\). We convert 10 km in cost-distance units for the computation.

# Global metric: PC
pc <- graphab_metric(proj_name = proj_name,
               graph = "graph_forest",
               metric = "PC",
               dist = 10000,
               prob = 0.05,
               beta = 1,
               cost_conv = TRUE)
pc
#> $`Metric name`
#> [1] "pc_d1479.8358851873484_p0.05_graph_forest"
#> 
#> $`Metric value table`
#>          Graph        d    p beta           PC
#> 1 graph_forest 1479.836 0.05    1 0.0007436003

Note that we could have specified with the argument resfile the name of the .txt file storing the result of the global metric value.

We obtain the value in an object of class list.

Now, using the same parameters, we compute the local metric Flux.

f <- graphab_metric(proj_name = proj_name,
                    graph = "graph_forest",
                    metric = "F",
                    dist = 10000,
                    prob = 0.05,
                    beta = 1,
                    cost_conv = FALSE)
#>   habitat id_habitat id_patch    area perim capacity
#> 1  forest          0        1 2610000 13000  2610000
#> 2  forest          0        2 8800000 23000  8800000
#> 3  forest          0        3 3270000 10800  3270000
#> 4  forest          0        4 5330000 18800  5330000
#> 5  forest          0        5 6580000 18200  6580000
#> 6  forest          0        6 2620000  8800  2620000
#>   f_d1479.8358851873484_p0.05_beta1_graph_forest
#> 1                                     22659462.5
#> 2                                     12467998.8
#> 3                                      2264071.3
#> 4                                       340302.5
#> 5                                     13018161.5
#> 6                                     16655121.0

Every time a local metric is computed, it can be returned in R environment (here stored in f) but is also stored in the habitat patch attribute table, such that at the end this table contains every metric computed. Because of this, we can load the metric values in R later on, using the get_graphab_metric function. For instance:

metric_table <- get_graphab_metric(proj_name = proj_name,
                   graph = "graph_forest")

Metrics can be filtered based on their specific name (one metric), the graph on which they were computed or the habitat types considered. See ?get_graphab_metric for more details.

In the specific case of multiple habitat graphs, we can compute different components of the metrics, each corresponding to the contribution of a specific habitat type. We add the multihab argument for that purpose. For instance with the EC metric computed on the multiple habitat graph graph_multi:

ec_multi <- graphab_metric(proj_name = proj_name,
                     graph = "graph_multi",
                     multihab = "all",
                     metric = "EC",
                     dist = 10000,
                     prob = 0.05,
                     beta = 1,
                     cost_conv = TRUE)
ec_multi
#> $`Metric name`
#> [1] "EC_graph_multi"
#> 
#> $`Metric value table`
#>         Graph       d    p beta     X0.0     X0.1     X1.1
#> 1 graph_multi 813.815 0.05    1 82578203 66570524 29719307

The X0.0 column indicates the contribution of the forest habitat nodes (habitat code 0) and the connections among them to the EC component (intra), whereas the X0.1 column indicates the contribution of the connections among forest and shrubland patches (inter), and X1.1 that of the shrubland patches and the connections among them (intra). Please see details about the formulas used for the decomposition in Savary et al. (2024).

Similarly, in the case of local metrics, the contribution of each habitat type to the local connectivity metric computed for each node can be assessed. For the Flux metric for instance, we can know how much a node is connected to the nodes of each other habitat type:

f_multi <- graphab_metric(proj_name = proj_name,
                    graph = "graph_multi",
                    multihab = "all",
                    metric = "F",
                    dist = 10000,
                    prob = 0.05,
                    beta = 1,
                    cost_conv = FALSE)
f_multi
#>   habitat id_habitat id_patch    area perim capacity
#> 1  forest          0        1 2610000 13000  2610000
#> 2  forest          0        2 8800000 23000  8800000
#> 3  forest          0        3 3270000 10800  3270000
#> 4  forest          0        4 5330000 18800  5330000
#> 5  forest          0        5 6580000 18200  6580000
#> 6  forest          0        6 2620000  8800  2620000
#>   f_d10000_p0.05_beta1.0_graph_multi f_d10000_p0.05_beta1.1_graph_multi
#> 1                          117669295                           49122576
#> 2                          105967219                           46842866
#> 3                           64066487                           35918701
#> 4                           42748208                           29043326
#> 5                          119935793                           51041965
#> 6                          123382351                           50838307

Graph partitioning

Another way to analyse landscape graph connectivity and topology is to make a partitioning. The principle is the same as that of modularity analyses of genetic graphs described in the second tutorial.

The graphab_modul function carries out such an analysis, but for the moment, it only creates a shapefile polygon layer with the Voronoi polygons corresponding to the groups of patches forming modules.

It takes as arguments:

For example:

graphab_modul(proj_name = proj_name,
              graph = "graph_forest",
              dist = 10000,
              prob = 0.05,
              beta = 1)

NOTA BENE: All these analyses can be performed for several graphs created in the same project, provided their name is correctly indicated in the function arguments.

Using landscape graphs in landscape genetic analyses

Landscape graphs have been created and analysed by computing connectivity metrics and/or by partitioning them. The output of these analyses can be used in landscape genetic analyses, e.g., to assess the relationship between genetic variables measured in populations inhabiting the study landscape and the connectivity of its habitat patches. To do that, we can import Graphab output in R environment to use it in subsequent (statistical) analyses.

As seen before, users can import in the R environment the link set properties in a data.frame with an edge list format with the function get_graphab_linkset which takes as arguments the project name and the link set name.

get_graphab_linkset(proj_name = proj_name,
                    linkset = "forest_link_planar")
#>    Id id1 id2       dist     distm
#> 1 6-1   6   1  956.73717 5704.1631
#> 2 7-1   7   1   82.24264  641.4214
#> 3 2-1   2   1  206.00000  900.0000
#> 4 7-2   7   2  313.62742 3679.8990
#> 5 9-2   9   2 1508.91084 6311.2698
#> 6 6-5   6   5   23.48528  582.8427

Similarly, users can import the table in which are stored all the metrics computed in the project as well as the node properties (including their areas). The function get_graphab_metric takes as argument the project name. For instance for the metrics relative to the forest habitat:

get_graphab_metric(proj_name = proj_name,
                   habitat = "forest")
#>   habitat id_habitat id_patch    area perim capacity
#> 1  forest          0        1 2610000 13000  2610000
#> 2  forest          0        2 8800000 23000  8800000
#> 3  forest          0        3 3270000 10800  3270000
#> 4  forest          0        4 5330000 18800  5330000
#> 5  forest          0        5 6580000 18200  6580000
#> 6  forest          0        6 2620000  8800  2620000
#>   f_d1479.8358851873484_p0.05_beta1_graph_forest
#> 1                                     22659462.5
#> 2                                     12467998.8
#> 3                                      2264071.3
#> 4                                       340302.5
#> 5                                     13018161.5
#> 6                                     16655121.0
#>   f_d813.8150263041181_p0.05_beta1.0_graph_multi
#> 1                                    15782142.44
#> 2                                     6216475.10
#> 3                                     1770605.62
#> 4                                       40623.71
#> 5                                     5147066.61
#> 6                                     8630957.14
#>   f_d813.8150263041181_p0.05_beta1.1_graph_multi
#> 1                                        4583715
#> 2                                        2491953
#> 3                                        1086021
#> 4                                        3134465
#> 5                                        4090063
#> 6                                        3730796
#>   f_d10000_p0.05_beta1.0_graph_multi f_d10000_p0.05_beta1.1_graph_multi
#> 1                          117669295                           49122576
#> 2                          105967219                           46842866
#> 3                           64066487                           35918701
#> 4                           42748208                           29043326
#> 5                          119935793                           51041965
#> 6                          123382351                           50838307

Finally, users can also create a graph from a Graphab link set and a given habitat type, and convert it into a graph object of class igraph. The imported graph has weighted links. Habitat patch attributes present in the Graphab project are included. A figure can be displayed automatically representing the graph on a map. The graph is given the topology of the selected link set.

The function graphab_to_igraph takes as arguments:

land_graph <- graphab_to_igraph(proj_name = proj_name,
                                linkset = "forest_link_planar",
                                habitat = "forest",
                                weight = "cost",
                                fig = FALSE,
                                crds = TRUE)

crds_patches <- land_graph[[2]]
land_graph <- land_graph[[1]]

The function returns a list of two objects:

This graph can be plotted on a map with plot_graph_lg with node sizes proportional to habitat patch area and link width inversely proportional to cost-distances:

plot_graph_lg(land_graph,
              crds = crds_patches,
              mode = "spatial",
              node_size = "area")

Computational performance

Some computations involved in the construction and analysis of landscape graphs can be heavy and take a lot of time and computational resources on your machines. Two main arguments are now included in most of the functions calling Graphab to adjust the RAM allocated to each computation, and the number of cores on which the computation can be run in parallel. These arguments are the following:

Conclusion

We have seen in this third vignette how to construct, analyse, and import landscape graphs with Graphab and graph4lg. In the next and last vignette, we will see how to compare genetic graphs and landscape graphs.

Note that other functions of graph4lg call Graphab and can be used to create corridors along least-cost paths, interpolate metrics, add pointsets to a project, among other examples.

References

Baranyi, Gabriella, Santiago Saura, János Podani, and Ferenc Jordán. 2011. “Contribution of Habitat Patches to Network Connectivity: Redundancy and Uniqueness of Topological Indices.” Ecological Indicators 11 (5): 1301–10.
Foltête, Jean-Christophe, Céline Clauzel, and Gilles Vuidel. 2012. “A Software Tool Dedicated to the Modelling of Landscape Networks.” Environmental Modelling & Software 38: 316–27.
Foltête, Jean-Christophe, Gilles Vuidel, Paul Savary, et al. 2021. “Graphab: An Application for Modeling and Managing Ecological Habitat Networks.” Software Impacts 8: 100065. https://doi.org/10.1016/j.simpa.2021.100065.
Rayfield, Bronwyn, Marie-Josée Fortin, and Andrew Fall. 2011. “Connectivity for Conservation: A Framework to Classify Network Measures.” Ecology 92 (4): 847–58.
Savary, Paul, Céline Clauzel, Jean-Christophe Foltête, et al. 2024. “Multiple Habitat Graphs: How Connectivity Brings Forth Landscape Ecological Processes.” Landscape Ecology, no. 9: 168. https://doi.org/10.1007/s10980-024-01947-4.