Differences to FRAGSTATS
2024-09-08
Source:vignettes/articles/comparing_tools.Rmd
comparing_tools.Rmd
Comparison with FRAGSTATS
landscapemetrics re-implements landscape metrics as they are mostly described in the FRAGSTATS software (McGarigal et al. 2023). Therefore, we compare our results with the results of FRAGSTATS. On patch-level we use a correlation approach testing values calculated by landscapemetrics and FRAGSTATS have at least a correlation of p>=0.975 because we are not able to exactly match patches. On class- and landscape-level we can match individual values and test if no deviation is larger than 5%. In the process, we recognized a few differences between the results. Some metrics in FRAGSTATS are interdependent across scales. Thus, if there is a deviation at the patch level, it propagates through the class- and landscape-level. In this document, we list the metrics with deviations at the lowest level only. Unfortunately, we do not have access to the source code of FRAGSTATS. Therefore, we are not able to finally explain all present differences of results.
General differences
Firstly, the patch ID is ordered in a different way, due to technical reasons (how connected patches are specified). Therefore, one has to pay attention comparing the results on patch level for FRAGSTATS and landscapemetrics.
All double precision floating point numbers are rounded in FRAGSTATS. Contrastingly, we do not round the numbers. Naturally, this can lead to small deviations between the results. However, these small differences should have no influence on any interpretation of the results.
There are quite a few metrics on class- and landscape-level that
summarize patch level metrics (e.g., the mean, standard deviation
(sd) or coefficient of variation (cv) of all values
belonging to class i). While the results are identical for
single patches and the mean of all patches, there are some slight
differences between lanscapemetrics and FRAGSTATS for
the sd and the cv. landscapemetrics
uses base R
functions and standard statistical definitions
to summarize the patch level metrics. Again, difference are only very
minor and should not affect interpretation of the results. In the
following, we are comparing the cv and sd for the
patch area.
We are including the cv calculated from all patch areas and the actual output of FRAGSTATS as well as the output of landscapemetrics. Interestingly, the cv calculated from all patches of FRAGSTATS is identical to the cv of landscapemetrics, but the already summarized result of FRAGSTATS is slightly different.
Click for details
class | fs_output | fs_calc | lsm_calc | lsm_fun |
---|---|---|---|---|
1 | 147.1030 | 156.02630 | 156.02630 | 156.02630 |
3 | 77.2108 | 84.58015 | 84.58015 | 84.58015 |
2 | 124.4360 | 129.51715 | 129.51715 | 129.51715 |
As for the cv, there are also minor differences for the sd. The result calculated from all patch areas of FRAGSTATS is identical to the result of landscapemetrics, but not the summarized result of FRAGSTATS.
Click for details
class | fs_output | fs_calculated | lsm_calculated | lsm_output |
---|---|---|---|---|
1 | 0.0030 | 0.0031899 | 0.0031899 | 0.0031899 |
3 | 0.0062 | 0.0067946 | 0.0067946 | 0.0067946 |
2 | 0.0022 | 0.0023313 | 0.0023313 | 0.0023313 |
Specific differences
All core-related metrics
Different definitions of the core area of a patch result in differences for all metrics that somehow related on the core area or number of disjunct core areas. landscapemetrics uses a cell-centered definition of the core area, namely “a cell is defined as core area if the cell has no neighbour with a different value than itself (rook’s case).” Contrastingly, FRAGSTATS uses “[…] a method involving the use of a variably-sized masked placed on cells on the perimeter of a patch […]”. Especially for patches with rather complicated shapes this seem to result in different core-metric values.
GYRATE metric
According to FRAGSTATS the radius of gyration for a patch consisting of only a single cell should equal GYRATE = 0.
[…] GYRATE = 0 when the patch consists of a single cell […]
However, for patches containing a single cell FRAGSTATS returns a value of GYRATE = 0.5. In the following table, patches with an area of area = 0.0001 consist of only one cell.
Click for details
fs_id | fs_area | fs_gyrate | lsm_id | lsm_area | lsm_gyrate |
---|---|---|---|---|---|
1 | 1e-04 | 0.5 | 1 | 1e-04 | 0 |
24 | 1e-04 | 0.5 | 4 | 1e-04 | 0 |
28 | 1e-04 | 0.5 | 5 | 1e-04 | 0 |
13 | 1e-04 | 0.5 | 11 | 1e-04 | 0 |
15 | 1e-04 | 0.5 | 13 | 1e-04 | 0 |
18 | 1e-04 | 0.5 | 16 | 1e-04 | 0 |
20 | 1e-04 | 0.5 | 17 | 1e-04 | 0 |
Additionally, we recognized small differences for all other patches as well. However, we could not find an explanation for this difference, yet.
PARA metric
The documentation of FRAGSTATS defines the perimeter-area ratio the following:
[…] PARA equals the ratio of the patch perimeter (m) to area (m2). […]
Contrastingly, the output of FRAGSTATS gives the result as the ratio of the patch perimeter in meters to area in hectares.
We implemented PARA as documented in the FRAGSTATS manual using square meters. Nevertheless, the differences between the softwares are only based on different units, as shown by converting the FRAGSTATS output to meters per square meters.
Click for details
fs_id | fs_area | fs_perim | fs_para | lsm_id | lsm_area | lsm_perim | lsm_para | lsm_para_ha |
---|---|---|---|---|---|---|---|---|
1 | 0.0001 | 4 | 40000.000 | 1 | 0.0001 | 4 | 4.0000000 | 40000.000 |
24 | 0.0001 | 4 | 40000.000 | 4 | 0.0001 | 4 | 4.0000000 | 40000.000 |
28 | 0.0001 | 4 | 40000.000 | 5 | 0.0001 | 4 | 4.0000000 | 40000.000 |
13 | 0.0001 | 4 | 40000.000 | 11 | 0.0001 | 4 | 4.0000000 | 40000.000 |
15 | 0.0001 | 4 | 40000.000 | 13 | 0.0001 | 4 | 4.0000000 | 40000.000 |
18 | 0.0001 | 4 | 40000.000 | 16 | 0.0001 | 4 | 4.0000000 | 40000.000 |
20 | 0.0001 | 4 | 40000.000 | 17 | 0.0001 | 4 | 4.0000000 | 40000.000 |
11 | 0.0002 | 6 | 30000.000 | 14 | 0.0002 | 6 | 3.0000000 | 30000.000 |
21 | 0.0002 | 6 | 30000.000 | 18 | 0.0002 | 6 | 3.0000000 | 30000.000 |
27 | 0.0003 | 10 | 33333.333 | 8 | 0.0003 | 10 | 3.3333333 | 33333.333 |
16 | 0.0003 | 8 | 26666.667 | 22 | 0.0003 | 8 | 2.6666667 | 26666.667 |
9 | 0.0005 | 12 | 24000.000 | 2 | 0.0005 | 12 | 2.4000000 | 24000.000 |
25 | 0.0005 | 10 | 20000.000 | 9 | 0.0005 | 10 | 2.0000000 | 20000.000 |
26 | 0.0006 | 10 | 16666.667 | 21 | 0.0006 | 10 | 1.6666667 | 16666.667 |
2 | 0.0009 | 16 | 17777.778 | 25 | 0.0009 | 16 | 1.7777778 | 17777.778 |
22 | 0.0013 | 22 | 16923.077 | 28 | 0.0013 | 22 | 1.6923077 | 16923.077 |
19 | 0.0016 | 22 | 13750.000 | 7 | 0.0016 | 22 | 1.3750000 | 13750.000 |
8 | 0.0024 | 32 | 13333.333 | 15 | 0.0024 | 32 | 1.3333333 | 13333.333 |
3 | 0.0034 | 38 | 11176.471 | 10 | 0.0034 | 38 | 1.1176471 | 11176.471 |
23 | 0.0036 | 34 | 9444.444 | 12 | 0.0036 | 34 | 0.9444444 | 9444.444 |
6 | 0.0040 | 34 | 8500.000 | 27 | 0.0040 | 34 | 0.8500000 | 8500.000 |
7 | 0.0055 | 38 | 6909.091 | 20 | 0.0055 | 38 | 0.6909091 | 6909.091 |
17 | 0.0068 | 52 | 7647.059 | 19 | 0.0068 | 52 | 0.7647059 | 7647.059 |
12 | 0.0072 | 60 | 8333.333 | 3 | 0.0072 | 60 | 0.8333333 | 8333.333 |
5 | 0.0080 | 68 | 8500.000 | 6 | 0.0080 | 68 | 0.8500000 | 8500.000 |
14 | 0.0113 | 100 | 8849.558 | 24 | 0.0113 | 100 | 0.8849558 | 8849.558 |
10 | 0.0148 | 104 | 7027.027 | 26 | 0.0148 | 104 | 0.7027027 | 7027.027 |
4 | 0.0159 | 90 | 5660.377 | 23 | 0.0159 | 90 | 0.5660377 | 5660.377 |
SHAPE metric
We are following the definition provided in the latest version of the FRAGSTATS manual, in which the shape index is defined as the perimeter (m) divided by the square root of the area (m2) of patch ij, adjusted by a constant to adjust for a square standard. Yet, for some patches there are minor differences between landscapemetrics and FRAGSTATS.
CIRCLE metric
According to FRAGSTATS, for patches with only one cell CIRCLE = 0.
[…] CIRCLE = 0 for one cell patches. […]
Nevertheless, because also patches with only one cell have a dimension in the raster context, we decided to calculate the CIRCLE metric for such patches.
Click for details
fs_id | fs_area | fs_circle | lsm_id | lsm_area | lsm_circle |
---|---|---|---|---|---|
1 | 1e-04 | 0 | 1 | 1e-04 | 0.3633802 |
24 | 1e-04 | 0 | 4 | 1e-04 | 0.3633802 |
28 | 1e-04 | 0 | 5 | 1e-04 | 0.3633802 |
13 | 1e-04 | 0 | 11 | 1e-04 | 0.3633802 |
15 | 1e-04 | 0 | 13 | 1e-04 | 0.3633802 |
18 | 1e-04 | 0 | 16 | 1e-04 | 0.3633802 |
20 | 1e-04 | 0 | 17 | 1e-04 | 0.3633802 |
It seems like FRAGSTATS uses the largest distance between the corner points of the cells to calculate the diameter of the circumscribing circle. However, this does not necessarily result in the correct circumscribing circle. While this approach works well for more compact patch shapes, there are some cases in which the approach fails. One example are T-shaped patches. Contrastingly to FRAGSTATS, our algorithm calculates the true circumscribing circle also for such patches.
Comparison with SDMTools
SDMTools
(VanDerWal et al. 2014) (still available, but
apparently not longer maintained) offers landscape metrics on patch and
class level. However, it does not return the same results as FRAGSTATS.
The main reason for this are different standard defaults (e.g.,
SDMTools
always considers the global landscape boundary)
and that SDMTools
returns results in map units and not in
m^2/hectar, as FRAGSTATS/landscapemetrics. This also
explains differences between our package and SDMTools
.
Jemma Stachelek was so nice to remind us of these issues and provided the comparison.
Patch metrics
To get all available metrics on, e.g., patch level with
SDMTools
, you have to make a binary landscape for every
class in your landscape, perform connected components labelling on it
and then calculate the patch metrics.
# binarize every class in the landscape and calculate patch metrics
sdmtools_result <- lapply(terra::unique(landscape), FUN = function(x){
tmp_land <- landscape
terra::values(tmp_land)[terra::values(tmp_land) != x] <- NA
terra::values(tmp_land)[terra::values(tmp_land) == x] <- 1
ccl <- SDMTools::ConnCompLabel(raster::raster(tmp_land))
PatchStat(ccl)
})
# combine to one data frame
sdmtools_result <- dplyr::bind_rows(sdmtools_result, .id = "Class")
landscapemetrics offers for such tasks the function
get_patches()
and for the metrics itself all of that is
done internally. To get all metrics on patch level with
landscapemetrics you could for example do:
patch_metrics <- calculate_lsm(landscape, what = "patch")
Click for details
Class | patchID | n.cell | n.core.cell | n.edges.perimeter | n.edges.internal | area | core.area | perimeter | perim.area.ratio | shape.index | frac.dim.index | core.area.index |
---|---|---|---|---|---|---|---|---|---|---|---|---|
clumps | 1 | 3 | 0 | 8 | 4 | 3 | 0 | 8 | 2.666667 | 1.000000 | 1.261859 | 0 |
clumps | 2 | 17 | 0 | 32 | 36 | 17 | 0 | 32 | 1.882353 | 1.777778 | 1.467903 | 0 |
clumps | 3 | 21 | 0 | 46 | 38 | 21 | 0 | 46 | 2.190476 | 2.300000 | 1.604421 | 0 |
clumps | 4 | 6 | 0 | 16 | 8 | 6 | 0 | 16 | 2.666667 | 1.600000 | 1.547411 | 0 |
clumps | 5 | 21 | 0 | 34 | 50 | 21 | 0 | 34 | 1.619048 | 1.700000 | 1.405847 | 0 |
clumps | 6 | 4 | 0 | 10 | 6 | 4 | 0 | 10 | 2.500000 | 1.250000 | 1.321928 | 0 |
clumps | 7 | 3 | 0 | 8 | 4 | 3 | 0 | 8 | 2.666667 | 1.000000 | 1.261859 | 0 |
clumps | 8 | 3 | 0 | 8 | 4 | 3 | 0 | 8 | 2.666667 | 1.000000 | 1.261859 | 0 |
clumps | 9 | 22 | 0 | 48 | 40 | 22 | 0 | 48 | 2.181818 | 2.400000 | 1.607811 | 0 |
clumps | 10 | 21 | 0 | 50 | 34 | 21 | 0 | 50 | 2.380952 | 2.500000 | 1.659195 | 0 |
clumps | 11 | 14 | 0 | 32 | 24 | 14 | 0 | 32 | 2.285714 | 2.000000 | 1.575897 | 0 |
clumps | 12 | 16 | 0 | 34 | 30 | 16 | 0 | 34 | 2.125000 | 2.125000 | 1.543731 | 0 |
clumps | 13 | 22 | 0 | 48 | 40 | 22 | 0 | 48 | 2.181818 | 2.400000 | 1.607811 | 0 |
clumps | 14 | 3 | 0 | 8 | 4 | 3 | 0 | 8 | 2.666667 | 1.000000 | 1.261859 | 0 |
clumps | 15 | 13 | 0 | 32 | 20 | 13 | 0 | 32 | 2.461539 | 2.000000 | 1.621429 | 0 |
clumps | 16 | 15 | 0 | 36 | 24 | 15 | 0 | 36 | 2.400000 | 2.250000 | 1.622736 | 0 |
clumps | 17 | 11 | 0 | 24 | 20 | 11 | 0 | 24 | 2.181818 | 1.714286 | 1.494444 | 0 |
clumps | 18 | 34 | 0 | 74 | 62 | 34 | 0 | 74 | 2.176471 | 3.083333 | 1.654834 | 0 |
clumps | 19 | 2 | 0 | 6 | 2 | 2 | 0 | 6 | 3.000000 | 1.000000 | 1.169925 | 0 |
clumps | 20 | 4 | 0 | 12 | 4 | 4 | 0 | 12 | 3.000000 | 1.500000 | 1.584963 | 0 |
clumps | 21 | 27 | 0 | 62 | 46 | 27 | 0 | 62 | 2.296296 | 2.818182 | 1.663213 | 0 |
clumps | 22 | 1 | 0 | 4 | 0 | 1 | 0 | 4 | 4.000000 | 1.000000 | NaN | 0 |
clumps | 23 | 9 | 0 | 26 | 10 | 9 | 0 | 26 | 2.888889 | 2.166667 | 1.703788 | 0 |
clumps | 24 | 18 | 0 | 42 | 30 | 18 | 0 | 42 | 2.333333 | 2.333333 | 1.627040 | 0 |
References
- McGarigal K., SA Cushman, and E Ene. 2023. FRAGSTATS v4: Spatial Pattern Analysis Program for Categorical Maps. Computer software program produced by the authors; available at the following web site: https://www.fragstats.org
- Jeremy VanDerWal, Lorena Falconi, Stephanie Januchowski, Luke Shoo and Collin Storlie (2014). SDMTools: Species Distribution Modelling Tools: Tools for processing data associated with species distribution modelling exercises. R package version 1.1-221. https://CRAN.R-project.org/package=SDMTools