Skip to contents

Hexsticker R Package for calculating distance-dependent or point cloud-based individual tree competition indices

This R package is designed for the quantitative analysis of individual tree competition within forest ecosystems. It accepts inputs such as LiDAR point clouds (as tabular data with x, y and z coordinates, .las/.laz files or .ply files) of forest plots and individual target trees, or inventory tables (including tree ID, x and y coordinates, diameter and/or tree height or other size parameters as crown projected area). Through the use of various competition indices, it enables the assessment and measurement of competition between trees, providing valuable insights for forest ecology, inventories, and forest management strategies. This package facilitates a systematic approach to understanding interactions and resource competition among trees and enables informed decision making in forest management.

Installation

You can install the stable version (main branch) as well as the current development version of TreeCompR (development branch: more up-to-date, but potentially unstable) from GitHub with:

# install.packages("devtools")

# get stable version
devtools::install_github("juliarieder/TreeCompR")

# get development branch 
devtools::install_github("juliarieder/TreeCompR", ref = "development")

Overview

TreeCompR can read point clouds or inventory tables and quantify tree competition in different ways:

  • Functions for point-cloud based methods
    • compete_pc() quantifies tree competition from point clouds using the cone or cylinder method (see Metz et al. 2013; Seidel et al. 2015)
    • read_pc() reads 3D point clouds from .las/.laz files, .ply files and text-only file formats such as .txt or .csv, and converts LAS objects and data.frames to a TreeCompR compatible format
    • tree_pos() computes the base position and height of target tree point clouds
  • Functions for inventory-based methods
    • compete_inv() quantifies size- and distance-dependent competition using inventory data based on a series of published indices
    • read_inv() reads and validates inventory tables from data.frames, or reads tabular data directly from text-only file sources such as .txt or .csv
    • define_target() can be used to define for which trees within a plot the competition should be quantified in compete_inv()
    • plot_target() check and validate the tree position(s) and the surrounding trees after defining them with define_target()

Methodology of the point cloud-based approach

LiDAR point clouds can be used directly to quantify the competition exerted by neighboring trees on the target tree. For this purpose, the target tree for which the competition is to be determined should be segmented beforehand. Since it is crucial whether a part of the point cloud is classified as “competing” or as part of the target tree itself, a manual segmentation (e.g. in CloudCompare) is recommended as it tends to be much more accurate. Read more about the pre-processing in our tutorial for the point-cloud-based approach.

Methods Workflow

Examples

Point-cloud based tree competition metrics

With compete_pc(), it is easy to quantify the competition with compete_pc() for one target tree, in this example using the cone method (which counts the amount of voxels belonging to competitor trees situated in a cone opening at 60 % of the target tree’s height in an angle of 60 degrees):

library(TreeCompR)
## insert path to point cloud of the forest plot and to the target tree 
compete_pc(forest_source  = "data/neighborhood.las", 
           tree_source    = "data/tree.las", 
           comp_method    = "cone",
           h_cone         = 0.6,
           print_progress = "none") # suppress messages
#> -------------------------------------------------------------------
#> 'compete_pc' class point-cloud based competition indices for 'tree'
#> -------------------------------------------------------------------
#>    target height_target center_position CI_cone h_cone
#>    <char>         <num>          <char>   <int>  <num>
#> 1:   tree          22.8    crown center   15330    0.6

Equivalently, the cylinder method can be used to count the amount of voxels belonging to competitor trees within a cylinder around the target tree with 5 m radius.

## or the cylinder method with radius 5 m
compete_pc(forest_source  = "data/neighborhood.txt", 
           tree_source    = "data/tree.txt", 
           comp_method    = "cylinder",
           cyl_r          = 5,
           print_progress = "none") # suppress messages
#> -------------------------------------------------------------------
#> 'compete_pc' class point-cloud based competition indices for 'tree'
#> -------------------------------------------------------------------
#>    target height_target center_position CI_cyl cyl_r
#>    <char>         <num>          <char>  <int> <num>
#> 1:   tree          22.8    crown center 100512     5

While these examples use the default settings of compete_pc(), the function is highly customizable and able to deal with a large number of different file formats and object types, the majority of which are identified and read automatically. In cases where this is not possible due to non-standard file structures, point clouds can be loaded and pre-processed outside of compete_pc() using read_pc() with custom settings or other functions and then passed on to compete_pc(). More information about these functions an be found in the point cloud tutorial.

Size- and distance-dependent tree competition metrics

Analogously, distance-dependent competition indices can be quantified using compete_inv(), which can read any text file with spatial positions of trees and measures of their size (conventionally, diameter at breast height or tree height).

As it is usually not advisable to compute competition indices for all trees in a plot because there will be strong edge effects when the sample of trees does not comprise the entire forest stand, for compete_inv() it is necessary to explicitly specify target trees. In cases where these are not a priori defined by the design of the study, it is possible to automatically identify target trees using the define_target() function.

In the following example, the inventory is first read with read_inv(), and then target trees are identified with define_target(). Again, read_inv() is highly customizable, and allows a large amount of different input formats and also manual identification of the names of the important variables (x and y coordinates and tree size).

## read forest inventory file from source
plot <- read_inv("../tests/testthat/testdata/inventory.csv", verbose = FALSE)
## define target trees
targets <- define_target(plot, target_source = "buff_edge", radius = 10)

With target_source = "buff_edge", target trees are defined as the trees who are in a distance of more than one search radius (in this case, 10 m) from the border of the forest stand (which is approximated by a concave hull). There are many other possible settings for target_source, such as specifying target trees by their IDs, by logical subsetting, or as a separate set of coordinates. It is also possible to define all trees as target trees, but unless your dataset contains all trees in the forest this is almost never a good idea due to the obvious edge effects.

It is possible to plot the selection of target trees and the surrounding neighborhood for visual inspection using plot_target():

## plot the positions of the target trees and trees at the border
plot_target(targets)

plot_trees

In this example, the neighborhood was already chosen to only contain a single tree within a 10 m buffer from the border, so in consequence, only a single tree was identified as a potential target tree.

As the target_inv object that results from a call to define_target() contains the information about all trees in the plot as well as their status as target or neighbor tree, it can directly be fed to compete_inv() to calculate the competition indices for our one target tree without having to specify target trees explicitly:

## get competition indices for the selected target trees
compete_inv(inv_source = targets,
            radius = 10, 
            method = "all_methods")
#> ------------------------------------------------------------
#> 'compete_inv' class distance-based competition index dataset
#> No. of target trees: 1       Source inventory size: 48 trees
#> Target source: 'buff_edge' (10 m)        Search radius: 10 m
#> ------------------------------------------------------------
#>        id     x      y   dbh CI_Hegyi CI_RK1 CI_RK2
#>    <char> <num>  <num> <num>    <num>  <num>  <num>
#> 1:     48 0.102 -0.494 0.244    4.388  1.068  1.581

Choosing method = "all_methods" computes all available metrics for the chosen data source. As the dataset only contains diameters, but no tree heights, in this case it is the Hegyi index as well as the RK1 and RK2 indices (see documentation of compete_inv() and our paper for details). For more examples on how to customize compete_inv(), have a look at our tutorial for the inventory-based approach.