Coder Social home page Coder Social logo

r-spatialecology / landscapemetrics Goto Github PK

View Code? Open in Web Editor NEW
228.0 14.0 43.0 76.77 MB

Landscape Metrics for Categorical Map Patterns 🗺️ in R

Home Page: https://r-spatialecology.github.io/landscapemetrics

License: GNU General Public License v3.0

R 94.49% C++ 5.51%
r landscape-metrics spatial raster landscape-ecology

landscapemetrics's Introduction

landscapemetrics

README last updated: 2024-07-29

CI Development CRAN License
R-CMD-check lifecycle CRAN status License: GPL v3
codecov Project Status CRAN downloads DOI

Starting from v2.0.0, landscapemetrics uses terra and sf internally. More information about the terra package can be found here: https://rspatial.org/index.html.

Overview

landscapemetrics is a R package for calculating landscape metrics for categorical landscape patterns in a tidy workflow. The package can be used as a drop-in replacement for FRAGSTATS (McGarigal et al. 2023), as it offers a reproducible workflow for landscape analysis in a single environment. It also allows for calculations of four theoretical metrics of landscape complexity: a marginal entropy, a conditional entropy, a joint entropy, and a mutual information (Nowosad and Stepinski 2019).

landscapemetrics supports terra, and stars and takes SpatRaster or stars spatial objects as input arguments. Every function can be used in a piped workflow, as it always takes the data as the first argument and returns a tibble.

Citation

To cite landscapemetrics or acknowledge its use, please cite the following Software note, substituting the version of the application that you used for ‘v0.0’:

Hesselbarth, M.H.K., Sciaini, M., With, K.A., Wiegand, K., Nowosad, J. 2019. landscapemetrics: an open‐source R tool to calculate landscape metrics. Ecography, 42: 1648-1657 (v0.0).

For more information see Publication record vignette. The get a BibTex entry, please use citation("landscapemetrics").

Installation

There are several ways to install landscapemetrics:

# Get the stable version from CRAN
install.packages("landscapemetrics")

# Alternatively, you can install the development version from Github
# install.packages("remotes")
remotes::install_github("r-spatialecology/landscapemetrics")

Announcement

Due to an improved connected-component labelling algorithm (landscapemetrics v1.4 and higher), patches are labeled in a different order than before and therefore different patch IDs might be used compared to previous versions. However, results for all metrics are identical.

Using landscapemetrics

The resolution of a raster cell has to be in meters, as the package converts units internally and returns results in either meters, square meters or hectares. Before using landscapemetrics, be sure to check your raster (see check_landscape()).

All functions in landscapemetrics start with lsm_ (for landscape metrics). The second part of the name specifies the level (patch - p, class - c or landscape - l). The last part of the function name is the abbreviation of the corresponding metric (e.g. enn for the euclidean nearest-neighbor distance):

# general structure
lsm_"level"_"metric"

# Patch level
## lsm_p_"metric"
lsm_p_enn()

# Class level
## lsm_c_"metric"
lsm_c_enn()

# Landscape level
## lsm_p_"metric"
lsm_l_enn()

All functions return an identical structured tibble:

layer level class id metric value
1 patch 1 1 landscape metric x
1 class 1 NA landscape metric x
1 landscape NA NA landscape metric x

Using metric functions

Every function follows the same implementation design, so the usage is quite straightforward:

library(landscapemetrics)
library(terra)

# internal data needs to be read
landscape <- terra::rast(landscapemetrics::landscape)

# landscape raster
plot(landscape)

# calculate for example the Euclidean nearest-neighbor distance on patch level
lsm_p_enn(landscape)
#> # A tibble: 28 × 6
#>    layer level class    id metric value
#>    <int> <chr> <int> <int> <chr>  <dbl>
#>  1     1 patch     1     1 enn     7   
#>  2     1 patch     1     2 enn     4   
#>  3     1 patch     1     3 enn     2   
#>  4     1 patch     1     4 enn     6.32
#>  5     1 patch     1     5 enn     5   
#>  6     1 patch     1     6 enn     2.24
#>  7     1 patch     1     7 enn     2   
#>  8     1 patch     1     8 enn     4.12
#>  9     1 patch     1     9 enn     4.12
#> 10     1 patch     2    10 enn     4.47
#> # ℹ 18 more rows

# calculate the total area and total class edge length
lsm_l_ta(landscape)
#> # A tibble: 1 × 6
#>   layer level     class    id metric value
#>   <int> <chr>     <int> <int> <chr>  <dbl>
#> 1     1 landscape    NA    NA ta      0.09
lsm_c_te(landscape)
#> # A tibble: 3 × 6
#>   layer level class    id metric value
#>   <int> <chr> <int> <int> <chr>  <dbl>
#> 1     1 class     1    NA te       181
#> 2     1 class     2    NA te       203
#> 3     1 class     3    NA te       296

There is also a wrapper around every metric in the package to quickly calculate a bunch of metrics:

