Giter Club home page Giter Club logo

vectormetrics's Introduction

vectormetrics

Lifecycle: experimental Codecov test coverage R-CMD-check

Overview

vectormetrics is an R package for calculating landscape and shape metrics for vector layers. Its aim is to provide a set of metrics that can characterize landscape patterns and properties of the shapes defined as polygons and multipolygons. Whole package is based on Simple Feature geometry standard provided by sf package. Every function can be used in a tidy, piped workflow, as it always takes the data as the first argument and returns a tibble.

Installation

You can download most recent development version of the package from GitHub with:

remotes::install_github("r-spatialecology/vectormetrics")

Using vectormetrics

Function names structure

All functions in vectormetrics start with vm_ (for vector 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 and rect for the rectangularity). Some landscape and class level functions have also a suffix at the end, that specifies the aggregation method (e.g. mean, sd).

# Patch level
## vm_p_"metric"
vm_p_area()
vm_p_square()

# Class level
## vm_c_"metric"[_"aggregation"]
vm_c_np()
vm_c_shape_sd()

# Landscape level
## vm_l_"metric"[_"aggregation"]
vm_l_lpi()
vm_l_square_mn()

Examples

Some examples of calculating metrics on all levels and with different class and patch columns.

library(vectormetrics)
library(sf)
data("vector_landscape")
plot(vector_landscape)

## Shape index
vm_p_shape(vector_landscape, class_col = "class")
#> MULTIPOLYGON geometry provided. You may want to cast it to separate polygons with 'get_patches()'.
#> This message is displayed once per session.
#> # A tibble: 3 × 5
#>   level class id    metric value
#>   <chr> <chr> <chr> <chr>  <dbl>
#> 1 patch 1     1     shape   5.06
#> 2 patch 2     2     shape   4.76
#> 3 patch 3     3     shape   4.80

## Number of patches
vm_c_np(vector_landscape, class_col = "class")
#> # A tibble: 3 × 5
#>   level class id    metric value
#>   <chr> <chr> <chr> <chr>  <int>
#> 1 class 1     <NA>  np         1
#> 2 class 2     <NA>  np         1
#> 3 class 3     <NA>  np         1

## Largest patch index
vm_l_lpi(vector_landscape)
#> # A tibble: 1 × 5
#>   level     class id    metric value
#>   <chr>     <chr> <chr> <chr>  <dbl>
#> 1 landscape <NA>  <NA>  lpi     49.7

## Mean squareness
vm_l_square_mn(vector_landscape)
#> # A tibble: 1 × 5
#>   level     class id    metric value
#>   <chr>     <chr> <chr> <chr>  <dbl>
#> 1 landscape <NA>  <NA>  sq_mn  0.232

Utility functions

For now there are two utility functions available in the package. First one is get_patches() which breaks multipolygon geometries into polygons. There are two types of neighborhood relations available: 4 (edge) and 8 (vertex). This function enables users to create set of geometries from aggregated shapes and analyze each shape’s properties separately.

vector_patches = get_patches(vector_landscape, class_col = "class", direction = 4)
vector_patches
#> Simple feature collection with 40 features and 2 fields
#> Geometry type: POLYGON
#> Dimension:     XY
#> Bounding box:  xmin: 0 ymin: 0 xmax: 30 ymax: 30
#> CRS:           NA
#> First 10 features:
#>    class patch                       geometry
#> 1      1     1 POLYGON ((1 2, 0 2, 0 3, 0 ...
#> 2      1     2 POLYGON ((14 5, 15 5, 16 5,...
#> 3      1     3 POLYGON ((12 18, 12 19, 12 ...
#> 4      1     4 POLYGON ((10 19, 10 18, 9 1...
#> 5      1     5 POLYGON ((5 20, 6 20, 6 19,...
#> 6      1     6 POLYGON ((6 21, 7 21, 7 20,...
#> 7      1     7 POLYGON ((3 16, 4 16, 4 15,...
#> 8      1     8 POLYGON ((2 24, 2 23, 2 22,...
#> 9      1     9 POLYGON ((10 20, 11 20, 11 ...
#> 10     1    10 POLYGON ((13 24, 14 24, 14 ...

vector_patches |>
  dplyr::mutate(patch = as.factor(patch)) |>
  plot()

## Shape index
vm_p_shape(vector_patches, class_col = "class", patch_col = "patch")
#> # A tibble: 40 × 5
#>    level class id    metric value
#>    <chr> <chr> <chr> <chr>  <dbl>
#>  1 patch 1     1     shape   1.66
#>  2 patch 1     2     shape   1.37
#>  3 patch 1     3     shape   1.51
#>  4 patch 1     4     shape   1.41
#>  5 patch 1     5     shape   1.13
#>  6 patch 1     6     shape   1.13
#>  7 patch 1     7     shape   1.13
#>  8 patch 1     8     shape   1.15
#>  9 patch 1     9     shape   1.13
#> 10 patch 1     10    shape   1.13
#> # ℹ 30 more rows