# calculate all metrics on patch level
calculate_lsm(landscape, level = "patch")
#> Warning: Please use 'check_landscape()' to ensure the input data is valid.
#> # A tibble: 336 × 6
#>    layer level class    id metric  value
#>    <int> <chr> <int> <int> <chr>   <dbl>
#>  1     1 patch     1     1 area   0.0001
#>  2     1 patch     1     2 area   0.0005
#>  3     1 patch     1     3 area   0.0072
#>  4     1 patch     1     4 area   0.0001
#>  5     1 patch     1     5 area   0.0001
#>  6     1 patch     1     6 area   0.008 
#>  7     1 patch     1     7 area   0.0016
#>  8     1 patch     1     8 area   0.0003
#>  9     1 patch     1     9 area   0.0005
#> 10     1 patch     2    10 area   0.0034
#> # ℹ 326 more rows

Utility functions

landscapemetrics further provides several visualization functions, e.g. show all labeled patches or the core area of all patches. All visualization functions start with the prefix show_ (e.g. show_cores()).

Important building blocks of the package are exported to help facilitate analysis or the development of new metrics. They all start with the prefix get_. All of them are implemented with Rcpp and have either memory or performance advantages compared to raster functions.

For more details, see the vignette("utility").

Contributing

One of the major motivations behind landscapemetrics is the idea to provide an open-source code collection of landscape metrics. This includes, besides bug reports, especially the idea to include new metrics and functions. Therefore, in case you want to suggest new metrics or functions and in the best case even contribute code, we warmly welcome to do so! For more information see CONTRIBUTING.

Maintainers and contributors must follow this repository’s CODE OF CONDUCT.

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/

Nowosad J., TF Stepinski. 2019. Information theory as a consistent framework for quantification and classification of landscape patterns. https://doi.org/10.1007/s10980-019-00830-x

landscapemetrics's People

Contributors

actions-user avatar bitbacchus avatar davzim avatar gponce-ars avatar jsta avatar kalab-oto avatar kant avatar marcosci avatar mhesselbarth avatar mstrimas avatar nowosad avatar rekyt avatar web-flow avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

landscapemetrics's Issues

stars

Stars is on CRAN now, I tested it once and it should be rather easy to support them - should we add that in the coming release or is there anything speaking against that?

Vignettes

I've had a look over the vignettes. It's looking fantastic and really well explained. I've made a few small corrections (typos and additional clarification where needed). Do you want me to just push, or would you prefer me to fork and do a pull request?

Some points on which I did not want to make large changes:

General points

  • Do you have any plans to allow for vector input? I can see cases in which this would be useful. Or do you think they may be so limited that it's fine to expect users to rasterize their data.
  • Core metrics: currently depth of edge is fixed to 1 cell. Might this be problematic for some uses because it is directly dependent on the resolution of the data. Could this be something a user specifies?

Utility functions

  • Connected labelling plots: viridis colour scheme doesn't really work very well in this case (especially plot 3 - the difference between colours is not visible) - is there another colour scheme that could be used?
  • Get adjacencies - need explanation of the second parameter (given as 4), why is 1-NA in the explanation? Also explanation of the output. I've also added a separate issue about this function.

Functions

  • I think it would be useful to have the names in full on this page (rather than the fragstats abbreviations). Some users won't be familiar with FRAGSTATS and it's a pain to click through to the page just to see what the function does if it's not immediately obvious.

I'll have a look at the functions in more depth and send any thoughts about those.

All checks return note

All checks started to return:

❯ checking top-level files ... NOTE
  Non-standard file/directory found at top level:
    ‘pkgdown’

Any ideas why?

Edges

Hi metrics hivemind,

is there any preferred strategy for edge detection?

We polygonized raster and dissolved them so far, which is quite fast with gdal_polygonize - but that would make the dependencies quite heavy. In some issues in fasterize and sf they spoke about implementing that, but I have not seen it so far.

Borrowing C++ code for connected labeling (the way SDMTools does it) is the other alternative - with the problem that you have to do that always for each class separately and have to go lengths to calculate edge length etc (as one can't simply calculate the length of the perimeter of a polygon).

Is there any preference for one of the two approaches?

Rcpp

Hey @Nowosad,

we were playing around with your rcpp functions - really handy stuff in there 👍

Just one weird thing with rcpp_get_coocurrence_matrix:

foo <- function(landscape){
    
    raster_padded <- pad_raster(landscape, pad_raster_value = -999,
                                pad_raster_cells = 1)
    
    adjacent_cells <- raster::adjacent(
        raster_padded,
        cells =  seq_len(raster::ncell(raster_padded)),
        directions = 4,
        pairs = TRUE
    )
    
    tb <- table(raster_padded[adjacent_cells[, 1]],
                raster_padded[adjacent_cells[, 2]])
    
    return(tb)
}


foo2 <- function(landscape){
    raster_padded <- pad_raster(landscape, pad_raster_value = -999,
                                pad_raster_cells = 1)
    
    tb <- rcpp_get_coocurrence_matrix(raster::as.matrix(raster_padded), directions = 4)
    
    return(tb)
}

x <- microbenchmark(
    r_stuff <- foo(podlasie_ccilc), 
    cpp <- foo2(podlasie_ccilc), 
    times = 100
)

x
Unit: seconds
                           expr      min       lq     mean   median       uq      max neval
 r_stuff <- foo(podlasie_ccilc) 2.066591 2.242272 2.429078 2.450698 2.558393 3.056486   100
    cpp <- foo2(podlasie_ccilc) 3.133793 3.462482 3.560858 3.565013 3.705634 3.951005   100

y <- microbenchmark(
    r_stuff <- foo(landscape), 
    cpp <- foo2(landscape), 
    times = 100
)

y
Unit: milliseconds
                      expr       min        lq      mean    median        uq      max neval
 r_stuff <- foo(landscape) 13.405927 14.166557 16.004563 14.811494 16.061616 49.77265   100
    cpp <- foo2(landscape)  2.200139  2.314256  2.839799  2.465439  2.690333 13.05235   100

.... for landscape it's way faster - but not for podlasie. Do you have anything in mind, why that could be?

show_patches

Shouldn't show_patches() be a part of the landscapetools package? What do you think?

Functions structure

Hey all!

I've opened this issue to discuss the internal structure of functions in this package.
Main idea:

  1. Don't repeat yourself. Most of the functions have the same/similar code twice - one for RasterLayer and second time for RasterStack/Brick, for example - https://github.com/marcosci/landscapemetrics/blob/master/R/lsm_l_shei.R. I would think there is a better way to handle it. Please take a look at my gist - https://gist.github.com/Nowosad/27341392f3053eab657efbe3cd42e999. It has only one main function (lsm_l_shei_calc) and the rest is just method calls. What do you think about it? I assume it also can be improved, but it is a step in right direction (in my opinion).

Minor ideas:

  1. We should use as.integer() instead of as numeric() for the layer or the id number.
  2. Consistent coding style is very helpful and it looks really good now. However, the only inconsistent thing that I've found is the use of single (') and double (") quotation marks. I would suggest that we stick to the double quotes.
  3. I would suggest using seq_len(nlayers(landscape)) instead of 1:raster::nlayers(landscape). In our case it is not a big deal, but it is a better programming style and helps to avoid problems in some cases (http://www.win-vector.com/blog/2018/02/r-tip-use-seq_len-to-avoid-the-backwards-sequence-bug/).

Let me know what you think about it. I am looking forward to your comments!
J.

New name

Since we actually worked on a lot of different stuff, I just renamed branch get_unique_values2 to rcpp_updates

Whitespace

Remove any whitespace around plots on the homepage

memory leak rcpp functions

For larger raster objects (starts in my case with 263169 cells - 513x513 rasters from NLMR) I get the following error:

 *** caught segfault ***
address 0xab0d4c0, cause 'invalid permissions'

Happens for some at random times, in the case of rcpp_get_composition_vector every time.
Only appears on Scientific linux/gcc 6.3.0, not on my Ubuntu machine.

Will look into this in 2 weeks - just a reminder here.

Error: requested size is too large

Hello,

I am trying to use the lsm_p_contig function on a raster, but I keep receiving the following error:

error: Mat::init(): requested size is too large
Error in rcpp_get_coocurrence_matrix(raster::as.matrix(patches_class), :
Mat::init(): requested size is too large

Here's the details about my raster:
dimensions : 30499, 28435, 867239065 (nrow, ncol, ncell)
resolution : 1, 1 (x, y)
extent : 475532, 503967, 4412908, 4443407 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : C:\Users\cshade\Desktop\FragStat_analysis\lc_2008_4bit_clip_reclass.tif
names : lc_2008_4bit_clip_reclass
values : 1, 3 (min, max)

Before I was trying to use 8 different classes, but I reclassified down to 3, although that did not seem to help.

Here are the details about my computer and software:

  • Windows 10
  • I'm using R 64 bit 3.5.1
  • I have 120 GB of RAM (it's not maxing out during the process)
  • I have 588 GB of free memory (also not maxing out)

I have been loading the raster into my RAM before starting the process.

I know other people have seemed to have a similar issue with raster size, but it seems no one has ever found a solution. Any help would be greatly appreciated!:)

Other (not-implemented) metrics

To keep it a bit more organized, here a single list with the metrics we are currently missing.

Cell-aggregation metrics

Contrast metrics

Patch level

  • Proximity index (Responsible: 👻) -> Needs user to specify search radius
  • Similarity index (Responsible: 👻) -> Needs user to input similarity table

Class level

  • Linearity index distribution (Responsible: 👻) -> Not in FRAGSTATS manual
  • Connectance (Responsible: @marcosci ) -> Needs nearest neighbor distances, so we wait until we have a good solution for ENN
  • Proximity index distribution (Responsible: 👻) -> Needs search radius
  • Similarity index distribution (Responsible: 👻) -> Needs similarity table
  • Linearity index distribution (Responsible: 👻) -> Not in FRAGSTATS manual
  • MFRAC (Responsible: 👻)

Landscape level

  • Linearity index distribution (Responsible: 👻) -> Missing in FRAGSTATS manual
  • Proximity index distribution (Responsible: 👻) -> Needs search radius
  • Similarity index (Responsible: 👻) -> Needs similarity table
  • Connectance (Responsible: @marcosci )

Memory

We should mention somewhere on the homepage that computing a lot of metrics (especially if you parallelize your code) creates a lot of copies of the rasters, so setting:

options(rasterMaxMemory = nbytes)

... can save some time finding out why RStudio freezes every now and then.

Base_functions()

I just created a new branch called base_functions - the idea is to subsequently replace purrr::map with the apply family (base R) and also get rid of all pipes. Both just adds dependencies we actually don't really need

Landscape metrics within neighborhood of points (feature request)

Great package, love the interface! I see two use cases that this package doesn't directly address, which come up for me when generating habitat covariates for species distribution models:

  1. Given a set of points, calculate landscape metrics within a neighborhood of each point, e.g. within a 1km buffer.
  2. Given a landcover raster at fine resolution, e.g. 30m, aggregate to a coarser resolution, e.g. 1km, calculating landscape metrics within each coarse cell. Solving 1 would also address this.

In both cases, I can do this in a hacky way by clipping out a small raster around each point/raster cell center, calculating the landscape metrics, then iterating over all points/centers. However, it's not very efficient. Any chance of including a helper function to speed up and simplify this process?

Landscape level metrics

Possible metrics at landscape level (prelimenary list).
All metrics label with distribution include the mean, the standard deviation and the coefficient of variation.

  • Landscape richness (Responsible: @marcosci)
  • Total edge (Responsible: @marcosci)
  • Number of patches (Responsible: @marcosci)
  • Radius of Gyration distribution (Responsible: @marcosci)
  • Related circumscribing circle distribution (Responsible: @marcosci)
  • Clumpiness Index (Responsible: @marcosci)
  • Euclidean nearest neighbor distance distribution (Responsible: @marcosci) -> SD and CV missing
  • Total area (Responsible: @mhesselbarth)
  • Landscape richness density (Responsible: @mhesselbarth)
  • Relative patch richness (Responsible: @mhesselbarth)
  • Largest patch index (Responsible: @mhesselbarth)
  • Patch area distribution (Responsible: @mhesselbarth)
  • Fractal index distribution (Responsible: @mhesselbarth)
  • Perimeter-area fractal dimension (Responsible: @mhesselbarth)
  • Perimeter-area ratio distribution (Responsible: @mhesselbarth)
  • Shape index distribution (Responsible: @mhesselbarth)
  • Total core area (Responsible: @mhesselbarth)
  • Number of disjunct core areas (Responsible: @mhesselbarth)
  • Disjunct core area density (Responsible: @mhesselbarth)
  • Core area distribution (Responsible: @mhesselbarth)
  • Disjunct core area distribution (Responsible: @mhesselbarth)
  • Core area index distribution (Responsible: @mhesselbarth)
  • Simpson's diversity ( (Responsible: @mhesselbarth)
  • Simpson's evenes ( (Responsible: @mhesselbarth)
  • Modified Simpson's diversity ( (Responsible: @mhesselbarth)
  • Modified Simpson's evenes ( (Responsible: @mhesselbarth)
  • Landscape shape index (Responsible: @mhesselbarth)
  • Patch density (Responsible: @mhesselbarth)
  • Landscape division index (Responsible: @mhesselbarth)
  • Splitting index (Responsible: @mhesselbarth)
  • Effective mesh size (Responsible: @mhesselbarth)
  • Edge density (Responsible: @mhesselbarth)
  • Interspersion/Juxtaposition (Responsible: @mhesselbarth)
  • Shannon Diversity (Responsible: @laurajanegraham)
  • Shannon evennes (Responsible: @laurajanegraham)
  • Landscape contagion index (Responsible: 👻)
  • Aggregation index (Responsible: 👻)
  • Linearity index distribution (Responsible: 👻) -> Missing in FRAGSTATS manual
  • Contiguity index distribution (Responsible: 👻)
  • Contagion (Responsible: 👻)
  • Percentage of like adjacencies (Responsible: 👻)
  • Patch cohesion index (Responsible: 👻)
  • Proximity index distribution (Responsible: 👻) -> Needs search radius
  • Similarity index (Responsible: 👻) -> Needs similarity table
  • Connectance (Responsible: 👻)

Discussion Wishlist

  1. @Nowosad what do you think about parallelization? Is one dependency more worth the speed gain?

  2. I assume you also added sf support: That would be just a wrapper around rasterize, or?

Document comparison with SDMTools::PatchStats

I am considering porting some code using SDMTools::PatchStats to landscapemetrics::calculate_metrics(what = "patch") but I am having some difficulty comparing their outputs. Would some documentation comparing the two be welcome? If so, does it make sense to document in the README, vignette, or function docs?

Update 0.3.1

I think the bugfixes and changes (see attached NEWS.md), especially the one in sample_lsm() justify a CRAN realease (v.0.3.1). If you guys agree, I would submit it to CRAN later this week.

Things to do:

Error in `lsm_p_circle()`

library(landscapemetrics)
library(raster)
#> Loading required package: sp
my_landscape = new("RasterLayer", file = new(".RasterFile", name = "", datanotation = "FLT4S", 
                                             byteorder = "little", nodatavalue = -Inf, NAchanged = FALSE, 
                                             nbands = 1L, bandorder = "BIL", offset = 0L, toptobottom = TRUE, 
                                             blockrows = 1L, blockcols = 87212L, driver = "", open = FALSE), 
                   data = new(".SingleLayerData", values = c(80L, 80L, 80L, 
                                                             80L, 12L, 12L, 12L, 12L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 
                                                             80L, 12L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 12L, 80L, 80L, 
                                                             80L, 80L, 80L, 80L, 80L, 12L, 80L, 80L, 80L, 80L, 80L, 80L, 
                                                             80L, 12L, 80L, 80L, 12L, 12L, 80L, 80L, 80L, 12L, 12L, 12L, 
                                                             12L, 12L, 80L, 80L, 80L, 12L, 12L, 12L, 12L, 12L, 12L, 80L, 
                                                             80L, 12L, 12L, 12L, 12L, 12L, 12L, 80L, 212L), offset = 0, 
                              gain = 1, inmemory = TRUE, fromdisk = FALSE, isfactor = FALSE, 
                              attributes = list(), haveminmax = TRUE, min = 12L, max = 212L, 
                              band = 1L, unit = "", names = "plot_1"),
                   legend = new(".RasterLegend", type = character(0), values = logical(0), color = logical(0), 
                                names = logical(0), colortable = logical(0)), title = character(0), 
                   extent = new("Extent", xmin = 1848294.46073262, xmax = 1848489.7135494, 
                                ymin = 1146966.88501973, ymax = 1147186.5444386), rotated = FALSE, 
                   rotation = new(".Rotation", geotrans = numeric(0), transfun = function () 
                       NULL), ncols = 8L, nrows = 9L, crs = new("CRS", projargs = "+proj=aea +lat_1=27 +lat_2=45 +lat_0=35 +lon_0=105 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0"), 
                   history = list(), z = list())
plot(my_landscape)

lsm_p_circle(my_landscape)
#> Error in points[, 3] <- landscape_labeled[!is.na(class_boundaries)]: incorrect number of subscripts on matrix

Created on 2019-01-21 by the reprex package (v0.2.1)

Problem with sample_lsm()

Based on the example in the help file:

library(landscapemetrics)
data("landscape")
points <- matrix(c(10, 5, 25, 15, 5, 25), ncol = 2, byrow = TRUE)
points_sp <- sp::SpatialPoints(points)
sample_lsm(landscape,
           points = points_sp, 
           size = 15, 
           what = "all")
#> Error in get(metrics_calc[[current_metric]], mode = "function"): object '_calc' of mode 'function' was not found

Created on 2019-01-18 by the reprex package (v0.2.1)

get_unique_values() does not work for vectors

I've started writing some additional tests and found out there is an issue when a numeric/integer vector is provided to get_unique_values():

library(landscapemetrics)
get_unique_values(c(1, 3))
#> Error in UseMethod("get_unique_values"): no applicable method for 'get_unique_values' applied to an object of class "c('double', 'numeric')"
get_unique_values(c(1L, 3L))
#> Error in UseMethod("get_unique_values"): no applicable method for 'get_unique_values' applied to an object of class "c('integer', 'numeric')"

Created on 2018-12-05 by the reprex package (v0.2.1)

Ideas for future updates

Just a list of possible ideas for future updates.

Maybe it makes sense to also include this list as a page on the homepage?

  • Think about including terra at some point
  • Including parallel computation (if we can somehow can controll what is happening): #87
  • Make sure everything runs for large raster

rcpp: specifing a neighborhood matrix

"It would be really helpful if one can specify the neighborhood of your adjacency function using e.g. a matrix and not being "limited" to the queen's or rook's case (comparable to the raster::adjacency directions option)."

Validation of the metrics

I think that functions validation is essential in projects like this one. Thus, I suggest the following steps after implementing all of basic metrics (in order):

  • 1. Create a diverse set of test examples. Dimensions: (a) input type (e.g. RasterLayer vs RasterStack), (b) number of classes (e.g. binary vs 5-classes), (c) data availability (e.g. full data vs some missing values), (d) distribution of values (e.g. random vs aggregated). [Am I missing something here?]
  • 2. Calculate all of the metric using FRAGSTATS. Save the results.
  • 3. Create a bunch of tests using testthat. They should compare our results and the FRAGSTATS's ones.
  • 4. The test (and codecov) should also show where we need to add some argument tests (#6 (comment)).

As always - it is just my idea. I am interested in your opinions!

lsm_c_ed -> subscript out of bounds

I get an error message with this function:

`> lsm_c_ed(landscape)

Error in [.default(tb, 2:ncol(tb), 1) : subscript out of bounds`

The error seems to occur in file lsm_c_te.R line 112, but I couldn't figure out the details. The error occurred also before commit 086c1d2 .

I attached two landscape files (please rename to .asc), one that triggers the error, one that doesn't. A minimal example to trigger the error would be:

`
landscape <- raster("landscape.asc")
lsm_c_ed(landscape) # error

landscape <- raster("landscape_ok.asc")
lsm_c_ed(landscape) # no error
`

Please let me know if I can give any support.

Best,
Sebastian

landscape.txt
landscape_ok.txt

Vignettes R CMD CHECK note

Does someone know how to avoid this note?

N  checking for unstated dependencies in vignettes ...
   '::' or ':::' import not declared from:landscapetools'library' or 'require' call not declared from:patchwork

We have a couple of "vignettes" that are only meant for the homepage.
They are in vignettes/articles, which is included in .Rbuildignore and I stripped everything related to vignettes from the yaml header - but the R CMD CHECK still thinks they would end up in the package?

Error in lsm_p_circle

According to FRAGSTATS manual:

CIRCLE = 0 for one cell patches.

We somehow missed that.

How to spatialize metrics?

Hi there

I have just found out about the package and it seems great. I made some tests and it is quite fast, also. Congrats for that!
My question is whether we can spatialize metrics. For instance, if I calculate the Euclidean nearest neighbor for each patch of each class, how can I produce a map with enn values in each pixel of the patches? (something to be able to visualize it, equivalent to the show_patches function but with enn values intead of class categories ou patch identity codes).
Is it already implemented?

Thanks,
Bernardo Niebuhr

Getting rid of dplyr

@marcosci and I just discussed to get rid of the dplyr dependency.

Most of the time we only use group_by()in combination with summarise()which could be replaced by aggregate(). Besides that, we use mutate() here and there. But also this could be repplaced quite easily.

All of this would make our coding a bit more complicated, but maybe worth getting rid of the dependency?

Any thoughts on that ?

Patch level metrics

Possible metrics at patch level (prelimenary list).

  • Patch size (Responsible: @mhesselbarth)
  • Perimeter (edge) (Responsible: @mhesselbarth)
  • Perimeter-to-area ratio (Responsible: @mhesselbarth)
  • Fractal dimension (Responsible: @mhesselbarth)
  • Shape index (Responsible: @mhesselbarth)
  • Core area (Responsible: @mhesselbarth)
  • Number of core areas (Responsible: @mhesselbarth)
  • Core area index (Responsible: @mhesselbarth)
  • Radius of Gyration (Responsible: @marcosci)
  • Related circumscribing circle (Responsible: @marcosci)
  • Proximity index (Responsible: @marcosci) -> Needs user to specify search radius
  • Contiguity index (Responsible: 👻)
  • Similarity index (Responsible: 👻) -> Needs user to input similarity table

Hectare/Metrics

This came up in the testing issue:

Hectare vs map units.
Fragstats uses hectare and assumes everything you put into fragstats is in meters and has a resolution > 0.0001. We are obviously not limited by that and could use map units instead. Nevertheless, from the reproducibility and science perspective, one would lose the capability to compare results against fragstats ... but would have much more intuitive results.

Option 1: We leave it as it right now (assuming resolution/grain in meters) and if people use the package and find it weird we change it into map units.

Option 2: They are better reasons for switching to map units than we can come up with. If so, I am happy to change everything to work with map insteads instead of hectare.

How to proceed

Maybe just a short explanation how we thought it would be the best to develop the package from now on.

I think the way to go on from here, is to create a new branch from the develop branch whenever someone wants to add or modify the code. Just name the branch according to your changes (e.g. the name of the new function or metric). Once everything is running smoothly we can merge the new branch into the development branch. The development branch would be the stable one for installing the package from GitHub, while the master branch would be the one for the CRAN releases. So feel free the create a new branch whenever you want :)

CRAN submission v0.3

We want to release the new version to CRAN at the end of the week.

Things to do:

  • Tests for all new functions
  • Sanity checks, maybe @mhesselbarth can run the use case again and I do the same with some NLMs?
  • Spellchecks, gp::goodpractice, etc. (e8f924d)
  • Update docs (ebdf902)
  • get_unique_values() for RasterStack (cb6a1a8 / 51ff2e5)

FINAL:

  • Merge with CRAN branch
  • Create "release"-tag

Test suite

@Nowosad suggested to test the results of our functions against the results from fragstats.

To do so, @mhesselbarth ran each examplary landscape in the package through fragstats:
fragstat_landscapemetrics.zip

Would make sense to bring the fragstats results in a tidy format and then come up with a streamlined approach to test everything.

Agenda

If you still plan to be on board, I invited both of you to a slack channel @ ropensci - I started there to discuss a naming scheme :)

get_adjacencies

A couple of points on the get_adjacencies function that I think need clarifying / improving:

  1. upper = TRUE only has an effect (and only makes sense) for unlike. What is the reasoning for having this parameter?

  2. Full explanation of the output would be useful.

  3. The second parameter will take in some nonsensical parameters. For example, a single number can be provided as input, but it doesn't make sense to do so. I'll see if I can add in a meaningful check to this (e.g. check input is 4, 8 or logical matrix).

Vignette New Metrics

Hey Jakub,

I started a vignette about new metrics in landscapemetrics that are not from FRAGSTATS.
The idea is to shed some light on them and that they don't drown in the masses of metrics coming from FRAGSTATS:

https://marcosci.github.io/landscapemetrics/articles/articles/new_metrics.html

I would reference every paper there and link the functions. I think it would be nice to have 3,4 sentences briefly describing them under the quote - would it be OK for you to write something about yours there? ☺️

Whishlist

Ideas for the future:

  • Adding the class to show_patches()
  • Use future-package for parallel computation
  • Function that runs every metric with the option to only run for patch, class or landscape scale (calculate_metrics(landscapes, what = "all"))
  • Support for non-raster data, for example sf objects
  • Vignette
    • Subvignette with a 3 column facet plot. Every row is one metric, every column represents from left to right a low, medium and high value of the corresponding metric. The plot itself is a landscape (most likely from NLMR) with the same characteristic described by the metric.

Bugs in FRAGSTATS

... our in Max's and my head.

A short list here to collect everything:

  • Patches with 1 cell get a CIRCLE metric of 0, should be something around 0.36 instead
    • Sometimes the abbreviation is CIRCLE, sometimes SQUARE
  • A mixup between hectare and meter in documentation and code
    • Perimeter-Area Ratio (PARA)

Edge case for `lsm_p_core()`

lsm_p_core() gives an error when the input raster is just one patch. What's the proper output value here? Zero?

library(raster)
#> Loading required package: sp
library(landscapemetrics)
x = raster(nrows = 100, ncols = 100, 
           xmn = 0, xmx = 100,
           ymn = 0, ymx = 100,
           crs = NA)
x[] = 2
plot(x)

# works -------------------------------------------------------------------
lsm_l_area_mn(x)
#> # A tibble: 1 x 6
#>   layer level     class    id metric  value
#>   <int> <chr>     <int> <int> <chr>   <dbl>
#> 1     1 landscape    NA    NA area_mn     1

# fails -------------------------------------------------------------------
lsm_p_core(x)
#> Error in cells_patch - cells_edge_patch: non-conformable arrays

Created on 2019-01-19 by the reprex package (v0.2.1)

Class level metrics

Possible metrics at class level (prelimenary list).
All metrics label with distribution include the mean, the standard deviation and the coefficient of variation.

  • Percentage of Landscape (Responsible: @mhesselbarth)
  • Total area (Responsible: @mhesselbarth)
  • Number of patches (Responsible: @mhesselbarth)
  • Patch Area Distribution (Responsible: @mhesselbarth)
  • Largest patch index (Responsible: @mhesselbarth)
  • Fractal Index Distribution (Responsible: @mhesselbarth)
  • Perimeter-area fractal dimension (Responsible: @mhesselbarth)
  • Perimeter-area ratio distribution (Responsible: @mhesselbarth)
  • Shape index distribution (Responsible: @mhesselbarth)
  • Total core area (Responsible: @mhesselbarth)
  • Core area percentage of landscape (Responsible: @mhesselbarth)
  • Number of disjunct core areas (Responsible: @mhesselbarth)
  • Disjunct core areas density (Responsible: @mhesselbarth)
  • Core area distribution (Responsible: @mhesselbarth)
  • Disjunct core area distribution (Responsible: @mhesselbarth)
  • Core area index distribution (Responsible: @mhesselbarth)
  • Landscape shape index (Responsible: @mhesselbarth)
  • Patch density (Responsible: @mhesselbarth)
  • Landscape division index (Responsible: @mhesselbarth)
  • Splitting index (Responsible: @mhesselbarth)
  • Effective mesh size (Responsible: @mhesselbarth)
  • Interspersion/Juxtaposition index (Responsible: @mhesselbarth)
  • Patch cohesion index (Responsible: @mhesselbarth)
  • Total edge (Responsible: @marcosci)
  • Edge density (Responsible: @marcosci)
  • Mean Euclidean nearest neighbor distance (Distribution) (Responsible: @marcosci) -> CV and SD missing
  • Like-Adjacencies (Responsible: @marcosci)
  • Radius of Gyration distribution (Responsible: @marcosci)
  • Related circumscribing circle distribution (Responsible: @marcosci)
  • Aggregation index (Responsible: 👻)
  • Clumpiness index (Responsible: 👻)
  • Contiguity index distribution (Responsible: 👻)
  • Linearity index distribution (Responsible: 👻) -> Not in FRAGSTATS manual
  • Connectance (Responsible: 👻)
  • normalized landscape shape index (Responsible: 👻)
  • Proximity index distribution (Responsible: 👻) -> Needs search radius
  • Similarity index distribution (Responsible: 👻) -> Needs similarity table
  • Linearity index distribution (Responsible: 👻) -> Not in FRAGSTATS manual

Copied Issue from NLMR

Implement metric functions:

  • Fractal dimension
  • Hurst
  • Lacunarity
  • Proportion of landscape
  • Number of instances
  • Instance size distribution
  • Instance perimeter
  • Instance bounding box aspect-ratio and proportion of bounding box area
  • Instance edge contrast index
  • Total edge

Slager CTJ, De Vries B. 2013. Landscape generator: Method to generate landscape configurations for spatial plan-making. Computers, Environment and Urban Systems 39:1–11. Elsevier Ltd.

  • Nc, the number of patches of a particular land-cover type
  • Sav, the area-weighted average patch size (ha)
  • Clg, the correlation length (m), which measures how compact the habitat patches are

Gardner RH, Urban DL. 2007. Neutral models for testing landscape hypotheses. Landscape Ecology 22:15–29.

tic

Just included a running tic script, that automatically:

  • renders the readme
  • runs devtools::document
  • builds the website

... if there is anything else you would like to be done by tic, let me know!
Currently, this behavior is only triggered on the master branch - so if you fork something, this will not happen there.

problem with `lsm_p_gyrate()`

It is probably related to #71.

library(landscapemetrics)
library(raster)
#> Loading required package: sp
my_landscape = new("RasterLayer", file = new(".RasterFile", name = "", datanotation = "FLT4S", 
                                             byteorder = "little", nodatavalue = -Inf, NAchanged = FALSE, 
                                             nbands = 1L, bandorder = "BIL", offset = 0L, toptobottom = TRUE, 
                                             blockrows = 1L, blockcols = 87212L, driver = "", open = FALSE), 
                   data = new(".SingleLayerData", values = c(80L, 80L, 80L, 
                                                             80L, 12L, 12L, 12L, 12L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 
                                                             80L, 12L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 12L, 80L, 80L, 
                                                             80L, 80L, 80L, 80L, 80L, 12L, 80L, 80L, 80L, 80L, 80L, 80L, 
                                                             80L, 12L, 80L, 80L, 12L, 12L, 80L, 80L, 80L, 12L, 12L, 12L, 
                                                             12L, 12L, 80L, 80L, 80L, 12L, 12L, 12L, 12L, 12L, 12L, 80L, 
                                                             80L, 12L, 12L, 12L, 12L, 12L, 12L, 80L, 212L), offset = 0, 
                              gain = 1, inmemory = TRUE, fromdisk = FALSE, isfactor = FALSE, 
                              attributes = list(), haveminmax = TRUE, min = 12L, max = 212L, 
                              band = 1L, unit = "", names = "plot_1"),
                   legend = new(".RasterLegend", type = character(0), values = logical(0), color = logical(0), 
                                names = logical(0), colortable = logical(0)), title = character(0), 
                   extent = new("Extent", xmin = 1848294.46073262, xmax = 1848489.7135494, 
                                ymin = 1146966.88501973, ymax = 1147186.5444386), rotated = FALSE, 
                   rotation = new(".Rotation", geotrans = numeric(0), transfun = function () 
                     NULL), ncols = 8L, nrows = 9L, crs = new("CRS", projargs = "+proj=aea +lat_1=27 +lat_2=45 +lat_0=35 +lon_0=105 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0"), 
                   history = list(), z = list())
plot(my_landscape)

lsm_p_gyrate(my_landscape)
#> Error in points[, 3] <- landscape_labeled[!is.na(landscape_labeled)]: incorrect number of subscripts on matrix

Created on 2019-01-21 by the reprex package (v0.2.1)

error in large Raster files

Hello all
I have several raster files with the characteristics below, when I try to calculate any metrics (any level) returns error in memory (below example). Is there any alternative to calculating the metrics in large files like these? Some alternative to this problem would be very important.

Thank you in advance for your thoughts, they are very much appreciated!

Best Regards

Rodrigo Vasconcelos

############################################################
Ex.
aa='C:/Users/Mapbiomas/Desktop/CAATINGA/clip_geral_1985.tif'
kk=raster(aa)
calc.metrics=calculate_metrics(kk,what = "class")
Error: cannot allocate vector of size 6.3 Gb

*Raster proprities
class : RasterLayer
dimensions : 49368, 34377, 1697123736 (nrow, ncol, ncell)
resolution : 0.0002694957, 0.0002694969 (x, y)
extent : -44.43804, -35.17359, -16.08875, -2.784231 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : C:\Users\Mapbiomas\Desktop\CAATINGA\clip_geral_1985.tif
names : clip_geral_1985
values : 0, 255 (min, max)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.