## Number of patches
vm_c_np(vector_patches, class_col = "class")
#> # A tibble: 3 × 5
#>   level class id    metric value
#>   <chr> <chr> <chr> <chr>  <int>
#> 1 class 1     <NA>  np        19
#> 2 class 2     <NA>  np        14
#> 3 class 3     <NA>  np         7

## Mean squareness
vm_l_square_mn(vector_patches)
#> # A tibble: 1 × 5
#>   level     class id    metric value
#>   <chr>     <chr> <chr> <chr>  <dbl>
#> 1 landscape <NA>  <NA>  sq_mn  0.845

Another utility function is get_axes() which calculates the length of the major and minor axes of the shape. It is used to calculate the elongation metric in vm_p_elong() but since length of axes might be useful information itself, get_axes() was exported as a separate function.

get_axes(vector_patches, class_col = "class")
#> # A tibble: 40 × 6
#>    level class id    metric    major minor
#>    <chr> <chr> <chr> <chr>     <dbl> <dbl>
#>  1 patch 1     1     main_axes 10.8   5.28
#>  2 patch 1     2     main_axes  9.64  7.84
#>  3 patch 1     3     main_axes  8.38  5.16
#>  4 patch 1     4     main_axes  3.6   2.22
#>  5 patch 1     5     main_axes  1.42  1.42
#>  6 patch 1     6     main_axes  1.42  1.42
#>  7 patch 1     7     main_axes  1.42  1.42
#>  8 patch 1     8     main_axes  4.24  2.82
#>  9 patch 1     9     main_axes  1.42  1.42
#> 10 patch 1     10    main_axes  1.42  1.42
#> # ℹ 30 more rows

Contributing

This is an experimental version of the package, so any feedback and contributions in the form of pull requests are welcome.

vectormetrics's People

Contributors

tomekmatuszek avatar nowosad avatar marcosci avatar tomaszmatuszekiq avatar

Stargazers

 avatar Lucas Johnson avatar Lambda Moses avatar Justin Millar avatar Michael Mahoney avatar Jakub.Miszczyszyn avatar Michael Koohafkan avatar Josh Erickson avatar Alex avatar Lorena Abad Crespo avatar Andrew Gene Brown avatar  avatar  avatar  avatar

Watchers

 avatar  avatar Antony Barja  avatar Maximilian Hesselbarth avatar

vectormetrics's Issues

To do list before package publication

List of things needed to finish before publication of the package:

  • write more unit tests covering edge cases
  • move some higher-level functions back to /R directory
  • review function names to make them possibly readable and unified
  • check documentation and examples for all functions to detect bugs
  • create pull request from develop branch to master
  • create README file to describe package functionalities
  • review all warnings and notes raised during R CMD Check
  • create GitHub Action that will run unit tests and deploys package after every push/PR on master
  • edit result tibbles to have class and patch column as character type
  • add possibility to provide patch_id column to the functions

@Nowosad is there anything more that I should do before the publication?

JOSS

I just discussed that with Max, do we want to submit vectormetrics after it s ready to JOSS?

Data types

... do we want to use to support just sf, or also sp?
Do we want to dispatch methods or just have functions?

Change of result tibble structure

Right now, both class and patch columns in a result tibble object are integers:
obraz

Class value is generated by converting class column (passed by a user) to a factor, and then converting to integer. This approach makes impossible to join result tibble to original data if, for example, class column is a character type. Simmilar problem occurs for a patch value - it is generated as integers from 1 to [number of patches], so it is impossible to assign values of the metric to the original objects.
I think that this situation is not optimal, because it hugely decreases number of use cases to which this package can be applied.

My proposition:

  1. Class value in a result tibble should be a factor - then, user can pass any column type as a class and it would be converted to factor inside the function. Thanks to that, column value in a result tibble will always be the same type, but at the same time it will preserve original information about the class and will enable joining results back to the source data.
  2. Each function should take the third argument named patch_id - it would be a name of ID column in source data. Thanks to that, these IDs can be passed to the results tibble to enable user to join results to the original patches. We can make this argument optional and generate patch IDs from 1 to [number of patches] if user does not provide column for that.
  3. Patch column should be a character - regardless of the input type of a patch ID, it should be always converted to a character in order to handle different ID types such as integer or factor while preserving the rule that all result tibbles have the same set of columns and types.

Structure of result tibble after these changes should look like this:
obraz

Is it correct approach or should I modify it?

Joseph

I invited Joseph (@jsta), as he was giving us feedback on landscapemetrics and had similar plans for a package :-) Just that no one is wondering.

Testing datasets

What kind of datasets could be useful for testing purposes? Am I missing something here?

  1. Simple landscape in a projected CRS
  2. Simple landscape in a geographical CRS
  3. Simple landscape without CRS
  4. Simple landscape in a projected CRS with missing values and missing geometries
  5. Complex landscape in a projected CRS

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.