From 47ba92ebfd06bd2b0a7734dad501c476ada7864f Mon Sep 17 00:00:00 2001 From: Jakob Date: Tue, 23 Jan 2024 08:28:17 +0100 Subject: [PATCH 1/6] Calculate the density of each patch --- NAMESPACE | 2 ++ R/calculate_patch_density.R | 47 ++++++++++++++++++++++++++++++ man/lfa_calculate_patch_density.Rd | 37 +++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 R/calculate_patch_density.R create mode 100644 man/lfa_calculate_patch_density.Rd diff --git a/NAMESPACE b/NAMESPACE index 94267db..10b9bcb 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,6 +4,7 @@ export(get_retile_dir) export(get_tile_dir) export(get_tiles_path) export(is_tile_existing) +export(lfa_calculate_patch_density) export(lfa_capitalize_first_char) export(lfa_check_flag) export(lfa_combine_sf_obj) @@ -12,6 +13,7 @@ export(lfa_count_returns_all_areas) export(lfa_count_returns_per_tree) export(lfa_create_boxplot) export(lfa_create_density_plots) +export(lfa_create_grouped_bar_plot) export(lfa_create_neighbor_mean_curves) export(lfa_create_plot_per_area) export(lfa_create_stacked_distributions_plot) diff --git a/R/calculate_patch_density.R b/R/calculate_patch_density.R new file mode 100644 index 0000000..0bc6fa0 --- /dev/null +++ b/R/calculate_patch_density.R @@ -0,0 +1,47 @@ +#' Calculate patch density for specified areas based on detection data +#' +#' This function calculates patch density for specified areas using detection data. +#' It reads the spatial polygons from a shapefile, computes the area size for each patch, +#' counts the number of detections in each patch, and calculates the patch density. +#' +#' @param areas_location The file path to a shapefile containing spatial polygons +#' representing the areas for which patch density needs to be calculated. +#' Default is "research_areas.shp". +#' @param detections A data frame containing detection information, where each row represents +#' a detection and includes the 'area' column specifying the corresponding area. +#' Default is obtained using lfa_get_detections(). +#' @return A data frame with patch density information for each specified area. +#' Columns include 'name' (area name), 'geometry' (polygon geometry), 'area_size' (patch area size), +#' 'detections' (number of detections in the patch), and 'density' (computed patch density). +#' +#' @examples +#' # Assuming you have a shapefile 'your_research_areas.shp' and detection data +#' # from lfa_get_detections() +#' density_data <- lfa_calculate_patch_density(areas_location = "your_research_areas.shp") +#' print(density_data) +#' +#' @export +lfa_calculate_patch_density <- function(areas_location = "research_areas.shp", + detections = lfa::lfa_get_detections()) { + # Set S2 usage to FALSE + sf::sf_use_s2(FALSE) + + # Read spatial polygons from the specified shapefile + patch_data <- sf::st_read(areas_location) + + # Compute the area size for each patch + patch_data$area_size <- sf::st_area(patch_data) + + # Initialize 'detections' column with NA + patch_data$detections <- NA + + # Count the number of detections in each patch + for (i in 1:nrow(patch_data)) { + patch_data[i, "detections"] <- nrow(detections[detections$area == patch_data[i, "name"], ]) + } + + # Calculate patch density + patch_data$density <- patch_data$detections / patch_data$area_size + + return(patch_data) +} diff --git a/man/lfa_calculate_patch_density.Rd b/man/lfa_calculate_patch_density.Rd new file mode 100644 index 0000000..22dbdbe --- /dev/null +++ b/man/lfa_calculate_patch_density.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/calculate_patch_density.R +\name{lfa_calculate_patch_density} +\alias{lfa_calculate_patch_density} +\title{Calculate patch density for specified areas based on detection data} +\usage{ +lfa_calculate_patch_density( + areas_location = "research_areas.shp", + detections = lfa::lfa_get_detections() +) +} +\arguments{ +\item{areas_location}{The file path to a shapefile containing spatial polygons +representing the areas for which patch density needs to be calculated. +Default is "research_areas.shp".} + +\item{detections}{A data frame containing detection information, where each row represents +a detection and includes the 'area' column specifying the corresponding area. +Default is obtained using lfa_get_detections().} +} +\value{ +A data frame with patch density information for each specified area. +Columns include 'name' (area name), 'geometry' (polygon geometry), 'area_size' (patch area size), +'detections' (number of detections in the patch), and 'density' (computed patch density). +} +\description{ +This function calculates patch density for specified areas using detection data. +It reads the spatial polygons from a shapefile, computes the area size for each patch, +counts the number of detections in each patch, and calculates the patch density. +} +\examples{ +# Assuming you have a shapefile 'your_research_areas.shp' and detection data +# from lfa_get_detections() +density_data <- lfa_calculate_patch_density(areas_location = "your_research_areas.shp") +print(density_data) + +} From 77573aa8ac08dff0dd38a4cd2ef239a8563948ae Mon Sep 17 00:00:00 2001 From: Jakob Date: Tue, 23 Jan 2024 08:28:39 +0100 Subject: [PATCH 2/6] Visualize data as bar plot --- R/create_bar_plot.R | 38 ++++++++++++++++++++++++++++++ man/lfa_create_grouped_bar_plot.Rd | 30 +++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 R/create_bar_plot.R create mode 100644 man/lfa_create_grouped_bar_plot.Rd diff --git a/R/create_bar_plot.R b/R/create_bar_plot.R new file mode 100644 index 0000000..c4263b9 --- /dev/null +++ b/R/create_bar_plot.R @@ -0,0 +1,38 @@ +#' Create a barplot using ggplot2 +#' +#' This function generates a barplot using ggplot2 based on the specified data frame columns. +#' The barplot displays the values from the specified column, grouped by another column. +#' The grouping can be further differentiated by color if desired. +#' +#' @param df A data frame containing the relevant columns for the barplot. +#' @param value_column The column containing the values to be plotted. +#' @param label_column The column used for labeling the bars on the x-axis. Default is "name". +#' @param grouping_column The column used for grouping the bars. Default is "species". +#' @return A ggplot2 barplot. +#' +#' +#' @examples +#' # Assuming you have a data frame 'your_data_frame' with columns "name", "species", and "value" +#' lfa_create_barplot(your_data_frame, value_column = "value", label_column = "name", grouping_column = "species") +#' +#'@export +lfa_create_grouped_bar_plot <- function(data, grouping_var, value_col, label_col) { + +if (!(grouping_var %in% colnames(data) && value_col %in% colnames(data) && label_col %in% colnames(data))) { + stop("Columns not found in the data.frame.") +} + +# Create a grouped bar plot +plot <- ggplot2::ggplot(data, ggplot2::aes(x = reorder(data[[label_col]], data[[value_col]]), y = data[[value_col]], fill = data[[grouping_var]])) + + ggplot2::geom_bar(stat = "identity", position = "dodge") + + ggplot2::labs(x = "Name of patch", y = "Density", fill = "Specie", title = "Tree density across the different patches, grouped by specie") + + ggplot2::theme_minimal() + + ggplot2::theme(axis.text.x = element_text(angle = 45, hjust = 1)) + +return(plot) +} + +# Example usage: +# Assuming 'my_data' is your data.frame, 'category' is the grouping variable, +# 'value' is the column with values, and 'label' is the column with labels. + diff --git a/man/lfa_create_grouped_bar_plot.Rd b/man/lfa_create_grouped_bar_plot.Rd new file mode 100644 index 0000000..089f059 --- /dev/null +++ b/man/lfa_create_grouped_bar_plot.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/create_bar_plot.R +\name{lfa_create_grouped_bar_plot} +\alias{lfa_create_grouped_bar_plot} +\title{Create a barplot using ggplot2} +\usage{ +lfa_create_grouped_bar_plot(data, grouping_var, value_col, label_col) +} +\arguments{ +\item{df}{A data frame containing the relevant columns for the barplot.} + +\item{value_column}{The column containing the values to be plotted.} + +\item{label_column}{The column used for labeling the bars on the x-axis. Default is "name".} + +\item{grouping_column}{The column used for grouping the bars. Default is "species".} +} +\value{ +A ggplot2 barplot. +} +\description{ +This function generates a barplot using ggplot2 based on the specified data frame columns. +The barplot displays the values from the specified column, grouped by another column. +The grouping can be further differentiated by color if desired. +} +\examples{ +# Assuming you have a data frame 'your_data_frame' with columns "name", "species", and "value" +lfa_create_barplot(your_data_frame, value_column = "value", label_column = "name", grouping_column = "species") + +} From 44058edc634e44033fef881cd75778e34d6566fc Mon Sep 17 00:00:00 2001 From: Jakob Date: Tue, 23 Jan 2024 08:56:15 +0100 Subject: [PATCH 3/6] Small bug fixes --- R/calculate_patch_density.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/calculate_patch_density.R b/R/calculate_patch_density.R index 0bc6fa0..e854a70 100644 --- a/R/calculate_patch_density.R +++ b/R/calculate_patch_density.R @@ -37,7 +37,7 @@ lfa_calculate_patch_density <- function(areas_location = "research_areas.shp", # Count the number of detections in each patch for (i in 1:nrow(patch_data)) { - patch_data[i, "detections"] <- nrow(detections[detections$area == patch_data[i, "name"], ]) + patch_data[i, "detections"]$detections <- nrow(detections[detections$area == patch_data[i, "name"]$name, ]) } # Calculate patch density From ca4ac6f2ab5590218de23e46a7c34f16356831a0 Mon Sep 17 00:00:00 2001 From: Jakob Date: Tue, 23 Jan 2024 08:56:42 +0100 Subject: [PATCH 4/6] Add the report --- results/report.qmd | 15 +-------------- results/results/density.qmd | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 results/results/density.qmd diff --git a/results/report.qmd b/results/report.qmd index d267d43..1bdbca7 100644 --- a/results/report.qmd +++ b/results/report.qmd @@ -42,23 +42,10 @@ This report documents the analysis of forest data for different tree species. {{< include results/researched-areas.qmd >}} {{< include results/z-distribution.qmd >}} {{< include results/number_of_returns.qmd >}} +{{< include results/density.qmd >}} -|specie |area | density (1/m²)| -|:------|:-------------------|---------:| -|beech |bielefeld_brackwede | 0.0089399| -|beech |billerbeck | 0.0093175| -|beech |wuelfenrath | 0.0079259| -|oak |hamm | 0.0090610| -|oak |muenster | 0.0077384| -|oak |rinkerode | 0.0082641| -|pine |greffen | 0.0103807| -|pine |mesum | 0.0124200| -|pine |telgte | 0.0122860| -|spruce |brilon | 0.0158030| -|spruce |oberhundem | 0.0162678| -|spruce |osterwald | 0.0129892| diff --git a/results/results/density.qmd b/results/results/density.qmd new file mode 100644 index 0000000..b5abdf0 --- /dev/null +++ b/results/results/density.qmd @@ -0,0 +1,17 @@ +## Density of forest patches +Examining densities provides valuable insights into identifying the dominant species within patches. Spruce stands out as the densest species, surpassing all other patches. Following closely in density is Pine, as depicted in Figure 1 (@fig-density-bar). + +Beech and Oak exhibit similar density levels, with Beech consistently denser across all patches. When comparing the highest density patches for each species, Beech consistently outpaces Oak. While Oak is slightly less dense overall ($8.354499 \times 10^{-3} \frac{1}{m^2}$) than Beech ($8.727781 \times 10^{-3} \frac{1}{m^2}$), the distinction in density remains noticeable. + + +```{r} +#| code-fold: true +#| warning: false +#| results: hide +#| fig-cap: Barplot of the densitys of all patches (#detected trees/area of patch). Colorized by the dominant tree species of each patch. +#| label: fig-density-bar +library(units) +lfa::lfa_calculate_patch_density() |> + lfa::lfa_create_grouped_bar_plot(grouping_var = "species", value_col = "density", label_col = "name") +``` +In summary, our findings indicate that the density of each patch proves highly effective in distinguishing dominant species. Furthermore, the differentiation between conifers (Pine and Spruce) and deciduous trees (Beech and Oak) based on density aligns with patterns observed in the number of return points per detected tree. While distinguishing within conifers is straightforward, discerning between the deciduous tree species Beech and Oak, is possible but poses a moderate challenge. From 301d52b1ca008108f1d8d3573f3ab2b187ca34e5 Mon Sep 17 00:00:00 2001 From: Jakob Date: Tue, 23 Jan 2024 08:57:03 +0100 Subject: [PATCH 5/6] Add docs to qmd --- results/appendix/package-docs/docs.qmd | 185 +++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/results/appendix/package-docs/docs.qmd b/results/appendix/package-docs/docs.qmd index 1f7babe..3d8d0ac 100644 --- a/results/appendix/package-docs/docs.qmd +++ b/results/appendix/package-docs/docs.qmd @@ -1,3 +1,53 @@ +### `lfa_calculate_patch_density` + +Calculate patch density for specified areas based on detection data + + +#### Arguments + +Argument |Description +------------- |---------------- +`areas_location` | The file path to a shapefile containing spatial polygons representing the areas for which patch density needs to be calculated. Default is "research_areas.shp". +`detections` | A data frame containing detection information, where each row represents a detection and includes the 'area' column specifying the corresponding area. Default is obtained using lfa_get_detections(). + + +#### Description + +This function calculates patch density for specified areas using detection data. + It reads the spatial polygons from a shapefile, computes the area size for each patch, + counts the number of detections in each patch, and calculates the patch density. + + +#### Value + +A data frame with patch density information for each specified area. + Columns include 'name' (area name), 'geometry' (polygon geometry), 'area_size' (patch area size), + 'detections' (number of detections in the patch), and 'density' (computed patch density). + + +#### Examples + +```{r} +#| eval: false +# Assuming you have a shapefile 'your_research_areas.shp' and detection data +# from lfa_get_detections() +density_data <- lfa_calculate_patch_density(areas_location = "your_research_areas.shp") +print(density_data) +``` + + +#### Usage + +```{r} +#| eval: false +lfa_calculate_patch_density( + areas_location = "research_areas.shp", + detections = lfa::lfa_get_detections() +) +``` + + + ### `lfa_capitalize_first_char` Capitalize First Character of a String @@ -393,6 +443,141 @@ lfa_create_density_plots( +### `lfa_create_grouped_bar_plot` + +Create a barplot using ggplot2 + + +#### Arguments + +Argument |Description +------------- |---------------- +`df` | A data frame containing the relevant columns for the barplot. +`value_column` | The column containing the values to be plotted. +`label_column` | The column used for labeling the bars on the x-axis. Default is "name". +`grouping_column` | The column used for grouping the bars. Default is "species". + + +#### Description + +This function generates a barplot using ggplot2 based on the specified data frame columns. + The barplot displays the values from the specified column, grouped by another column. + The grouping can be further differentiated by color if desired. + + +#### Value + +A ggplot2 barplot. + + +#### Examples + +```{r} +#| eval: false +# Assuming you have a data frame 'your_data_frame' with columns "name", "species", and "value" +lfa_create_barplot(your_data_frame, value_column = "value", label_column = "name", grouping_column = "species") +``` + + +#### Usage + +```{r} +#| eval: false +lfa_create_grouped_bar_plot(data, grouping_var, value_col, label_col) +``` + + + +### `lfa_create_neighbor_mean_curves` + +Create neighbor mean curves for specified areas + + +#### Arguments + +Argument |Description +------------- |---------------- +`neighbors` | A data frame containing information about neighbors, where each column represents a specific neighbor, and each row corresponds to an area. +`use_avg` | Logical. If TRUE, the function computes average curves across all neighbors. If FALSE, it computes curves for individual neighbors. + + +#### Description + +This function generates mean curves for a specified set of areas based on neighbor data. + The user can choose to compute mean curves for individual neighbors or averages across neighbors. + + +#### Value + +A data frame with mean curves for each specified area. + Columns represent areas, and rows represent index values. + + +#### Examples + +```{r} +#| eval: false +# Assuming you have a data frame 'your_neighbors_data' with neighbor information +mean_curves <- lfa_create_neighbor_mean_curves(your_neighbors_data, use_avg = TRUE) +print(mean_curves) +``` + + +#### Usage + +```{r} +#| eval: false +lfa_create_neighbor_mean_curves(neighbors, use_avg = FALSE) +``` + + + +### `lfa_create_plot_per_area` + +Create a line plot per area with one color per specie + + +#### Arguments + +Argument |Description +------------- |---------------- +`data` | A data frame with numeric columns and a column named 'specie' for species information. + + +#### Description + +This function takes a data frame containing numeric columns and creates a line plot + using ggplot2. Each line in the plot represents a different area, with one color per specie. + + +#### Value + +A ggplot2 line plot. + + +#### Examples + +```{r} +#| eval: false +data <- data.frame( +specie = rep(c("Species1", "Species2", "Species3"), each = 10), +column1 = rnorm(30), +column2 = rnorm(30), +column3 = rnorm(30) +) +lfa_create_plot_per_area(data) +``` + + +#### Usage + +```{r} +#| eval: false +lfa_create_plot_per_area(data) +``` + + + ### `lfa_create_stacked_distributions_plot` Create a stacked distribution plot for tree detections, visualizing the distribution From fb03516f591cc064378f16733df963c2c74b35d7 Mon Sep 17 00:00:00 2001 From: Jakob Date: Tue, 23 Jan 2024 08:57:16 +0100 Subject: [PATCH 6/6] Update cache --- .../_freeze/report/execute-results/html.json | 4 ++-- .../report/figure-html/fig-density-bar-1.png | Bin 0 -> 61687 bytes 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 results/_freeze/report/figure-html/fig-density-bar-1.png diff --git a/results/_freeze/report/execute-results/html.json b/results/_freeze/report/execute-results/html.json index b780f76..d5293c8 100644 --- a/results/_freeze/report/execute-results/html.json +++ b/results/_freeze/report/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "9f8331cdcca8df29add1ef17b1269fd1", + "hash": "c9e59ae14aeb7afdb94886698bbd9f2f", "result": { - "markdown": "---\ntitle: \"Forest Data Analysis Report\"\noutput:\n pdf_document:\n latex_engine: xelatex\ntoc: true\ntoc-depth: 2\ntoc-title: Contents\nnumber-sections: true\nnumber-depth: 3\ndate: today\nauthor:\n - name: Jakob Danel\n email: jakob.danel@uni-muenster.de\n url: https://github.com/jakobdanel\n affiliations:\n - name: Universität Münster\n city: Münster\n country: Germany\n - name: Federick Bruch\n email: f_bruc03@uni-muenster.de\n url: https://www.uni-muenster.de/Geoinformatics/institute/staff/index.php/351/Frederick_Bruch\n affiliations:\n - name: Universität Münster\n city: Münster\n country: Germany\nbibliography: references.bib\nexecute-dir: .. \nprefer-html: true\n---\n\n\n# Introduction\n\nThis report documents the analysis of forest data for different tree species.\n\n# Methods\n\n## Data acquisition\n\nOur primary objective is to identify patches where one tree species exhibits a high level of dominance, striving to capture monocultural stands within the diverse forests of Nordrhein-Westfalia (NRW). Recognizing the practical challenges of finding true monocultures, we aim to identify patches where one species is highly dominant, enabling meaningful comparisons across different species.\n\nThe study is framed within the NRW region due to the availability of an easily accessible dataset. Our focus includes four prominent tree species in NRW: oak, beech, spruce, and pine, representing the most prevalent species in the region. To ensure the validity of our findings, we derive three patches for each species, thereby confirming that observed variables are characteristic of a particular species rather than a specific patch. Each patch is carefully selected to encompass an area of approximately 50-100 hectares and contain between 5,000 and 10,000 trees. Striking a balance between relevance and manageability, these patches avoid excessive size to enhance the likelihood of capturing varied species mixes and ensure compatibility with local hardware.\n\nSpecific Goals:\n\n1. Retrieve patches with highly dominant tree species.\n2. Minimize or eliminate the presence of human-made structures within the selected patches.\n\nTo achieve our goals, we utilized the waldmonitor dataset [@welle2014] and the map provided by [@Blickensdoerfer2022], both indicating dominant tree species in NRW. We identified patches of feasible size where both sources predicted the presence of a specific species. Further validation involved examining sentinel images of these forest regions to assess the evenness of structures, leaf color distribution, and the absence of significant human-made structures such as roads or buildings. The subsequent preprocessing steps, detailed in the following subsection, involved refining our selected patches and deriving relevant variables, such as tree distribution and density, to ensure that the chosen areas align with the desired research domains.\n\n## Preprocessing\n::: {.cell}\n\n:::\n\n\nIn this research study, the management and processing of a large dataset are crucial considerations. The dataset's substantial size necessitates careful maintenance to ensure efficient handling. Furthermore, the data should be easily processable and editable to facilitate necessary corrections and precalculations within the context of our research objectives. To achieve our goals, we have implemented a framework that automatically derives data based on a shapefile, delineating areas of interest. The processed data and results of precalculations are stored in a straightforward manner to enhance accessibility. Additionally, we have designed functions that establish a user-friendly interface, enabling the execution of algorithms on subsets of the data, such as distinct species. These interfaces are not only directly callable by users but can also be integrated into other functions to automate processes. The overarching aim is to streamline the entire preprocessing workflow using a single script, leveraging only the shapefile as a basis. This subsection details the accomplishments of our R-package in realizing these goals, outlining the preprocessing steps undertaken and justifying their necessity in the context of our research.\n\nThe data are stored in a data subdirectory of the root directory in the format `species/location-name/tile-name`. To automate the matching of areas of interest with the catalog from the Land NRW[^1], we utilize the intersecting tool developed by Heisig[^2]. This tool, allows for the automatic retrieval and placement of data downloaded from the Land NRW catalog. To enhance data accessibility, we have devised an object that incorporates species, location name, and tile name (the NRW internal identifier) for each area This object facilitates the specification of the area to be processed. Additionally, we have defined an initialization function that downloads all tiles, returning a list of tile location objects for subsequent processing. A pivotal component of the package's preprocessing functionality is the map function, which iterates over a list of tile locations (effectively the entire dataset) and accepts a processing function as an argument. The subsequent paragraph outlines the specific preprocessing steps employed, all of which are implemented within the mapping function.\n\nTo facilitate memory-handling capabilities, each of the tiles, where one area can span multiple tiles, has been split into manageable chunks. We employed a 50x50m size for each tile, resulting in the division of original 1km x 1km files into 400 tiles. These tiles are stored in our directory structure, with each tile housed in a directory named after its tile name and assigned an id as the filename. Implementation-wise, the `lidr::catalog_retile` function was instrumental in achieving this segmentation. The resulting smaller chunks allow for efficient iteration during subsequent preprocessing steps.\n\nThe next phase involves reducing our data to the actual size by intersecting the tiles with the defined area of interest. Using the `lidR::merge_spatial` function, we intersect the area derived from the shapefile, removing all point cloud items outside this region. Due to our tile-wise approach, empty tiles may arise, and in such cases, those tiles are simply deleted.\n\nFollowing the size reduction to our dataset, the next step involves correcting the `z` values. The `z` values in the data are originally relative to the ellipsoid used for referencing, but we require them to be relative to the ground. To achieve this, we utilize the `lidR::tin` function, which extrapolates a convex hull between all ground points (classified by the data provider) and calculates the z value based on this structure.\n\nSubsequently, we aim to perform segmentation for each distinct tree, marking each item of the point cloud with a tree ID. We employ the algorithm described by @li2012, using parameters `li2012(dt1 = 2, dt2 = 3, R = 2, Zu = 10, hmin = 5, speed_up = 12)`. The meanings of these parameters are elucidated in Li et al.'s work [@li2012].\n\nFinally, the last preprocessing step involves individual tree detection, seeking a single `POINT` object for each tree. The `lidR::lmf` function, an implementation of the tree data using a local maximum approach, is utilized for this purpose [@popescu2004]. The results are stored in GeoPackage files within our data structure.\n\nSee @sec-appendix-preprocessing for the implementation of the preprocessing.\n\n[^1]: https://www.opengeodata.nrw.de/produkte/geobasis/hm/3dm_l_las/3dm_l_las/, last visited 7th Dec 2023\n[^2]: https://github.com/joheisig/GEDIcalibratoR, last visited 7th Dec 2023\n\n## Analysis of different distributions\n\nAnalysis of data distributions is a critical aspect of our research, with a focus on comparing two or more distributions. Our objective extends beyond evaluating the disparities between species; we also aim to assess differences within a species. To gain a comprehensive understanding of the data, we employ various visualization techniques, including histograms, density functions, and box plots.\n\nIn tandem with visualizations, descriptive statistics, such as means, standard errors, and quantiles, are leveraged to provide key insights into the central tendency and variability of the data.\n\nFor a more quantitative analysis of distribution dissimilarity, statistical tests are employed. The Kullback-Leibler (KL) difference serves as a measure to compare the similarity of a set of distributions. This involves converting distributions into their density functions, with the standard error serving as the bandwidth. The KL difference is calculated for each pair of distributions, as it is asymmetric. For the two distributions the KL difference is defined as following [@kullback1951kullback]:\n\n$$\nD_{KL}(P \\, \\| \\, Q) = \\sum_i P(i) \\log\\left(\\frac{P(i)}{Q(i)}\\right)\n$$\n\nTo obtain a symmetric score, the Jensen-Shannon Divergence (JSD) is utilized [@grosse2002analysis], expressed by the formula:\n\n$$\nJS(P || Q) = \\frac{1}{2} * KL(P || M) + \\frac{1}{2} * KL(Q || M)\n$$\nHere, $M = \\frac{1}{2} * (P + Q)$. The JSD provides a balanced measure of dissimilarity between distributions [@Brownlee2019Calculate]. For comparing the different scores to each other, we will use averages.\n\nAdditionally, the Kolmogorov-Smirnov Test is implemented to assess whether two distributions significantly differ from each other. This statistical test offers a formal evaluation of the dissimilarity between empirical distribution functions.\n\n\n# Results\n::: {.cell}\n\n:::\n\n## Researched areas\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlibrary(ggplot2)\nsf::sf_use_s2(FALSE)\npatches <- sf::read_sf(\"research_areas.shp\") |> sf::st_centroid()\n\nde <- sf::read_sf(\"results/results/states_de/Bundesländer_2017_mit_Einwohnerzahl.shp\") # Source: https://hub.arcgis.com/datasets/esri-de-content::bundesl%C3%A4nder-2017-mit-einwohnerzahl/explore?location=51.099647%2C10.454033%2C7.43\nnrw <- de[5,] |> sf::st_geometry()\n\n\nggplot() + geom_sf(data = nrw) + \n geom_sf(data = patches, mapping = aes(col = species))\n```\n\n::: {.cell-output-display}\n![Locations of the different patches with the dominant species for that patch. The patches centroids are displayed on a basemap describing the borders from NRW.](report_files/figure-html/fig-patches-nrw-1.png){#fig-patches-nrw width=672}\n:::\n:::\nWe draw three patches for each species from different regions (see @tbl-summary-researched-areas). We download the LiDAR data for those patches and runned all preprocessing steps as described. We than checked with certain derived parameters (e.g. tree heights, tree distributions or tree density) that all patches contain valid forest data. In that step we discovered, that in one patch some forest clearance took place in the near past. This patch was removed from the dataset and was replaced with a new one. \n\nIn our research, drawing patches evenly distributed across Nordrhein-Westfalia is inherently constrained by natural factors. Consequently, the patches for oak and pine predominantly originate from the Münsterland region, as illustrated in [@fig-patches-nrw]. For spruce, the patches were derived from Sauerland, reflecting the prevalence of spruce forests in this specific region within NRW, as corroborated by Welle et al. [@welle2014] and Blickensdörfer et al. [@Blickensdoerfer2022]. Beech patches, on the other hand, were generated from diverse locations within NRW. Across all patches, no human-made objects were identified, with the exception of small paths for pedestrians and forestry vehicles.\n\nThe distribution of area and detections is notable for each four species. Beech covers 69,791.9 hectares with a total of 5,954 detections, oak spans 63,232.49 hectares with 5,354 detections, pine extends across 72,862.4 hectares with 8,912 detections, and spruce encompasses 57,940.02 hectares with 8,619 detections. Both the amount of detections and the corresponding area exhibit a relatively uniform distribution across the diverse patches, as summarized in @tbl-summary-researched-areas. \n\nWith the selected dataset described, we intentionally chose three patches for each four species that exhibit a practical and usable size for our research objectives. These carefully chosen patches align with the conditions essential for our study, providing comprehensive and representative data for in-depth analysis and meaningful insights into the characteristics of each tree species within the specified areas.\n\n\n::: {#tbl-summary-researched-areas .cell tbl-cap='Summary of researched patches grouped by species, with their location, area and the amount of detected trees.'}\n\n```{.r .cell-code code-fold=\"true\"}\nshp <- sf::read_sf(\"research_areas.shp\")\ntable <- lfa::lfa_get_all_areas()\n\nsf::sf_use_s2(FALSE)\nfor (row in 1:nrow(table)) {\n area <-\n dplyr::filter(shp, shp$species == table[row, \"specie\"] &\n shp$name == table[row, \"area\"])\n area_size <- area |> sf::st_area()\n point <- area |> sf::st_centroid() |> sf::st_coordinates()\n table[row,\"point\"] <- paste0(\"(\",round(point[1], digits = 4),\", \",round(point[2],digits = 4),\")\")\n \n table[row, \"area_size\"] = round(area_size,digits = 2) #paste0(round(area_size,digits = 2), \" m²\")\n \n amount_det <- nrow(lfa::lfa_get_detection_area(table[row, \"specie\"], table[row, \"area\"]))\n if(is.null(amount_det)){\n cat(nrow(lfa::lfa_get_detection_area(table[row, \"specie\"], table[row, \"area\"])),table[row, \"specie\"],table[row, \"area\"])\n }\n table[row, \"amount_detections\"] = amount_det\n \n # table[row, \"specie\"] <- lfa::lfa_capitalize_first_char(table[row,\"specie\"])\n table[row, \"area\"] <- lfa::lfa_capitalize_first_char(table[row,\"area\"])\n }\ntable$area <- gsub(\"_\", \" \", table$area)\ntable$area <- gsub(\"ue\", \"ü\", table$area)\ntable = table[,!names(table) %in% c(\"specie\")]\n\nknitr::kable(table, \"html\", col.names = c(\"Patch Name\",\"Location\",\"Area size (m²)\",\"Amount tree detections\" ), caption = NULL, digits = 2, escape = TRUE) |>\n kableExtra::kable_styling(\n bootstrap_options = c(\"striped\", \"hold_position\", \"bordered\",\"responsive\"),\n stripe_index = c(1:3,7:9),\n full_width = FALSE\n ) |>\n kableExtra::pack_rows(\"Beech\", 1, 3) |>\n kableExtra::pack_rows(\"Oak\", 4, 6) |>\n kableExtra::pack_rows(\"Pine\", 7, 9) |>\n kableExtra::pack_rows(\"Spruce\", 10, 12) |>\n kableExtra::column_spec(1, bold = TRUE)\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n \n \n \n \n \n \n \n \n\n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Patch Name Location Area size (m²) Amount tree detections
Beech
Bielefeld brackwede (8.5244, 51.9902) 161410.57 1443
Billerbeck (7.3273, 51.9987) 185887.25 1732
Wülfenrath (7.0769, 51.2917) 350621.21 2779
Oak
Hamm (7.8618, 51.6639) 269397.22 2441
Münster (7.6187, 51.9174) 164116.61 1270
Rinkerode (7.6744, 51.8598) 198811.09 1643
Pine
Greffen (8.1697, 51.9913) 49418.81 513
Mesum (7.5403, 52.2573) 405072.85 5031
Telgte (7.7816, 52.0024) 274132.34 3368
Spruce
Brilon (8.5352, 51.4084) 211478.20 3342
Oberhundem (8.1861, 51.0909) 151895.53 2471
Osterwald (8.3721, 51.2151) 216026.43 2806
\n\n`````\n:::\n:::\n\n\n\n\n\n## Distribution of the tree heights\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndetections <- lfa::lfa_get_detections()\n```\n:::\n\nIn this study, we scrutinize the distribution of tree heights, focusing initially on the density distribution to unravel the nuances across various tree species. Notably, our examination reveals distinctive patterns, with Oak and Pine exhibiting significantly steeper peaks in their density curves compared to Beech and Spruce. While all species present unique density curves, a commonality emerges—each curve is characterized by a single peak, except for the intriguing exception observed in Telgte. Taking Beech as an illustrative example, our findings indicate a notable shift in the peak to a considerably higher extent. The varinace in the density curves indicating that an differencation between species only with the help oof tree height values could be difficult.\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_density_plots(detections, value_column = \"Z\", category_column1 = \"area\", category_column2 = \"specie\", title = \"Density of the height distributions\", xlims = c(0,50))\n```\n\n::: {.cell-output-display}\n![Density of the height distribitions of the detectected trees. Splitted by the different researched areas and grouped by the dominant specie in this area.](report_files/figure-html/fig-density-z-1.png){#fig-density-z width=672}\n:::\n:::\n\nTo have a deeper look into the distributions of those `Z`-values we will now also have a look into the boxplots of the height distrubutions in the different areas.\nNoteworthy observations include the presence of outliers beyond the extended range of the Whisker Antennas ($1.5*\\text{IQR}$) in all datasets. Of particular interest is the Rinkerode dataset, which exhibits a higher prevalence of outliers in the upper domain. Anomalies in this dataset are attributed to potential inaccuracies, urging a critical examination of data integrity. A pairwise examination of Oak and Pine species indicates higher mean heights for Oak compared to Pine. This insight underscores the significance of species-specific attributes in shaping overall height distributions. Further exploration into the factors contributing to these mean differences enhances our understanding of the unique characteristics inherent to each species. Contrary to expectations, the spread within a particular species does not exhibit significant divergence from the spread observed between different species. This finding suggests that while species-specific traits play a crucial role in shaping height distributions, certain overarching factors may contribute to shared patterns across diverse tree populations.\n\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_boxplot(detections, value_column = \"Z\", category_column1 = \"area\", category_column2 = \"specie\", title = \"Boxplots of the height distributions\")\n```\n\n::: {.cell-output-display}\n![Boxplots of the height distribitions of the detectected trees. Splitted by the different researched areas and grouped by the dominant specie in this area.](report_files/figure-html/fig-boxplot-z-1.png){#fig-boxplot-z width=672}\n:::\n:::\n\n\n\nOur examination of Kullback-Leibler Divergence (KLD) and Jensen-Shannon Divergence (JSD) metrics reveals low mean values (KLD: 5.252696, JSD: 2.246663) across different species, indicating overall similarity in tree species height distributions. However, within specific species, particularly Pine, higher divergence values (see @tbl-z-values-kld-pine and @tbl-z-values-jsd-pine) suggest significant intraspecific differences.\n\nNotably, the Spruce species consistently demonstrates low divergence values across all tested areas, implying a high level of explainability. This finding highlights tree height as a reliable indicator for detecting Spruce trees, indicating its potential for accurate species identification in diverse forest ecosystems.\n\n## n-nearest Neighbours\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nneighbors <- lfa::lfa_combine_sf_obj(lfa::lfa_get_neighbor_paths(),lfa::lfa_get_all_areas())\n```\n:::\n\n### Overview\nTo initiate our analysis, we first establish a framework for selecting neighbors by examining the distance development with different n, as illustrated in @fig-n-nearest-overview. The curves share a similar design, but the actual values vary. Notably, as n increases, the distance between all patches also increases, indicating a broader spatial context.\n\nConsidering this trend, we extend our investigation beyond the nearest neighbor to include the 100th nearest neighbor. The $\\Delta$distance shows a consistent decrease with each increment in n, reinforcing our decision to limit exploration beyond n of a hundred. Additionally, the constraint is driven by practical considerations, as our sample size occasionally lacks the capacity to explore larger n values, resulting in inaccurate values due to the absence of the true nearest neighbor within the sample area.\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_neighbor_mean_curves(neighbors) |> lfa::lfa_create_plot_per_area()\n```\n\n::: {.cell-output-display}\n![Average Distance to n-nearest neighbor from each patch. For simplicity colored by the dominant specie of each tree.](report_files/figure-html/fig-n-nearest-overview-1.png){#fig-n-nearest-overview width=672}\n:::\n:::\n\n\n### The Nearest Neighbour\nOur initial focus centers on examining the distance to the nearest neighbor for each tree. Notably, the curve representing Spruce exhibits distinct characteristics compared to the three other curves—displaying a steeper profile with less variance, as depicted in @fig-density-1-nearest.\n\nFurther analysis of all patches reveals similar distributions, as evident in the boxplot shown in Figure 2 (@fig-boxplot-1-nearest), where mean and variance demonstrate consistency across patches. However, these graphical statistics present challenges in effectively distinguishing between different tree species based on the distance to the nearest neighbor.\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_density_plots(neighbors,value_column = \"Neighbor_1\",category_column1 = \"area\",category_column2 = \"specie\", title = \"Density plots for the nearest neighbor among species and areas\", xlims = c(0,15))\n```\n\n::: {.cell-output-display}\n![Density plot of the distance to the nearest neighbor distribution across all patches grouped by the dominant species.](report_files/figure-html/fig-density-1-nearest-1.png){#fig-density-1-nearest width=672}\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_boxplot(neighbors,value_column = \"Neighbor_1\",category_column1 = \"area\",category_column2 = \"specie\", title = \"Box plots for the nearest neighbor among species and areas\")\n```\n\n::: {.cell-output-display}\n![Density plot of the distance to the nearest neighbor distribution across all patches grouped by the dominant species.](report_files/figure-html/fig-boxplot-1-nearest-1.png){#fig-boxplot-1-nearest width=672}\n:::\n:::\n\n\n### The 100th nearest Neighbor\nMoving on to the analysis of the 100th nearest neighbor, intriguing patterns emerge. Peaks in the curves display varying heights and positions, with a notable example being the complete shift between Oak and Spruce, as illustrated in @fig-density-100-nearest.\n\nHowever, it is essential to acknowledge the high variance observed between curves within a species, such as Pine or Beech. While this variance could serve as a potential indicator, it comes with the caveat that the sample size must be substantial for reliable conclusions.\n\nExamining boxplots reveals numerous outliers above the boxes, hinting at potential edge effects on the sides of patches. This observation raises concerns about the adequacy of trees in these areas for a more in-depth analysis, posing challenges in deriving accurate insights.\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_density_plots(neighbors,value_column = \"Neighbor_100\",category_column1 = \"area\",category_column2 = \"specie\", title = \"Density plots for the nearest neighbor along species and areas\", xlims = c(35,100))\n```\n\n::: {.cell-output-display}\n![Density plot of the distance to the nearest neighbor distribution across all patches grouped by the dominant species.](report_files/figure-html/fig-density-100-nearest-1.png){#fig-density-100-nearest width=672}\n:::\n:::\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_boxplot(neighbors,value_column = \"Neighbor_100\",category_column1 = \"area\",category_column2 = \"specie\", title = \"Box plots for the nearest neighbor along species and areas\")\n```\n\n::: {.cell-output-display}\n![Density plot of the distance to the nearest neighbor distribution across all patches grouped by the dominant species.](report_files/figure-html/fig-boxplot-100-nearest-1.png){#fig-boxplot-100-nearest width=672}\n:::\n:::\n\n#### Average distance to 100 nearest neighbors\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nnames <- paste0(\"Neighbor_\",1:100)\nneighbors$avg = rowMeans(dplyr::select(as.data.frame(neighbors),names))\n```\n:::\n\nTurning our attention to the averages of the first 100 neighbors, our analysis indicates strikingly similar results. There is considerable variance observed between different species, as well as within individual species, as depicted in @fig-density-avg-nearest.\n\nDespite the uniformity in average results, the issue of outliers persists, as evident in the boxplot representation shown in @fig-boxplot-avg-nearest. These outliers pose challenges and may be indicative of specific environmental conditions affecting tree distributions. Further exploration is required to better understand and mitigate the impact of outliers on our analysis.\n\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_density_plots(neighbors,value_column = \"avg\",category_column1 = \"area\",category_column2 = \"specie\", title = \"Density plots for the avergae of 100 nearest neighbors across species and areas\", xlims = c(25,60))\n```\n\n::: {.cell-output-display}\n![Density plot of the average distance to the nearest neighbor (n=100) distribution across all patches grouped by the dominant species.](report_files/figure-html/fig-density-avg-nearest-1.png){#fig-density-avg-nearest width=672}\n:::\n:::\n\n\n\nThe neighbor analysis proves potentially useful for distinguishing between tree species, yet the observed variances within each species suggest that relying solely on distance to neighbors may not suffice.\n\nA critical consideration is the sample size problem, wherein more distinguishable patterns emerge with higher neighbor levels, but this necessitates a sufficiently large sample size. Unfortunately, deriving a clear relationship between sample size and the number of tree neighbors remains elusive in our current findings. This gap in understanding could be a pertinent subject for further research, delving into the intricate interplay between sample size and the effectiveness of neighbor analysis in species differentiation.\n\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_boxplot(neighbors,value_column = \"avg\",category_column1 = \"area\",category_column2 = \"specie\", title = \"Box plots for the average to the nearest neighbor across all species and areas\")\n```\n\n::: {.cell-output-display}\n![Density plot of the average distance to the nearest neighbor (n = 100) distribution across all patches grouped by the dominant species.](report_files/figure-html/fig-boxplot-avg-nearest-1.png){#fig-boxplot-avg-nearest width=672}\n:::\n:::\n\n\n\n\n|specie |area | density (1/m²)|\n|:------|:-------------------|---------:|\n|beech |bielefeld_brackwede | 0.0089399|\n|beech |billerbeck | 0.0093175|\n|beech |wuelfenrath | 0.0079259|\n|oak |hamm | 0.0090610|\n|oak |muenster | 0.0077384|\n|oak |rinkerode | 0.0082641|\n|pine |greffen | 0.0103807|\n|pine |mesum | 0.0124200|\n|pine |telgte | 0.0122860|\n|spruce |brilon | 0.0158030|\n|spruce |oberhundem | 0.0162678|\n|spruce |osterwald | 0.0129892|\n\n\n\n# References\n\n::: {#refs}\n:::\n\n# Appendix\n## Script which can be used to do all preprocessing {#sec-appendix-preprocessing}\n\n::: {.cell}\n\n:::\n\n\nLoad the file with the research areas\n::: {.cell}\n\n```{.r .cell-code}\nsf <- sf::read_sf(here::here(\"research_areas.shp\"))\nprint(sf)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSimple feature collection with 12 features and 3 fields\nGeometry type: POLYGON\nDimension: XY\nBounding box: xmin: 7.071625 ymin: 51.0895 xmax: 8.539877 ymax: 52.25983\nGeodetic CRS: WGS 84\n# A tibble: 12 × 4\n id species name geometry\n \n 1 1 oak rinkerode ((7.678922 51.85789, 7.675446 51.85752, 7.…\n 2 2 oak hamm ((7.858955 51.66699, 7.866444 51.66462, 7.…\n 3 3 oak muenster ((7.618908 51.9154, 7.617384 51.9172, 7.61…\n 4 4 pine greffen ((8.168691 51.98965, 8.167178 51.99075, 8.…\n 5 5 pine telgte ((7.779728 52.00662, 7.781616 52.00662, 7.…\n 6 6 pine mesum ((7.534424 52.25499, 7.53378 52.25983, 7.5…\n 7 7 beech bielefeld_brackwede ((8.524749 51.9921, 8.528418 51.99079, 8.5…\n 8 8 beech wuelfenrath ((7.071625 51.29256, 7.072311 51.29334, 7.…\n 9 9 beech billerbeck ((7.324729 51.99783, 7.323548 51.99923, 7.…\n10 11 spruce brilon ((8.532195 51.41029, 8.535027 51.41064, 8.…\n11 12 spruce osterwald ((8.369328 51.21693, 8.371238 51.21718, 8.…\n12 10 spruce oberhundem ((8.18082 51.08999, 8.180868 51.09143, 8.1…\n```\n:::\n:::\n\n\nInit the project\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(lfa)\nsf::sf_use_s2(FALSE)\nlocations <- lfa_init(\"research_areas.shp\")\n```\n:::\n\nDo all of the prprocessing steps\n::: {.cell}\n\n```{.r .cell-code}\nlfa_map_tile_locations(locations,retile,check_flag = \"retile\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNo further processing: flag retile is set!Function is already computed, no further computings here\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\nNULL\n```\n:::\n\n```{.r .cell-code}\nlfa_map_tile_locations(locations, lfa_intersect_areas, ctg = NULL, areas_sf = sf,check_flag = \"intersect\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNo further processing: flag intersect is set!Function is already computed, no further computings here\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\nNULL\n```\n:::\n\n```{.r .cell-code}\nlfa_map_tile_locations(locations, lfa_ground_correction, ctg = NULL,check_flag = \"z_correction\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNo further processing: flag z_correction is set!Function is already computed, no further computings here\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\nNULL\n```\n:::\n\n```{.r .cell-code}\nlfa_map_tile_locations(locations, lfa_segmentation, ctg = NULL,check_flag = \"segmentation\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNo further processing: flag segmentation is set!Function is already computed, no further computings here\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\nNULL\n```\n:::\n\n```{.r .cell-code}\nlfa_map_tile_locations(locations, lfa_detection, catalog = NULL, write_to_file = TRUE,check_flag = \"detection\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNo further processing: flag detection is set!Function is already computed, no further computings here\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\nNULL\n```\n:::\n:::\n\n\n## Quantitative Results\n### Distribution of Z-Values\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndata <- lfa::lfa_get_detections()\nvalue_column <- \"Z\"\n```\n:::\n\n\n\n#### Kullback-Leibler-Divergence\n\n\n\n::: {#tbl-z-values-kld_specie .cell tbl-cap='Kullback-Leibler-Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nkld_results_specie <- lfa::lfa_run_test_asymmetric(data,value_column,\"specie\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_specie,\"Kullback-Leibler-Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between species
Beech Oak Pine Spruce
Beech 0.0 13.2 12.5 0.76
Oak 4.2 0.0 3.4 5.02
Pine 2.3 5.6 0.0 3.95
Spruce 2.4 14.7 16.1 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 5.252696\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-kld-beech .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie beech for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\nkld_results_beech <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_beech,\"Kullback-Leibler-Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0.00 0.4 3.1
Billerbeck 0.27 0.0 6.0
Wuelfenrath 1.13 2.4 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 1.473353\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-kld-oak .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie oak for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\nkld_results_oak <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_oak,\"Kullback-Leibler-Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0.0 2.1 16
Muenster 0.4 0.0 17
Rinkerode 7.6 17.8 0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 6.779863\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-kld-pine .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie pine for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\nkld_results_pine <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_pine,\"Kullback-Leibler-Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0.00 0.74 16
Mesum 0.43 0.00 18
Telgte 3.87 6.82 0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 5.129383\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-kld-spruce .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie spruce for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\nkld_results_spruce <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_spruce,\"Kullback-Leibler-Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0.000 0.092 1.7
Oberhundem 0.081 0.000 2.1
Osterwald 1.521 2.178 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.8509258\n```\n:::\n:::\n\n\n\n\n#### Jensen-Shannon Divergence\n\n\n\n::: {#tbl-z-values-jsd_specie .cell tbl-cap='Jensen-Shannon Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\njsd_results_specie <- lfa::lfa_run_test_symmetric(data,value_column,\"specie\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_specie,\"Jensen-Shannon Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between species
Beech Oak Pine Spruce
Beech 0 4.5 4.6 2.4
Oak NA 0.0 3.9 6.1
Pine NA NA 0.0 7.1
Spruce NA NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 2.246663\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-jsd-beech .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie beech for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\njsd_results_beech <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_beech,\"Jensen-Shannon Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0 1.1 3.3
Billerbeck NA 0.0 4.9
Wuelfenrath NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 1.10555\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-jsd-oak .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie oak for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\njsd_results_oak <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_oak,\"Jensen-Shannon Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0 1.6 6.5
Muenster NA 0.0 6.4
Rinkerode NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 1.692942\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-jsd-pine .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie pine for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\njsd_results_pine <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_pine,\"Jensen-Shannon Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0 3.1 12
Mesum NA 0.0 10
Telgte NA NA 0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 2.956354\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-jsd-spruce .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie spruce for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\njsd_results_spruce <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_spruce,\"Jensen-Shannon Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0 0.31 4.0
Oberhundem NA 0.00 5.5
Osterwald NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 1.100383\n```\n:::\n:::\n\n\n\n\n### Nearest Neighbours\n#### Distribution of nearest neighbor distances\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndata <- lfa::lfa_combine_sf_obj(lfa::lfa_get_neighbor_paths(),lfa::lfa_get_all_areas())\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/bielefeld_brackwede/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1443 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 466999.8 ymin: 5759839 xmax: 467617.1 ymax: 5760261\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/billerbeck/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1732 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 384890.8 ymin: 5761918 xmax: 385590.9 ymax: 5762478\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/wuelfenrath/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2779 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 365546.3 ymin: 5683711 xmax: 366356.1 ymax: 5684321\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/hamm/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2441 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 420953.3 ymin: 5723884 xmax: 421596 ymax: 5724609\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/muenster/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1270 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 404615.6 ymin: 5752535 xmax: 405396.8 ymax: 5752971\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/rinkerode/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1643 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 408428.2 ymin: 5746021 xmax: 409014.8 ymax: 5746511\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/greffen/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 513 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442816.1 ymin: 5760217 xmax: 443148.9 ymax: 5760567\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/mesum/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 5031 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 399930.6 ymin: 5790412 xmax: 400969.7 ymax: 5790950\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/telgte/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3368 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 416135.1 ymin: 5761663 xmax: 416697.1 ymax: 5762477\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/brilon/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3342 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 467305.7 ymin: 5695055 xmax: 467996.9 ymax: 5695593\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/oberhundem/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2471 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442631.7 ymin: 5660096 xmax: 443309.5 ymax: 5660502\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/osterwald/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2806 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 455822 ymin: 5673761 xmax: 456483.2 ymax: 5674162\nProjected CRS: ETRS89 / UTM zone 32N\n```\n:::\n\n```{.r .cell-code code-fold=\"true\"}\nvalue_column <- \"Neighbor_1\"\n```\n:::\n\n\n\n##### Kullback-Leibler-Divergence\n\n\n\n::: {#tbl-nearest-neighbor-1-kld_specie .cell tbl-cap='Kullback-Leibler-Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nkld_results_specie <- lfa::lfa_run_test_asymmetric(data,value_column,\"specie\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_specie,\"Kullback-Leibler-Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between species
Beech Oak Pine Spruce
Beech 0.000 0.029 0.40 3.3
Oak 0.031 0.000 0.25 3.9
Pine 0.213 0.128 0.00 4.9
Spruce 2.735 3.199 4.52 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 1.477983\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-kld-beech .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\nkld_results_beech <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_beech,\"Kullback-Leibler-Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0.000 0.35 0.051
Billerbeck 0.380 0.00 0.138
Wuelfenrath 0.059 0.15 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1249588\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-kld-oak .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\nkld_results_oak <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_oak,\"Kullback-Leibler-Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0.000 0.079 0.078
Muenster 0.092 0.000 0.019
Rinkerode 0.086 0.020 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.04167636\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-kld-pine .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\nkld_results_pine <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_pine,\"Kullback-Leibler-Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0.00 0.495 0.258
Mesum 0.48 0.000 0.098
Telgte 0.22 0.076 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1812239\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-kld-spruce .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\nkld_results_spruce <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_spruce,\"Kullback-Leibler-Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0.00 0.67 5.1
Oberhundem 0.41 0.00 7.2
Osterwald 6.09 6.23 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 2.863587\n```\n:::\n:::\n\n\n\n\n##### Jensen-Shannon Divergence\n\n\n\n::: {#tbl-nearest-neighbor-1-jsd_specie .cell tbl-cap='Jensen-Shannon Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\njsd_results_specie <- lfa::lfa_run_test_symmetric(data,value_column,\"specie\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_specie,\"Jensen-Shannon Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between species
Beech Oak Pine Spruce
Beech 0 0.22 2.1 9.3
Oak NA 0.00 1.3 10.6
Pine NA NA 0.0 14.7
Spruce NA NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 2.470051\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-jsd-beech .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\njsd_results_beech <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_beech,\"Jensen-Shannon Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0 2.2 0.39
Billerbeck NA 0.0 0.85
Wuelfenrath NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.5042359\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-jsd-oak .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\njsd_results_oak <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_oak,\"Jensen-Shannon Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0 0.57 0.61
Muenster NA 0.00 0.17
Rinkerode NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1803836\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-jsd-pine .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\njsd_results_pine <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_pine,\"Jensen-Shannon Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0 3.6 1.89
Mesum NA 0.0 0.68
Telgte NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.891592\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-jsd-spruce .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\njsd_results_spruce <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_spruce,\"Jensen-Shannon Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0 4.1 16
Oberhundem NA 0.0 18
Osterwald NA NA 0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 4.471632\n```\n:::\n:::\n\n\n#### Distribution of distances to 100th nearest neighbor\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndata <- lfa::lfa_combine_sf_obj(lfa::lfa_get_neighbor_paths(),lfa::lfa_get_all_areas())\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/bielefeld_brackwede/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1443 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 466999.8 ymin: 5759839 xmax: 467617.1 ymax: 5760261\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/billerbeck/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1732 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 384890.8 ymin: 5761918 xmax: 385590.9 ymax: 5762478\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/wuelfenrath/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2779 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 365546.3 ymin: 5683711 xmax: 366356.1 ymax: 5684321\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/hamm/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2441 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 420953.3 ymin: 5723884 xmax: 421596 ymax: 5724609\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/muenster/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1270 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 404615.6 ymin: 5752535 xmax: 405396.8 ymax: 5752971\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/rinkerode/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1643 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 408428.2 ymin: 5746021 xmax: 409014.8 ymax: 5746511\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/greffen/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 513 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442816.1 ymin: 5760217 xmax: 443148.9 ymax: 5760567\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/mesum/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 5031 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 399930.6 ymin: 5790412 xmax: 400969.7 ymax: 5790950\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/telgte/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3368 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 416135.1 ymin: 5761663 xmax: 416697.1 ymax: 5762477\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/brilon/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3342 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 467305.7 ymin: 5695055 xmax: 467996.9 ymax: 5695593\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/oberhundem/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2471 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442631.7 ymin: 5660096 xmax: 443309.5 ymax: 5660502\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/osterwald/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2806 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 455822 ymin: 5673761 xmax: 456483.2 ymax: 5674162\nProjected CRS: ETRS89 / UTM zone 32N\n```\n:::\n\n```{.r .cell-code code-fold=\"true\"}\nvalue_column <- \"Neighbor_100\"\n```\n:::\n\n\n\n##### Kullback-Leibler-Divergence\n\n\n\n::: {#tbl-nearest-neighbor-100-kld_specie .cell tbl-cap='Kullback-Leibler-Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nkld_results_specie <- lfa::lfa_run_test_asymmetric(data,value_column,\"specie\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_specie,\"Kullback-Leibler-Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between species
Beech Oak Pine Spruce
Beech 0.000 0.194 0.082 0.89
Oak 0.183 0.000 0.063 0.67
Pine 0.084 0.069 0.000 0.86
Spruce 1.083 0.809 1.200 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.3862841\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-kld-beech .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\nkld_results_beech <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_beech,\"Kullback-Leibler-Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0.00 0.12 0.12
Billerbeck 0.14 0.00 0.40
Wuelfenrath 0.12 0.31 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1338066\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-kld-oak .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\nkld_results_oak <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_oak,\"Kullback-Leibler-Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0.00 0.19 0.11
Muenster 0.20 0.00 0.06
Rinkerode 0.11 0.07 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.08182597\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-kld-pine .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\nkld_results_pine <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_pine,\"Kullback-Leibler-Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0.00 0.25 0.51
Mesum 0.20 0.00 0.25
Telgte 0.54 0.26 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.22229\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-kld-spruce .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\nkld_results_spruce <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_spruce,\"Kullback-Leibler-Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0.000 0.05 0.23
Oberhundem 0.046 0.00 0.37
Osterwald 0.276 0.46 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1591879\n```\n:::\n:::\n\n\n\n\n##### Jensen-Shannon Divergence\n\n\n\n::: {#tbl-nearest-neighbor-100-jsd_specie .cell tbl-cap='Jensen-Shannon Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\njsd_results_specie <- lfa::lfa_run_test_symmetric(data,value_column,\"specie\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_specie,\"Jensen-Shannon Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between species
Beech Oak Pine Spruce
Beech 0 0.38 0.14 1.27
Oak NA 0.00 0.30 0.78
Pine NA NA 0.00 1.39
Spruce NA NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.2997233\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-jsd-beech .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\njsd_results_beech <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_beech,\"Jensen-Shannon Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0 0.22 0.21
Billerbeck NA 0.00 0.57
Wuelfenrath NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.124106\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-jsd-oak .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\njsd_results_oak <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_oak,\"Jensen-Shannon Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0 0.34 0.17
Muenster NA 0.00 0.23
Rinkerode NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1007612\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-jsd-pine .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\njsd_results_pine <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_pine,\"Jensen-Shannon Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0 0.45 0.86
Mesum NA 0.00 0.50
Telgte NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.2265055\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-jsd-spruce .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\njsd_results_spruce <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_spruce,\"Jensen-Shannon Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0 0.1 0.57
Oberhundem NA 0.0 0.73
Osterwald NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1613747\n```\n:::\n:::\n\n\n#### Distribution of average nearest neighbor distances\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndata <- lfa::lfa_combine_sf_obj(lfa::lfa_get_neighbor_paths(),lfa::lfa_get_all_areas())\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/bielefeld_brackwede/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1443 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 466999.8 ymin: 5759839 xmax: 467617.1 ymax: 5760261\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/billerbeck/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1732 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 384890.8 ymin: 5761918 xmax: 385590.9 ymax: 5762478\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/wuelfenrath/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2779 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 365546.3 ymin: 5683711 xmax: 366356.1 ymax: 5684321\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/hamm/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2441 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 420953.3 ymin: 5723884 xmax: 421596 ymax: 5724609\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/muenster/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1270 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 404615.6 ymin: 5752535 xmax: 405396.8 ymax: 5752971\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/rinkerode/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1643 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 408428.2 ymin: 5746021 xmax: 409014.8 ymax: 5746511\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/greffen/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 513 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442816.1 ymin: 5760217 xmax: 443148.9 ymax: 5760567\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/mesum/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 5031 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 399930.6 ymin: 5790412 xmax: 400969.7 ymax: 5790950\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/telgte/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3368 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 416135.1 ymin: 5761663 xmax: 416697.1 ymax: 5762477\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/brilon/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3342 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 467305.7 ymin: 5695055 xmax: 467996.9 ymax: 5695593\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/oberhundem/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2471 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442631.7 ymin: 5660096 xmax: 443309.5 ymax: 5660502\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/osterwald/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2806 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 455822 ymin: 5673761 xmax: 456483.2 ymax: 5674162\nProjected CRS: ETRS89 / UTM zone 32N\n```\n:::\n\n```{.r .cell-code code-fold=\"true\"}\nnames <- paste0(\"Neighbor_\",1:100)\ndata$avg = rowMeans(dplyr::select(as.data.frame(data),names))\nvalue_column <- \"avg\"\n```\n:::\n\n\n\n##### Kullback-Leibler-Divergence\n\n\n\n::: {#tbl-nearest-neighbor-avg-kld_specie .cell tbl-cap='Kullback-Leibler-Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nkld_results_specie <- lfa::lfa_run_test_asymmetric(data,value_column,\"specie\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_specie,\"Kullback-Leibler-Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between species
Beech Oak Pine Spruce
Beech 0.000 0.31 0.065 1.28
Oak 0.302 0.00 0.178 0.83
Pine 0.067 0.17 0.000 1.23
Spruce 1.660 0.92 1.869 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.5552882\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-kld-beech .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\nkld_results_beech <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_beech,\"Kullback-Leibler-Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0.000 0.052 0.50
Billerbeck 0.052 0.000 0.91
Wuelfenrath 0.348 0.612 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.27574\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-kld-oak .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\nkld_results_oak <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_oak,\"Kullback-Leibler-Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0.00 0.166 0.217
Muenster 0.16 0.000 0.031
Rinkerode 0.21 0.037 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.09154318\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-kld-pine .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\nkld_results_pine <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_pine,\"Kullback-Leibler-Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0.00 0.17 0.29
Mesum 0.14 0.00 0.30
Telgte 0.26 0.32 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1637513\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-kld-spruce .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\nkld_results_spruce <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_spruce,\"Kullback-Leibler-Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0.000 0.11 0.29
Oberhundem 0.097 0.00 0.59
Osterwald 0.341 0.75 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.2404004\n```\n:::\n:::\n\n\n\n\n##### Jensen-Shannon Divergence\n\n\n\n::: {#tbl-nearest-neighbor-avg-jsd_specie .cell tbl-cap='Jensen-Shannon Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\njsd_results_specie <- lfa::lfa_run_test_symmetric(data,value_column,\"specie\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_specie,\"Jensen-Shannon Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between species
Beech Oak Pine Spruce
Beech 0 0.73 0.19 2.6
Oak NA 0.00 0.64 1.4
Pine NA NA 0.00 3.0
Spruce NA NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.5999417\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-jsd-beech .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\njsd_results_beech <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_beech,\"Jensen-Shannon Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0 0.14 1.0
Billerbeck NA 0.00 1.7
Wuelfenrath NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.3215991\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-jsd-oak .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\njsd_results_oak <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_oak,\"Jensen-Shannon Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0 0.41 0.53
Muenster NA 0.00 0.26
Rinkerode NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1558436\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-jsd-pine .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\njsd_results_pine <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_pine,\"Jensen-Shannon Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0 0.44 0.76
Mesum NA 0.00 0.89
Telgte NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.2560143\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-jsd-spruce .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\njsd_results_spruce <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_spruce,\"Jensen-Shannon Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0 0.32 1.1
Oberhundem NA 0.00 1.8
Osterwald NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.3713411\n```\n:::\n:::\n\n\n\n\n## Documentation\n### `lfa_capitalize_first_char`\n\nCapitalize First Character of a String\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`input_string` | A single-character string to be processed.\n\n\n#### Concept\n\nString Manipulation\n\n\n#### Description\n\nThis function takes a string as input and returns the same string with the\n first character capitalized. If the first character is already capitalized,\n the function does nothing. If the first character is not from the alphabet,\n an error is thrown.\n\n\n#### Details\n\nThis function performs the following steps:\n \n\n* Checks if the input is a single-character string. \n\n* Verifies if the first character is from the alphabet (A-Z or a-z). \n\n* If the first character is not already capitalized, it capitalizes it. \n\n* Returns the modified string.\n\n\n#### Keyword\n\nalphabet\n\n\n#### Note\n\nThis function is case-sensitive and assumes ASCII characters.\n\n\n#### References\n\nNone\n\n\n#### Seealso\n\nThis function is related to the basic string manipulation functions in base R.\n\n\n#### Value\n\nA modified string with the first character capitalized if it is\n not already. If the first character is already capitalized, the original\n string is returned.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Capitalize the first character of a string\ncapitalize_first_char(\"hello\") # Returns \"Hello\"\ncapitalize_first_char(\"World\") # Returns \"World\"\n\n# Error example (non-alphabetic first character)\ncapitalize_first_char(\"123abc\") # Throws an error\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_capitalize_first_char(input_string)\n```\n:::\n\n\n\n### `lfa_check_flag`\n\nCheck if a flag is set, indicating the completion of a specific process.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`flag_name` | A character string specifying the name of the flag file. It should be a descriptive and unique identifier for the process being checked.\n\n\n#### Description\n\nThis function checks for the existence of a hidden flag file at a specified location within the working directory. If the flag file is found, a message is printed, and the function returns `TRUE` to indicate that the associated processing step has already been completed. If the flag file is not found, the function returns `FALSE` , indicating that further processing can proceed.\n\n\n#### Value\n\nA logical value indicating whether the flag is set ( `TRUE` ) or not ( `FALSE` ).\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Check if the flag for a process named \"data_processing\" is set\nlfa_check_flag(\"data_processing\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_check_flag(flag_name)\n```\n:::\n\n\n\n### `lfa_combine_sf_obj`\n\nCombine Spatial Feature Objects from Multiple GeoPackage Files\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`paths` | A character vector containing file paths to GeoPackage files with neighbor information.\n`area_infos` | A data frame or list containing information about the corresponding detection areas, including \"area\" and \"specie\" columns.\n\n\n#### Description\n\nThis function reads spatial feature objects (sf) from multiple GeoPackage files and combines them into a single sf object.\n Each GeoPackage file is assumed to contain neighbor information for a specific detection area, and the resulting sf object\n includes additional columns indicating the corresponding area and species information.\n\n\n#### Value\n\nA combined sf object with additional columns for area and specie information.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming paths and area_infos are defined\ncombined_sf <- lfa_combine_sf_obj(paths, area_infos)\n\n# Print the combined sf object\nprint(combined_sf)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_combine_sf_obj(paths, area_infos)\n```\n:::\n\n\n\n### `lfa_count_returns_all_areas`\n\nCount tree returns for all species and areas, returning a consolidated data frame.\n\n\n#### Description\n\nThis function iterates through all species and areas obtained from the function\n [`lfa_get_all_areas`](#lfagetallareas) . For each combination of species and area, it reads\n the corresponding area as a catalog, counts the returns per tree using\n [`lfa_count_returns_per_tree`](#lfacountreturnspertree) , and consolidates the results into a data frame.\n The resulting data frame includes columns for the species, area, and return counts per tree.\n\n\n#### Keyword\n\ncounting\n\n\n#### Seealso\n\n[`lfa_get_all_areas`](#lfagetallareas) , [`lfa_read_area_as_catalog`](#lfareadareaascatalog) ,\n [`lfa_count_returns_per_tree`](#lfacountreturnspertree)\n\n\n#### Value\n\nA data frame with columns for species, area, and return counts per tree.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Count tree returns for all species and areas\nreturns_counts <- lfa_count_returns_all_areas()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_count_returns_all_areas()\n```\n:::\n\n\n\n### `lfa_count_returns_per_tree`\n\nCount returns per tree for a given lidR catalog.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`ctg` | A lidR catalog object containing LAS files to be processed.\n\n\n#### Description\n\nThis function takes a lidR catalog as input and counts the returns per tree.\n It uses the lidR package to read LAS files from the catalog and performs the counting\n operation on each tree. The result is a data frame containing the counts of returns\n for each unique tree ID within the lidR catalog.\n\n\n#### Keyword\n\ncounting\n\n\n#### Seealso\n\n[`lidR::readLAS`](#lidr::readlas) , [`lidR::is.empty`](#lidr::is.empty) ,\n [`base::table`](#base::table) , [`dplyr::bind_rows`](#dplyr::bindrows)\n\n\n#### Value\n\nA data frame with columns for tree ID and the corresponding count of returns.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Count returns per tree for a lidR catalog\nctg <- lfa_read_area_as_catalog(\"SpeciesA\", \"Area1\")\nreturns_counts_per_tree <- lfa_count_returns_per_tree(ctg)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_count_returns_per_tree(ctg)\n```\n:::\n\n\n\n### `lfa_create_boxplot`\n\nCreate a box plot from a data frame\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`data` | A data frame containing the data.\n`value_column` | The name of the column containing the values for the box plot.\n`category_column1` | The name of the column containing the first categorical variable.\n`category_column2` | The name of the column containing the second categorical variable.\n`title` | An optional title for the plot. If not provided, a default title is generated based on the data frame name.\n\n\n#### Description\n\nThis function generates a box plot using ggplot2 based on the specified data frame and columns.\n\n\n#### Details\n\nThe function creates a box plot where the x-axis is based on the second categorical variable,\n the y-axis is based on the specified value column, and the box plots are colored based on the first\n categorical variable. The grouping of box plots is done based on the unique values in the second categorical variable.\n\n\n#### Value\n\nA ggplot object representing the box plot.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming you have a data frame 'your_data' with columns 'value', 'category1', and 'category2'\ncreate_boxplot(your_data, \"value\", \"category1\", \"category2\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_boxplot(\n data,\n value_column,\n category_column1,\n category_column2,\n title = NULL\n)\n```\n:::\n\n\n\n### `lfa_create_density_plots`\n\nCreate density plots for groups in a data frame\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`data` | A data frame containing the data.\n`value_column` | The name of the column containing the values for the density plot.\n`category_column1` | The name of the column containing the categorical variable for grouping.\n`category_column2` | The name of the column containing the categorical variable for arranging plots.\n`title` | An optional title for the plot. If not provided, a default title is generated based on the data frame name.\n`xlims` | Optional limits for the x-axis. Should be a numeric vector with two elements (lower and upper bounds).\n`ylims` | Optional limits for the y-axis. Should be a numeric vector with two elements (lower and upper bounds).\n\n\n#### Description\n\nThis function generates density plots using ggplot2 based on the specified data frame and columns.\n\n\n#### Details\n\nThe function creates density plots where the x-axis is based on the specified value column,\n and the density plots are colored based on the first categorical variable. The arrangement of plots\n is done based on the unique values in the second categorical variable. The plots are arranged in a 2x2 grid.\n\n\n#### Value\n\nA ggplot object representing the density plots arranged in a 2x2 grid.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming you have a data frame 'your_data' with columns 'value', 'category1', and 'category2'\ncreate_density_plots(your_data, \"value\", \"category1\", \"category2\", title = \"Density Plots\", xlims = c(0, 10), ylims = c(0, 0.5))\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_density_plots(\n data,\n value_column,\n category_column1 = \"area\",\n category_column2 = \"specie\",\n title = NULL,\n xlims = NULL,\n ylims = NULL\n)\n```\n:::\n\n\n\n### `lfa_create_stacked_distributions_plot`\n\nCreate a stacked distribution plot for tree detections, visualizing the distribution\n of a specified variable on the x-axis, differentiated by another variable.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`trees` | A data frame containing tree detection data.\n`x_value` | A character string specifying the column name used for finding the values on the x-axis of the histogram.\n`fill_value` | A character string specifying the column name by which the data are differentiated in the plot.\n`bin` | An integer specifying the number of bins for the histogram. Default is 100.\n`ylab` | A character string specifying the y-axis label. Default is \"Amount trees.\"\n`xlim` | A numeric vector of length 2 specifying the x-axis limits. Default is c(0, 100).\n`ylim` | A numeric vector of length 2 specifying the y-axis limits. Default is c(0, 1000).\n`title` | The title of the plot.\n\n\n#### Description\n\nThis function generates a stacked distribution plot using the ggplot2 package,\n providing a visual representation of the distribution of a specified variable\n ( `x_value` ) on the x-axis, with differentiation based on another variable\n ( `fill_value` ). The data for the plot are derived from the provided `trees` \n data frame.\n\n\n#### Keyword\n\ndata\n\n\n#### Seealso\n\n[`ggplot2::geom_histogram`](#ggplot2::geomhistogram) , [`ggplot2::facet_wrap`](#ggplot2::facetwrap) ,\n [`ggplot2::ylab`](#ggplot2::ylab) , [`ggplot2::scale_fill_brewer`](#ggplot2::scalefillbrewer) ,\n [`ggplot2::coord_cartesian`](#ggplot2::coordcartesian)\n\n\n#### Value\n\nA ggplot object representing the stacked distribution plot.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Create a stacked distribution plot for variable \"Z,\" differentiated by \"area\"\ntrees <- lfa_get_detections()\nlfa_create_stacked_distributions_plot(trees, \"Z\", \"area\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_stacked_distributions_plot(\n trees,\n x_value,\n fill_value,\n bin = 100,\n ylab = \"Amount trees\",\n xlim = c(0, 100),\n ylim = c(0, 1000),\n title =\n \"Histograms of height distributions between species 'beech', 'oak', 'pine' and 'spruce' divided by the different areas of Interest\"\n)\n```\n:::\n\n\n\n### `lfa_create_stacked_histogram`\n\nCreate a stacked histogram for tree detections, summing up the values for each species.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`trees` | A data frame containing tree detection data.\n`x_value` | A character string specifying the column name used for finding the values on the x-axis of the histogram.\n`fill_value` | A character string specifying the column name by which the data are differentiated in the plot.\n`bin` | An integer specifying the number of bins for the histogram. Default is 30.\n`ylab` | A character string specifying the y-axis label. Default is \"Frequency.\"\n`xlim` | A numeric vector of length 2 specifying the x-axis limits. Default is c(0, 100).\n`ylim` | A numeric vector of length 2 specifying the y-axis limits. Default is NULL.\n\n\n#### Description\n\nThis function generates a stacked histogram using the ggplot2 package,\n summing up the values for each species and visualizing the distribution of\n a specified variable ( `x_value` ) on the x-axis, differentiated by another\n variable ( `fill_value` ). The data for the plot are derived from the provided\n `trees` data frame.\n\n\n#### Keyword\n\ndata\n\n\n#### Seealso\n\n[`ggplot2::geom_histogram`](#ggplot2::geomhistogram) , [`ggplot2::ylab`](#ggplot2::ylab) ,\n [`ggplot2::scale_fill_brewer`](#ggplot2::scalefillbrewer) , [`ggplot2::coord_cartesian`](#ggplot2::coordcartesian)\n\n\n#### Value\n\nA ggplot object representing the stacked histogram.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Create a stacked histogram for variable \"Z,\" differentiated by \"area\"\ntrees <- lfa_get_detections()\nlfa_create_stacked_histogram(trees, \"Z\", \"area\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_stacked_histogram(\n trees,\n x_value,\n fill_value,\n bin = 30,\n ylab = \"Frequency\",\n xlim = c(0, 100),\n ylim = NULL\n)\n```\n:::\n\n\n\n### `lfa_create_tile_location_objects`\n\nCreate tile location objects\n\n\n#### Author\n\nJakob Danel\n\n\n#### Description\n\nThis function traverses a directory structure to find LAZ files and creates\n tile location objects for each file. The function looks into the the `data` \n directory of the repository/working directory. It then creates `tile_location` \n objects based on the folder structure. The folder structure should not be\n touched by hand, but created by `lfa_init_data_structure()` which builds the\n structure based on a shape file.\n\n\n#### Seealso\n\n[`tile_location`](#tilelocation)\n\n\n#### Value\n\nA vector containing tile location objects.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_tile_location_objects()\n\nlfa_create_tile_location_objects()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_tile_location_objects()\n```\n:::\n\n\n\n### `lfa_detection`\n\nPerform tree detection on a lidar catalog and optionally save the results to a file.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`catalog` | A lidar catalog containing point cloud data. If set to NULL, the function attempts to read the catalog from the specified tile location.\n`tile_location` | An object specifying the location of the lidar tile. If catalog is NULL, the function attempts to read the catalog from this tile location.\n`write_to_file` | A logical value indicating whether to save the detected tree information to a file. Default is TRUE.\n\n\n#### Description\n\nThis function utilizes lidar data to detect trees within a specified catalog. The detected tree information can be optionally saved to a file in the GeoPackage format. The function uses parallel processing to enhance efficiency.\n\n\n#### Value\n\nA sf style data frame containing information about the detected trees.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Perform tree detection on a catalog and save the results to a file\nlfa_detection(catalog = my_catalog, tile_location = my_tile_location, write_to_file = TRUE)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_detection(catalog, tile_location, write_to_file = TRUE)\n```\n:::\n\n\n\n### `lfa_download_areas`\n\nDownload areas based on spatial features\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`sf_areas` | Spatial features representing areas to be downloaded. It must include columns like \"species\" \"name\" See details for more information.\n\n\n#### Author\n\nJakob Danel\n\n\n#### Description\n\nThis function initiates the data structure and downloads areas based on spatial features.\n\n\n#### Details\n\nThe input data frame, `sf_areas` , must have the following columns:\n \n\n* \"species\": The species associated with the area. \n\n* \"name\": The name of the area. \n \n The function uses the `lfa_init_data_structure` function to set up the data structure\n and then iterates through the rows of `sf_areas` to download each specified area.\n\n\n#### Value\n\nNone\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_download_areas(sf_areas)\n\n\n# Example spatial features data frame\nsf_areas <- data.frame(\nspecies = c(\"SpeciesA\", \"SpeciesB\"),\nname = c(\"Area1\", \"Area2\"),\n# Must include also other attributes specialized to sf objects\n# such as geometry, for processing of the download\n)\n\nlfa_download_areas(sf_areas)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_download_areas(sf_areas)\n```\n:::\n\n\n\n### `lfa_download`\n\nDownload an las file from the state NRW from a specific location\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`species` | The species of the tree which is observed at this location\n`name` | The name of the area that is observed\n`location` | An sf object, which holds the location information for the area where the tile should be downloaded from.\n\n\n#### Description\n\nIt will download the file and save it to data/ list(list(\"html\"), list(list(\"\"))) / list(list(\"html\"), list(list(\"\"))) with the name of the tile\n\n\n#### Value\n\nThe LASCatalog object of the downloaded file\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_download(species, name, location)\n```\n:::\n\n\n\n### `lfa_find_n_nearest_trees`\n\nFind n Nearest Trees\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`trees` | A sf object containing tree coordinates.\n`n` | The number of nearest trees to find for each tree (default is 100).\n\n\n#### Description\n\nThis function calculates the distances to the n nearest trees for each tree in the input dataset.\n\n\n#### Value\n\nA data frame with additional columns representing the distances to the n nearest trees.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Load tree data using lfa_get_detections() (not provided)\ntree_data <- lfa_get_detections()\n\n# Filter tree data for a specific species and area\ntree_data = tree_data[tree_data$specie == \"pine\" & tree_data$area == \"greffen\", ]\n\n# Find the 100 nearest trees for each tree in the filtered dataset\ntree_data <- lfa_find_n_nearest_trees(tree_data)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_find_n_nearest_trees(trees, n = 100)\n```\n:::\n\n\n\n### `lfa_generate_result_table_tests`\n\nGenerate Result Table for Tests\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`table` | A data frame representing the result table.\n\n\n#### Description\n\nThis function generates a result table for tests using the knitr::kable function.\n\n\n#### Details\n\nThis function uses the knitr::kable function to create a formatted table, making it suitable for HTML output.\n The input table is expected to be a data frame with test results, and the resulting table will have capitalized\n row and column names with lines between columns and rows.\n\n\n#### Value\n\nA formatted table suitable for HTML output with lines between columns and rows.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Generate a result table for tests\nresult_table <- data.frame(\nTest1 = c(0.05, 0.10, 0.03),\nTest2 = c(0.02, 0.08, 0.01),\nTest3 = c(0.08, 0.12, 0.05)\n)\nformatted_table <- lfa_generate_result_table_tests(result_table)\nprint(formatted_table)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_generate_result_table_tests(table, caption = \"Table Caption\")\n```\n:::\n\n\n\n### `lfa_get_all_areas`\n\nRetrieve a data frame containing all species and corresponding areas.\n\n\n#### Description\n\nThis function scans the \"data\" directory within the current working directory to\n obtain a list of species. It then iterates through each species to retrieve the list\n of areas associated with that species. The resulting data frame contains two columns:\n \"specie\" representing the species and \"area\" representing the corresponding area.\n\n\n#### Keyword\n\ndata\n\n\n#### Seealso\n\n[`list.dirs`](#list.dirs)\n\n\n#### Value\n\nA data frame with columns \"specie\" and \"area\" containing information about\n all species and their associated areas.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Retrieve a data frame with information about all species and areas\nall_areas_df <- lfa_get_all_areas()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_all_areas()\n```\n:::\n\n\n\n### `lfa_get_detection_area`\n\nGet Detection for an area\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`species` | A character string specifying the target species.\n`name` | A character string specifying the name of the tile.\n\n\n#### Description\n\nRetrieves the tree detection information for a specified species and tile.\n\n\n#### Details\n\nThis function reads tree detection data from geopackage files within the specified tile location for a given species. It then combines the data into a single SF data frame and returns it. The function assumes that the tree detection files follow a naming convention with the pattern \"_detection.gpkg\".\n\n\n#### Keyword\n\nspatial\n\n\n#### References\n\nThis function is part of the LiDAR Forest Analysis (LFA) package.\n\n\n#### Seealso\n\n[`get_tile_dir`](#gettiledir)\n\n\n#### Value\n\nA Simple Features (SF) data frame containing tree detection information for the specified species and tile.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Retrieve tree detection data for species \"example_species\" in tile \"example_tile\"\ntrees_data <- lfa_get_detection_tile_location(\"example_species\", \"example_tile\")\n\n# Example usage:\ntrees_data <- lfa_get_detection_tile_location(\"example_species\", \"example_tile\")\n\n# No trees found scenario:\nempty_data <- lfa_get_detection_tile_location(\"nonexistent_species\", \"nonexistent_tile\")\n# The result will be an empty data frame if no trees are found for the specified species and tile.\n\n# Error handling:\n# In case of invalid inputs, the function may throw errors. Ensure correct species and tile names are provided.\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_detection_area(species, name)\n```\n:::\n\n\n\n### `lfa_get_detections_species`\n\nRetrieve detections for a specific species.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`species` | A character string specifying the target species.\n\n\n#### Description\n\nThis function retrieves detection data for a given species from multiple areas.\n\n\n#### Details\n\nThe function looks for detection data in the \"data\" directory for the specified species.\n It then iterates through each subdirectory (representing different areas) and consolidates the\n detection data into a single data frame.\n\n\n#### Value\n\nA data frame containing detection information for the specified species in different areas.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Example usage:\ndetections_data <- lfa_get_detections_species(\"example_species\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_detections_species(species)\n```\n:::\n\n\n\n### `lfa_get_detections`\n\nRetrieve aggregated detection data for multiple species.\n\n\n#### Concept\n\ndata retrieval functions\n\n\n#### Description\n\nThis function obtains aggregated detection data for multiple species by iterating\n through the list of species obtained from [`lfa_get_species`](#lfagetspecies) . For each\n species, it calls [`lfa_get_detections_species`](#lfagetdetectionsspecies) to retrieve the\n corresponding detection data and aggregates the results into a single data frame.\n The resulting data frame includes columns for the species, tree detection data,\n and the area in which the detections occurred.\n\n\n#### Keyword\n\naggregation\n\n\n#### Seealso\n\n[`lfa_get_species`](#lfagetspecies) , [`lfa_get_detections_species`](#lfagetdetectionsspecies) \n \n Other data retrieval functions:\n [`lfa_get_species`](#lfagetspecies)\n\n\n#### Value\n\nA data frame containing aggregated detection data for multiple species.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_detections()\n\n# Retrieve aggregated detection data for multiple species\ndetections_data <- lfa_get_detections()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_detections()\n```\n:::\n\n\n\n### `lfa_get_flag_path`\n\nGet the path to a flag file indicating the completion of a specific process.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`flag_name` | A character string specifying the name of the flag file. It should be a descriptive and unique identifier for the process being flagged.\n\n\n#### Description\n\nThis function constructs and returns the path to a hidden flag file, which serves as an indicator that a particular processing step has been completed. The flag file is created in a designated location within the working directory.\n\n\n#### Value\n\nA character string representing the absolute path to the hidden flag file.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Get the flag path for a process named \"data_processing\"\nlfa_get_flag_path(\"data_processing\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_flag_path(flag_name)\n```\n:::\n\n\n\n### `lfa_get_neighbor_paths`\n\nGet Paths to Neighbor GeoPackage Files\n\n\n#### Description\n\nThis function retrieves the file paths to GeoPackage files containing neighbor information for each detection area.\n The GeoPackage files are assumed to be named \"neighbours.gpkg\" and organized in a directory structure under the \"data\" folder.\n\n\n#### Value\n\nA character vector containing file paths to GeoPackage files for each detection area's neighbors.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Get paths to neighbor GeoPackage files for all areas\npaths <- lfa_get_neighbor_paths()\n\n# Print the obtained file paths\nprint(paths)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_neighbor_paths()\n```\n:::\n\n\n\n### `lfa_get_species`\n\nGet a list of species from the data directory.\n\n\n#### Concept\n\ndata retrieval functions\n\n\n#### Description\n\nThis function retrieves a list of species by scanning the \"data\" directory\n located in the current working directory.\n\n\n#### Keyword\n\ndata\n\n\n#### References\n\nThis function relies on the [`list.dirs`](#list.dirs) function for directory listing.\n\n\n#### Seealso\n\n[`list.dirs`](#list.dirs) \n \n Other data retrieval functions:\n [`lfa_get_detections`](#lfagetdetections)\n\n\n#### Value\n\nA character vector containing the names of species found in the \"data\" directory.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Retrieve the list of species\nspecies_list <- lfa_get_species()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_species()\n```\n:::\n\n\n\n### `lfa_ground_correction`\n\nCorrect the point clouds for correct ground imagery\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`ctg` | An LASCatalog object. If not null, it will perform the actions on this object, if NULL inferring the catalog from the tile_location\n`tile_location` | A tile_location type object holding the information about the location of the cataog. This is used to save the catalog after processing too.\n\n\n#### Author\n\nJakob Danel\n\n\n#### Description\n\nThis function is needed to correct the Z value of the point cloud, relative to the real\n ground height. After using this function to your catalog, the Z values can be seen as the\n real elevation about the ground. At the moment the function uses the `tin()` function from\n the `lidr` package. NOTE : The operation is inplace and can not be reverted, the old values\n of the point cloud will be deleted!\n\n\n#### Value\n\nA catalog with the corrected z values. The catalog is always stored at tile_location and\n holding only the transformed values.\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_ground_correction(ctg, tile_location)\n```\n:::\n\n\n\n### `lfa_init_data_structure`\n\nInitialize data structure for species and areas\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`sf_species` | A data frame with information about species and associated areas.\n\n\n#### Description\n\nThis function initializes the data structure for storing species and associated areas.\n\n\n#### Details\n\nThe input data frame, `sf_species` , should have at least the following columns:\n \n\n* \"species\": The names of the species for which the data structure needs to be initialized. \n\n* \"name\": The names of the associated areas. \n \n The function creates directories based on the species and area information provided in\n the `sf_species` data frame. It checks whether the directories already exist and creates\n them if they don't.\n\n\n#### Value\n\nNone\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Example species data frame\nsf_species <- data.frame(\nspecies = c(\"SpeciesA\", \"SpeciesB\"),\nname = c(\"Area1\", \"Area2\"),\n# Other necessary columns\n)\n\nlfa_init_data_structure(sf_species)\n\n# Example species data frame\nsf_species <- data.frame(\nspecies = c(\"SpeciesA\", \"SpeciesB\"),\nname = c(\"Area1\", \"Area2\"),\n# Other necessary columns\n)\n\nlfa_init_data_structure(sf_species)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_init_data_structure(sf_species)\n```\n:::\n\n\n\n### `lfa_init`\n\nInitialize LFA (LiDAR forest analysis) data processing\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`sf_file` | A character string specifying the path to the shapefile containing spatial features of research areas.\n\n\n#### Description\n\nThis function initializes the LFA data processing by reading a shapefile containing\n spatial features of research areas, downloading the specified areas, and creating\n tile location objects for each area.\n\n\n#### Details\n\nThis function reads a shapefile ( `sf_file` ) using the `sf` package, which should\n contain information about research areas. It then calls the `lfa_download_areas` \n function to download the specified areas and `lfa_create_tile_location_objects` \n to create tile location objects based on Lidar data files in those areas. The\n shapefile MUST follow the following requirements:\n \n\n* Each geometry must be a single object of type polygon \n\n* Each entry must have the following attributes: \n\n* species: A string describing the tree species of the area. \n\n* name: A string describing the location of the area.\n\n\n#### Value\n\nA vector containing tile location objects.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Initialize LFA processing with the default shapefile\nlfa_init()\n\n# Initialize LFA processing with a custom shapefile\nlfa_init(\"custom_areas.shp\")\n\n# Example usage with the default shapefile\nlfa_init()\n\n# Example usage with a custom shapefile\nlfa_init(\"custom_areas.shp\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_init(sf_file = \"research_areas.shp\")\n```\n:::\n\n\n\n### `lfa_intersect_areas`\n\nIntersect Lidar Catalog with Spatial Features\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`ctg` | A LAScatalog object representing the Lidar data to be processed.\n`tile_location` | A tile location object representing the specific area of interest.\n`areas_sf` | Spatial features defining areas.\n\n\n#### Description\n\nThis function intersects a Lidar catalog with a specific area defined by spatial features.\n\n\n#### Details\n\nThe function intersects the Lidar catalog specified by `ctg` with a specific area defined by\n the `tile_location` object and `areas_sf` . It removes points outside the specified area and\n returns a modified LAScatalog object.\n \n The specified area is identified based on the `species` and `name` attributes in the\n `tile_location` object. If a matching area is not found in `areas_sf` , the function\n stops with an error.\n \n The function then transforms the spatial reference of the identified area to match that of\n the Lidar catalog using `sf::st_transform` .\n \n The processing is applied to each chunk in the catalog using the `identify_area` function,\n which merges spatial information and filters out points that are not classified as inside\n the identified area. After processing, the function writes the modified LAS files back to\n the original file locations, removing points outside the specified area.\n \n If an error occurs during the processing of a chunk, a warning is issued, and the function\n continues processing the next chunks. If no points are found after filtering, a warning is\n issued, and NULL is returned.\n\n\n#### Seealso\n\nOther functions in the Lidar forest analysis (LFA) package.\n\n\n#### Value\n\nA modified LAScatalog object with points outside the specified area removed.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Example usage\nlfa_intersect_areas(ctg, tile_location, areas_sf)\n\n# Example usage\nlfa_intersect_areas(ctg, tile_location, areas_sf)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_intersect_areas(ctg, tile_location, areas_sf)\n```\n:::\n\n\n\n### `lfa_jsd_from_vec`\n\nCompute Jensen-Shannon Divergence from Vectors\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`x` | A numeric vector.\n`y` | A numeric vector.\n\n\n#### Description\n\nThis function calculates the Jensen-Shannon Divergence (JSD) between two vectors.\n\n\n#### Value\n\nJensen-Shannon Divergence between the density distributions of x and y.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nx <- rnorm(100)\ny <- rnorm(100, mean = 2)\nlfa_jsd_from_vec(x, y)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_jsd_from_vec(x, y)\n```\n:::\n\n\n\n### `lfa_jsd`\n\nJensen-Shannon Divergence Calculation\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`p` | A numeric vector representing the probability distribution P.\n`q` | A numeric vector representing the probability distribution Q.\n`epsilon` | A small positive constant added to both P and Q to avoid logarithm of zero. Default is 1e-10.\n\n\n#### Description\n\nThis function calculates the Jensen-Shannon Divergence (JSD) between two probability distributions P and Q.\n\n\n#### Details\n\nThe JSD is computed using the Kullback-Leibler Divergence (KLD) as follows:\n `sum((p * log((p + epsilon) / (m + epsilon)) + q * log((q + epsilon) / (m + epsilon))) / 2)` \n where `m = (p + q) / 2` .\n\n\n#### Seealso\n\n[`kld`](#kld) , [`sum`](#sum) , [`log`](#log)\n\n\n#### Value\n\nA numeric value representing the Jensen-Shannon Divergence between P and Q.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Calculate JSD between two probability distributions\np_distribution <- c(0.2, 0.3, 0.5)\nq_distribution <- c(0.1, 0, 0.9)\njsd_result <- jsd(p_distribution, q_distribution)\nprint(jsd_result)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_jsd(p, q, epsilon = 1e-10)\n```\n:::\n\n\n\n### `lfa_kld_from_vec`\n\nCompute Kullback-Leibler Divergence from Vectors\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`x` | A numeric vector.\n`y` | A numeric vector.\n\n\n#### Description\n\nThis function calculates the Kullback-Leibler Divergence (KLD) between two vectors.\n\n\n#### Value\n\nKullback-Leibler Divergence between the density distributions of x and y.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nx <- rnorm(100)\ny <- rnorm(100, mean = 2)\nlfa_kld_from_vec(x, y)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_kld_from_vec(x, y)\n```\n:::\n\n\n\n### `lfa_kld`\n\nKullback-Leibler Divergence Calculation\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`p` | A numeric vector representing the probability distribution P.\n`q` | A numeric vector representing the probability distribution Q.\n`epsilon` | A small positive constant added to both P and Q to avoid logarithm of zero. Default is 1e-10.\n\n\n#### Description\n\nThis function calculates the Kullback-Leibler Divergence (KLD) between two probability distributions P and Q.\n\n\n#### Details\n\nThe KLD is computed using the formula:\n `sum(p * log((p + epsilon) / (q + epsilon)))` \n This avoids issues when the denominator (Q) contains zero probabilities.\n\n\n#### Seealso\n\n[`sum`](#sum) , [`log`](#log)\n\n\n#### Value\n\nA numeric value representing the Kullback-Leibler Divergence between P and Q.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Calculate KLD between two probability distributions\np_distribution <- c(0.2, 0.3, 0.5)\nq_distribution <- c(0.1, 0, 0.9)\nkld_result <- kld(p_distribution, q_distribution)\nprint(kld_result)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_kld(p, q, epsilon = 1e-10)\n```\n:::\n\n\n\n### `lfa_ks_test`\n\nKolmogorov-Smirnov Test Wrapper Function\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`x` | A numeric vector representing the first sample.\n`y` | A numeric vector representing the second sample.\n`output_variable` | A character string specifying the output variable to extract from the ks.test result. Default is \"p.value\". Other possible values include \"statistic\" and \"alternative\".\n`...` | Additional arguments to be passed to the ks.test function.\n\n\n#### Description\n\nThis function serves as a wrapper for the Kolmogorov-Smirnov (KS) test between two samples.\n\n\n#### Details\n\nThe function uses the ks.test function to perform a two-sample KS test and returns the specified output variable.\n The default output variable is the p-value. Other possible output variables include \"statistic\" and \"alternative\".\n\n\n#### Seealso\n\n[`ks.test`](#ks.test)\n\n\n#### Value\n\nA numeric value representing the specified output variable from the KS test result.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Perform KS test and extract the p-value\nresult <- lfa_ks_test(sample1, sample2)\nprint(result)\n\n# Perform KS test and extract the test statistic\nresult_statistic <- lfa_ks_test(sample1, sample2, output_variable = \"statistic\")\nprint(result_statistic)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_ks_test(x, y, output_variable = \"p.value\", ...)\n```\n:::\n\n\n\n### `lfa_load_ctg_if_not_present`\n\nLoading the catalog if it is not present\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`ctg` | Catalog object. Can be NULL\n`tile_location` | The location to look for the catalog tiles, if their are not present\n\n\n#### Description\n\nThis function checks if the catalog is `NULL` . If it is it will load the\n catalog from the `tile_location`\n\n\n#### Value\n\nThe provided ctg object if not null, else the catalog for the tiles\n of the tile_location.\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_load_ctg_if_not_present(ctg, tile_location)\n```\n:::\n\n\n\n### `lfa_map_tile_locations`\n\nMap Function Over Tile Locations\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`tile_locations` | A list of tile location objects.\n`map_function` | The mapping function to be applied to each tile location.\n`...` | Additional arguments to be passed to the mapping function.\n\n\n#### Description\n\nThis function applies a specified mapping function to each tile location in a list.\n\n\n#### Details\n\nThis function iterates over each tile location in the provided list ( `tile_locations` )\n and applies the specified mapping function ( `map_function` ) to each tile location.\n The mapping function should accept a tile location object as its first argument, and\n additional arguments can be passed using the ellipsis ( `...` ) syntax.\n \n This function is useful for performing operations on multiple tile locations concurrently,\n such as loading Lidar data, processing areas, or other tasks that involve tile locations.\n\n\n#### Seealso\n\nThe mapping function provided should be compatible with the structure and requirements\n of the tile locations and the specific task being performed.\n\n\n#### Value\n\nNone\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Example usage\nlfa_map_tile_locations(tile_locations, my_mapping_function, param1 = \"value\")\n\n# Example usage\nlfa_map_tile_locations(tile_locations, my_mapping_function, param1 = \"value\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_map_tile_locations(tile_locations, map_function, check_flag = NULL, ...)\n```\n:::\n\n\n\n### `lfa_merge_and_save`\n\nMerge and Save Text Files in a Directory\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`input_directory` | The path to the input directory containing text files.\n`output_name` | The name for the output file where the merged content will be saved.\n\n\n#### Description\n\nThis function takes an input directory and an output name as arguments.\n It merges the textual content of all files in the specified directory into\n a single string, with each file's content separated by a newline character.\n The merged content is then saved into a file named after the output name\n in the same directory. After the merging is complete, all input files are\n deleted.\n\n\n#### Details\n\nThis function reads the content of each text file in the specified input directory\n and concatenates them into a single string. Each file's content is separated by a newline\n character. The merged content is then saved into a file named after the output name\n in the same directory. Finally, all input files are deleted from the directory.\n\n\n#### Seealso\n\n[`readLines`](#readlines) , [`writeLines`](#writelines) , [`file.remove`](#file.remove)\n\n\n#### Value\n\nThis function does not explicitly return any value. It prints a message\n indicating the successful completion of the merging and saving process.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Merge text files in the \"data_files\" directory and save the result in \"merged_output\"\nlfa_merge_and_save(\"data_files\", \"merged_output\")\n\n# Merge text files in the \"data_files\" directory and save the result in \"merged_output\"\nlfa_merge_and_save(\"data_files\", \"merged_output\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_merge_and_save(input_directory, output_name)\n```\n:::\n\n\n\n### `lfa_random_forest`\n\nRandom Forest Classifier with Leave-One-Out Cross-Validation\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`tree_data` | A data frame containing the tree data, including the response variable (\"specie\") and predictor variables.\n`excluded_input_columns` | A character vector specifying columns to be excluded from predictor variables.\n`response_variable` | The response variable to be predicted (default is \"specie\").\n`seed` | An integer to set the seed for reproducibility (default is 123).\n`...` | Additional parameters to be passed to the randomForest function.\n\n\n#### Description\n\nThis function performs a random forest classification using leave-one-out cross-validation for each area in the input tree data.\n It returns a list containing various results, including predicted species, confusion matrix, accuracy, and the formula used for modeling.\n\n\n#### Value\n\nA list containing the following elements:\n \n\n* `predicted_species_absolute` : A data frame with observed and predicted species for each area. \n\n* `predicted_species_relative` : A data frame wit the relative precictions per speices and areas, normalized by the total predictions in each area. \n\n* `confusion_matrix` : A confusion matrix showing the counts of predicted vs. observed species. \n\n* `accuracy` : The accuracy of the model, calculated as the sum of diagonal elements in the confusion matrix divided by the total count. \n\n* `formula` : The formula used for modeling.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming tree_data is defined\nresults <- lfa_random_forest(tree_data, excluded_input_columns = c(\"column1\", \"column2\"))\n\n# Print the list of results\nprint(results)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_random_forest(\n tree_data,\n excluded_input_columns,\n response_variable = \"specie\",\n ntree = 100,\n seed = 123,\n ...\n)\n```\n:::\n\n\n\n### `lfa_rd_to_qmd`\n\nConvert Rd File to Markdown\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`rdfile` | The path to the Rd file or a parsed Rd object.\n`outfile` | The path to the output Markdown file (including the file extension).\n`append` | Logical, indicating whether to append to an existing file (default is FALSE).\n\n\n#### Description\n\nIMPORTANT NOTE: \n This function is nearly identical to the `Rd2md::Rd2markdown` function from the `Rd2md` \n package. We needed to implement our own version of it because of various reasons:\n \n\n* The algorithm uses hardcoded header sizes (h1 and h2 in original) which is not feasible for our use-case of the markdown. \n\n* We needed to add some Quarto Markdown specifics, e.g. to make sure that the examples will not be runned. \n\n* We want to exclude certain tags from our implementation.\n\n\n#### Details\n\nFor that reason we copied the method and made changes as needed and also added this custom documentation.\n \n This function converts an Rd (R documentation) file to Markdown format (.md) and\n saves the converted file at the specified location. The function allows appending\n to an existing file or creating a new one. The resulting Markdown file includes\n sections for the function's name, title, and additional content such as examples,\n usage, arguments, and other sections present in the Rd file.\n \n The function performs the following steps:\n \n\n* Parses the Rd file using the Rd2md package. \n\n* Creates a Markdown file with sections for the function's name, title, and additional content. \n\n* Appends the content to an existing file if `append` is set to TRUE. \n\n* Saves the resulting Markdown file at the specified location.\n\n\n#### Seealso\n\n[`Rd2md::parseRd`](#rd2md::parserd)\n\n\n#### Value\n\nThis function does not explicitly return any value. It saves the converted Markdown file\n at the specified location as described in the details section.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Convert Rd file to Markdown and save it\nlfa_rd_to_md(\"path/to/your/file.Rd\", \"path/to/your/output/file.md\")\n\n# Convert Rd file to Markdown and append to an existing file\nlfa_rd_to_md(\"path/to/your/file.Rd\", \"path/to/existing/output/file.md\", append = TRUE)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_rd_to_qmd(rdfile, outfile, append = FALSE)\n```\n:::\n\n\n\n### `lfa_rd_to_results`\n\nConvert Rd Files to Markdown and Merge Results\n\n\n#### Description\n\nThis function converts all Rd (R documentation) files in the \"man\" directory\n to Markdown format (.qmd) and saves the converted files in the \"results/appendix/package-docs\" directory.\n It then merges the converted Markdown files into a single string and saves\n the merged content into a file named \"docs.qmd\" in the \"results/appendix/package-docs\" directory.\n\n\n#### Details\n\nThe function performs the following steps:\n \n\n* Removes any existing \"docs.qmd\" file in the \"results/appendix/package-docs\" directory. \n\n* Finds all Rd files in the \"man\" directory. \n\n* Converts each Rd file to Markdown format (.qmd) using the `lfa_rd_to_qmd` function. \n\n* Saves the converted Markdown files in the \"results/appendix/package-docs\" directory. \n\n* Merges the content of all converted Markdown files into a single string. \n\n* Saves the merged content into a file named \"docs.qmd\" in the \"results/appendix/package-docs\" directory.\n\n\n#### Seealso\n\n[`lfa_rd_to_qmd`](#lfardtoqmd) , [`lfa_merge_and_save`](#lfamergeandsave)\n\n\n#### Value\n\nThis function does not explicitly return any value. It performs the conversion,\n merging, and saving operations as described in the details section.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Convert Rd files to Markdown and merge the results\nlfa_rd_to_results()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_rd_to_results()\n```\n:::\n\n\n\n### `lfa_read_area_as_catalog`\n\nRead LiDAR data from a specified species and location as a catalog.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`specie` | A character string specifying the species of interest.\n`location_name` | A character string specifying the name of the location.\n\n\n#### Description\n\nThis function constructs the file path based on the specified `specie` and `location_name` ,\n lists the directories at that path, and reads the LiDAR data into a `lidR::LAScatalog` .\n\n\n#### Value\n\nA `lidR::LAScatalog` object containing the LiDAR data from the specified location and species.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_read_area_as_catalog(\"beech\", \"location1\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_read_area_as_catalog(specie, location_name)\n```\n:::\n\n\n\n### `lfa_run_test_asymmetric`\n\nAsymmetric Pairwise Test for Categories\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`data` | A data frame containing the relevant columns.\n`data_column` | A character string specifying the column containing the numerical data.\n`category_column` | A character string specifying the column containing the categorical variable.\n`test_function` | A function used to perform the pairwise test between two sets of data. It should accept two vectors of numeric data and additional parameters specified by `...` . The function should return a numeric value representing the test result.\n`...` | Additional parameters to be passed to the `test_function` .\n\n\n#### Description\n\nThis function performs an asymmetric pairwise test for categories using a user-defined `test_function` .\n\n\n#### Details\n\nThe function calculates the test results for each unique combination of categories using the specified\n `test_function` . The resulting table is asymmetric, containing the test results for comparisons\n from the rows to the columns.\n\n\n#### Seealso\n\n[`outer`](#outer) , [`Vectorize`](#vectorize)\n\n\n#### Value\n\nA data frame representing the results of the asymmetric pairwise tests between categories.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Define a custom test function\ncustom_test_function <- function(x, y) {\n# Your test logic here\n# Return a numeric result\nreturn(mean(x) - mean(y))\n}\n\n# Perform an asymmetric pairwise test\nresult <- lfa_run_test_asymmetric(your_data, \"numeric_column\", \"category_column\", custom_test_function)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_run_test_asymmetric(data, data_column, category_column, test_function, ...)\n```\n:::\n\n\n\n### `lfa_run_test_symmetric`\n\nSymmetric Pairwise Test for Categories\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`data` | A data frame containing the relevant columns.\n`data_column` | A character string specifying the column containing the numerical data.\n`category_column` | A character string specifying the column containing the categorical variable.\n`test_function` | A function used to perform the pairwise test between two sets of data. It should accept two vectors of numeric data and additional parameters specified by `...` . The function should return a numeric value representing the test result.\n`...` | Additional parameters to be passed to the `test_function` .\n\n\n#### Description\n\nThis function performs a symmetric pairwise test for categories using a user-defined `test_function` .\n\n\n#### Details\n\nThe function calculates the test results for each unique combination of categories using the specified\n `test_function` . The resulting table is symmetric, containing the test results for comparisons\n from the rows to the columns. The upper triangle of the matrix is filled with `NA` to avoid duplicate results.\n\n\n#### Seealso\n\n[`outer`](#outer) , [`Vectorize`](#vectorize)\n\n\n#### Value\n\nA data frame representing the results of the symmetric pairwise tests between categories.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Define a custom test function\ncustom_test_function <- function(x, y) {\n# Your test logic here\n# Return a numeric result\nreturn(mean(x) - mean(y))\n}\n\n# Perform a symmetric pairwise test\nresult <- lfa_run_test_symmetric(your_data, \"numeric_column\", \"category_column\", custom_test_function)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_run_test_symmetric(data, data_column, category_column, test_function, ...)\n```\n:::\n\n\n\n### `lfa_save_all_neighbours`\n\nSave Neighbors for All Areas\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`n` | The number of nearest trees to find for each tree (default is 100).\n\n\n#### Description\n\nThis function iterates through all detection areas, finds the n nearest trees for each tree,\n and saves the result to a GeoPackage file for each area.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Save neighbors for all areas with default value (n=100)\nlfa_save_all_neighbours()\n\n# Save neighbors for all areas with a specific value of n (e.g., n=50)\nlfa_save_all_neighbours(n = 50)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_save_all_neighbours(n = 100)\n```\n:::\n\n\n\n### `lfa_segmentation`\n\nSegment the elements of an point cloud by trees\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`ctg` | An LASCatalog object. If not null, it will perform the actions on this object, if NULL inferring the catalog from the tile_location\n`tile_location` | A tile_location type object holding the information about the location of the catalog. This is used to save the catalog after processing too.\n\n\n#### Author\n\nJakob Danel\n\n\n#### Description\n\nThis function will try to to divide the hole point cloud into unique trees.\n Therefore it is assigning for each chunk of the catalog a `treeID` for each\n point. Therefore the algorithm uses the `li2012` implementation with the\n following parameters: `li2012(dt1 = 2, dt2 = 3, R = 2, Zu = 10, hmin = 5, speed_up = 12)` \n NOTE : The operation is in place and can not be reverted, the old values\n of the point cloud will be deleted!\n\n\n#### Value\n\nA catalog where each chunk has additional `treeID` values indicating the belonging tree.\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_segmentation(ctg, tile_location)\n```\n:::\n\n\n\n### `lfa_set_flag`\n\nSet a flag to indicate the completion of a specific process.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`flag_name` | A character string specifying the name of the flag file. It should be a descriptive and unique identifier for the process being flagged.\n\n\n#### Description\n\nThis function creates a hidden flag file at a specified location within the working directory to indicate that a particular processing step has been completed. If the flag file already exists, a warning is issued.\n\n\n#### Value\n\nThis function does not have a formal return value.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Set the flag for a process named \"data_processing\"\nlfa_set_flag(\"data_processing\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_set_flag(flag_name)\n```\n:::\n\n\n\n", + "markdown": "---\ntitle: \"Forest Data Analysis Report\"\noutput:\n pdf_document:\n latex_engine: xelatex\ntoc: true\ntoc-depth: 2\ntoc-title: Contents\nnumber-sections: true\nnumber-depth: 3\ndate: today\nauthor:\n - name: Jakob Danel\n email: jakob.danel@uni-muenster.de\n url: https://github.com/jakobdanel\n affiliations:\n - name: Universität Münster\n city: Münster\n country: Germany\n - name: Federick Bruch\n email: f_bruc03@uni-muenster.de\n url: https://www.uni-muenster.de/Geoinformatics/institute/staff/index.php/351/Frederick_Bruch\n affiliations:\n - name: Universität Münster\n city: Münster\n country: Germany\nbibliography: references.bib\nexecute-dir: .. \nprefer-html: true\n---\n\n\n# Introduction\n\nThis report documents the analysis of forest data for different tree species.\n\n# Methods\n\n## Data acquisition\n\nOur primary objective is to identify patches where one tree species exhibits a high level of dominance, striving to capture monocultural stands within the diverse forests of Nordrhein-Westfalia (NRW). Recognizing the practical challenges of finding true monocultures, we aim to identify patches where one species is highly dominant, enabling meaningful comparisons across different species.\n\nThe study is framed within the NRW region due to the availability of an easily accessible dataset. Our focus includes four prominent tree species in NRW: oak, beech, spruce, and pine, representing the most prevalent species in the region. To ensure the validity of our findings, we derive three patches for each species, thereby confirming that observed variables are characteristic of a particular species rather than a specific patch. Each patch is carefully selected to encompass an area of approximately 50-100 hectares and contain between 5,000 and 10,000 trees. Striking a balance between relevance and manageability, these patches avoid excessive size to enhance the likelihood of capturing varied species mixes and ensure compatibility with local hardware.\n\nSpecific Goals:\n\n1. Retrieve patches with highly dominant tree species.\n2. Minimize or eliminate the presence of human-made structures within the selected patches.\n\nTo achieve our goals, we utilized the waldmonitor dataset [@welle2014] and the map provided by [@Blickensdoerfer2022], both indicating dominant tree species in NRW. We identified patches of feasible size where both sources predicted the presence of a specific species. Further validation involved examining sentinel images of these forest regions to assess the evenness of structures, leaf color distribution, and the absence of significant human-made structures such as roads or buildings. The subsequent preprocessing steps, detailed in the following subsection, involved refining our selected patches and deriving relevant variables, such as tree distribution and density, to ensure that the chosen areas align with the desired research domains.\n\n## Preprocessing\n::: {.cell}\n\n:::\n\n\nIn this research study, the management and processing of a large dataset are crucial considerations. The dataset's substantial size necessitates careful maintenance to ensure efficient handling. Furthermore, the data should be easily processable and editable to facilitate necessary corrections and precalculations within the context of our research objectives. To achieve our goals, we have implemented a framework that automatically derives data based on a shapefile, delineating areas of interest. The processed data and results of precalculations are stored in a straightforward manner to enhance accessibility. Additionally, we have designed functions that establish a user-friendly interface, enabling the execution of algorithms on subsets of the data, such as distinct species. These interfaces are not only directly callable by users but can also be integrated into other functions to automate processes. The overarching aim is to streamline the entire preprocessing workflow using a single script, leveraging only the shapefile as a basis. This subsection details the accomplishments of our R-package in realizing these goals, outlining the preprocessing steps undertaken and justifying their necessity in the context of our research.\n\nThe data are stored in a data subdirectory of the root directory in the format `species/location-name/tile-name`. To automate the matching of areas of interest with the catalog from the Land NRW[^1], we utilize the intersecting tool developed by Heisig[^2]. This tool, allows for the automatic retrieval and placement of data downloaded from the Land NRW catalog. To enhance data accessibility, we have devised an object that incorporates species, location name, and tile name (the NRW internal identifier) for each area This object facilitates the specification of the area to be processed. Additionally, we have defined an initialization function that downloads all tiles, returning a list of tile location objects for subsequent processing. A pivotal component of the package's preprocessing functionality is the map function, which iterates over a list of tile locations (effectively the entire dataset) and accepts a processing function as an argument. The subsequent paragraph outlines the specific preprocessing steps employed, all of which are implemented within the mapping function.\n\nTo facilitate memory-handling capabilities, each of the tiles, where one area can span multiple tiles, has been split into manageable chunks. We employed a 50x50m size for each tile, resulting in the division of original 1km x 1km files into 400 tiles. These tiles are stored in our directory structure, with each tile housed in a directory named after its tile name and assigned an id as the filename. Implementation-wise, the `lidr::catalog_retile` function was instrumental in achieving this segmentation. The resulting smaller chunks allow for efficient iteration during subsequent preprocessing steps.\n\nThe next phase involves reducing our data to the actual size by intersecting the tiles with the defined area of interest. Using the `lidR::merge_spatial` function, we intersect the area derived from the shapefile, removing all point cloud items outside this region. Due to our tile-wise approach, empty tiles may arise, and in such cases, those tiles are simply deleted.\n\nFollowing the size reduction to our dataset, the next step involves correcting the `z` values. The `z` values in the data are originally relative to the ellipsoid used for referencing, but we require them to be relative to the ground. To achieve this, we utilize the `lidR::tin` function, which extrapolates a convex hull between all ground points (classified by the data provider) and calculates the z value based on this structure.\n\nSubsequently, we aim to perform segmentation for each distinct tree, marking each item of the point cloud with a tree ID. We employ the algorithm described by @li2012, using parameters `li2012(dt1 = 2, dt2 = 3, R = 2, Zu = 10, hmin = 5, speed_up = 12)`. The meanings of these parameters are elucidated in Li et al.'s work [@li2012].\n\nFinally, the last preprocessing step involves individual tree detection, seeking a single `POINT` object for each tree. The `lidR::lmf` function, an implementation of the tree data using a local maximum approach, is utilized for this purpose [@popescu2004]. The results are stored in GeoPackage files within our data structure.\n\nSee @sec-appendix-preprocessing for the implementation of the preprocessing.\n\n[^1]: https://www.opengeodata.nrw.de/produkte/geobasis/hm/3dm_l_las/3dm_l_las/, last visited 7th Dec 2023\n[^2]: https://github.com/joheisig/GEDIcalibratoR, last visited 7th Dec 2023\n\n## Analysis of different distributions\n\nAnalysis of data distributions is a critical aspect of our research, with a focus on comparing two or more distributions. Our objective extends beyond evaluating the disparities between species; we also aim to assess differences within a species. To gain a comprehensive understanding of the data, we employ various visualization techniques, including histograms, density functions, and box plots.\n\nIn tandem with visualizations, descriptive statistics, such as means, standard errors, and quantiles, are leveraged to provide key insights into the central tendency and variability of the data.\n\nFor a more quantitative analysis of distribution dissimilarity, statistical tests are employed. The Kullback-Leibler (KL) difference serves as a measure to compare the similarity of a set of distributions. This involves converting distributions into their density functions, with the standard error serving as the bandwidth. The KL difference is calculated for each pair of distributions, as it is asymmetric. For the two distributions the KL difference is defined as following [@kullback1951kullback]:\n\n$$\nD_{KL}(P \\, \\| \\, Q) = \\sum_i P(i) \\log\\left(\\frac{P(i)}{Q(i)}\\right)\n$$\n\nTo obtain a symmetric score, the Jensen-Shannon Divergence (JSD) is utilized [@grosse2002analysis], expressed by the formula:\n\n$$\nJS(P || Q) = \\frac{1}{2} * KL(P || M) + \\frac{1}{2} * KL(Q || M)\n$$\nHere, $M = \\frac{1}{2} * (P + Q)$. The JSD provides a balanced measure of dissimilarity between distributions [@Brownlee2019Calculate]. For comparing the different scores to each other, we will use averages.\n\nAdditionally, the Kolmogorov-Smirnov Test is implemented to assess whether two distributions significantly differ from each other. This statistical test offers a formal evaluation of the dissimilarity between empirical distribution functions.\n\n\n# Results\n::: {.cell}\n\n:::\n\n## Researched areas\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlibrary(ggplot2)\nsf::sf_use_s2(FALSE)\npatches <- sf::read_sf(\"research_areas.shp\") |> sf::st_centroid()\n\nde <- sf::read_sf(\"results/results/states_de/Bundesländer_2017_mit_Einwohnerzahl.shp\") # Source: https://hub.arcgis.com/datasets/esri-de-content::bundesl%C3%A4nder-2017-mit-einwohnerzahl/explore?location=51.099647%2C10.454033%2C7.43\nnrw <- de[5,] |> sf::st_geometry()\n\n\nggplot() + geom_sf(data = nrw) + \n geom_sf(data = patches, mapping = aes(col = species))\n```\n\n::: {.cell-output-display}\n![Locations of the different patches with the dominant species for that patch. The patches centroids are displayed on a basemap describing the borders from NRW.](report_files/figure-html/fig-patches-nrw-1.png){#fig-patches-nrw width=672}\n:::\n:::\nWe draw three patches for each species from different regions (see @tbl-summary-researched-areas). We download the LiDAR data for those patches and runned all preprocessing steps as described. We than checked with certain derived parameters (e.g. tree heights, tree distributions or tree density) that all patches contain valid forest data. In that step we discovered, that in one patch some forest clearance took place in the near past. This patch was removed from the dataset and was replaced with a new one. \n\nIn our research, drawing patches evenly distributed across Nordrhein-Westfalia is inherently constrained by natural factors. Consequently, the patches for oak and pine predominantly originate from the Münsterland region, as illustrated in [@fig-patches-nrw]. For spruce, the patches were derived from Sauerland, reflecting the prevalence of spruce forests in this specific region within NRW, as corroborated by Welle et al. [@welle2014] and Blickensdörfer et al. [@Blickensdoerfer2022]. Beech patches, on the other hand, were generated from diverse locations within NRW. Across all patches, no human-made objects were identified, with the exception of small paths for pedestrians and forestry vehicles.\n\nThe distribution of area and detections is notable for each four species. Beech covers 69,791.9 hectares with a total of 5,954 detections, oak spans 63,232.49 hectares with 5,354 detections, pine extends across 72,862.4 hectares with 8,912 detections, and spruce encompasses 57,940.02 hectares with 8,619 detections. Both the amount of detections and the corresponding area exhibit a relatively uniform distribution across the diverse patches, as summarized in @tbl-summary-researched-areas. \n\nWith the selected dataset described, we intentionally chose three patches for each four species that exhibit a practical and usable size for our research objectives. These carefully chosen patches align with the conditions essential for our study, providing comprehensive and representative data for in-depth analysis and meaningful insights into the characteristics of each tree species within the specified areas.\n\n\n::: {#tbl-summary-researched-areas .cell tbl-cap='Summary of researched patches grouped by species, with their location, area and the amount of detected trees.'}\n\n```{.r .cell-code code-fold=\"true\"}\nshp <- sf::read_sf(\"research_areas.shp\")\ntable <- lfa::lfa_get_all_areas()\n\nsf::sf_use_s2(FALSE)\nfor (row in 1:nrow(table)) {\n area <-\n dplyr::filter(shp, shp$species == table[row, \"specie\"] &\n shp$name == table[row, \"area\"])\n area_size <- area |> sf::st_area()\n point <- area |> sf::st_centroid() |> sf::st_coordinates()\n table[row,\"point\"] <- paste0(\"(\",round(point[1], digits = 4),\", \",round(point[2],digits = 4),\")\")\n \n table[row, \"area_size\"] = round(area_size,digits = 2) #paste0(round(area_size,digits = 2), \" m²\")\n \n amount_det <- nrow(lfa::lfa_get_detection_area(table[row, \"specie\"], table[row, \"area\"]))\n if(is.null(amount_det)){\n cat(nrow(lfa::lfa_get_detection_area(table[row, \"specie\"], table[row, \"area\"])),table[row, \"specie\"],table[row, \"area\"])\n }\n table[row, \"amount_detections\"] = amount_det\n \n # table[row, \"specie\"] <- lfa::lfa_capitalize_first_char(table[row,\"specie\"])\n table[row, \"area\"] <- lfa::lfa_capitalize_first_char(table[row,\"area\"])\n }\ntable$area <- gsub(\"_\", \" \", table$area)\ntable$area <- gsub(\"ue\", \"ü\", table$area)\ntable = table[,!names(table) %in% c(\"specie\")]\n\nknitr::kable(table, \"html\", col.names = c(\"Patch Name\",\"Location\",\"Area size (m²)\",\"Amount tree detections\" ), caption = NULL, digits = 2, escape = TRUE) |>\n kableExtra::kable_styling(\n bootstrap_options = c(\"striped\", \"hold_position\", \"bordered\",\"responsive\"),\n stripe_index = c(1:3,7:9),\n full_width = FALSE\n ) |>\n kableExtra::pack_rows(\"Beech\", 1, 3) |>\n kableExtra::pack_rows(\"Oak\", 4, 6) |>\n kableExtra::pack_rows(\"Pine\", 7, 9) |>\n kableExtra::pack_rows(\"Spruce\", 10, 12) |>\n kableExtra::column_spec(1, bold = TRUE)\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n \n \n \n \n \n \n \n \n\n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Patch Name Location Area size (m²) Amount tree detections
Beech
Bielefeld brackwede (8.5244, 51.9902) 161410.57 1443
Billerbeck (7.3273, 51.9987) 185887.25 1732
Wülfenrath (7.0769, 51.2917) 350621.21 2779
Oak
Hamm (7.8618, 51.6639) 269397.22 2441
Münster (7.6187, 51.9174) 164116.61 1270
Rinkerode (7.6744, 51.8598) 198811.09 1643
Pine
Greffen (8.1697, 51.9913) 49418.81 513
Mesum (7.5403, 52.2573) 405072.85 5031
Telgte (7.7816, 52.0024) 274132.34 3368
Spruce
Brilon (8.5352, 51.4084) 211478.20 3342
Oberhundem (8.1861, 51.0909) 151895.53 2471
Osterwald (8.3721, 51.2151) 216026.43 2806
\n\n`````\n:::\n:::\n\n\n\n\n\n## Distribution of the tree heights\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndetections <- lfa::lfa_get_detections()\n```\n:::\n\nIn this study, we scrutinize the distribution of tree heights, focusing initially on the density distribution to unravel the nuances across various tree species. Notably, our examination reveals distinctive patterns, with Oak and Pine exhibiting significantly steeper peaks in their density curves compared to Beech and Spruce. While all species present unique density curves, a commonality emerges—each curve is characterized by a single peak, except for the intriguing exception observed in Telgte. Taking Beech as an illustrative example, our findings indicate a notable shift in the peak to a considerably higher extent. The varinace in the density curves indicating that an differencation between species only with the help oof tree height values could be difficult.\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_density_plots(detections, value_column = \"Z\", category_column1 = \"area\", category_column2 = \"specie\", title = \"Density of the height distributions\", xlims = c(0,50))\n```\n\n::: {.cell-output-display}\n![Density of the height distribitions of the detectected trees. Splitted by the different researched areas and grouped by the dominant specie in this area.](report_files/figure-html/fig-density-z-1.png){#fig-density-z width=672}\n:::\n:::\n\nTo have a deeper look into the distributions of those `Z`-values we will now also have a look into the boxplots of the height distrubutions in the different areas.\nNoteworthy observations include the presence of outliers beyond the extended range of the Whisker Antennas ($1.5*\\text{IQR}$) in all datasets. Of particular interest is the Rinkerode dataset, which exhibits a higher prevalence of outliers in the upper domain. Anomalies in this dataset are attributed to potential inaccuracies, urging a critical examination of data integrity. A pairwise examination of Oak and Pine species indicates higher mean heights for Oak compared to Pine. This insight underscores the significance of species-specific attributes in shaping overall height distributions. Further exploration into the factors contributing to these mean differences enhances our understanding of the unique characteristics inherent to each species. Contrary to expectations, the spread within a particular species does not exhibit significant divergence from the spread observed between different species. This finding suggests that while species-specific traits play a crucial role in shaping height distributions, certain overarching factors may contribute to shared patterns across diverse tree populations.\n\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_boxplot(detections, value_column = \"Z\", category_column1 = \"area\", category_column2 = \"specie\", title = \"Boxplots of the height distributions\")\n```\n\n::: {.cell-output-display}\n![Boxplots of the height distribitions of the detectected trees. Splitted by the different researched areas and grouped by the dominant specie in this area.](report_files/figure-html/fig-boxplot-z-1.png){#fig-boxplot-z width=672}\n:::\n:::\n\n\n\nOur examination of Kullback-Leibler Divergence (KLD) and Jensen-Shannon Divergence (JSD) metrics reveals low mean values (KLD: 5.252696, JSD: 2.246663) across different species, indicating overall similarity in tree species height distributions. However, within specific species, particularly Pine, higher divergence values (see @tbl-z-values-kld-pine and @tbl-z-values-jsd-pine) suggest significant intraspecific differences.\n\nNotably, the Spruce species consistently demonstrates low divergence values across all tested areas, implying a high level of explainability. This finding highlights tree height as a reliable indicator for detecting Spruce trees, indicating its potential for accurate species identification in diverse forest ecosystems.\n\n## Distribution of number of returns per detected tree.\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndata <- sf::st_read(\"data/tree_properties.gpkg\")\nneighbors <- lfa::lfa_get_neighbor_paths() |> lfa::lfa_combine_sf_obj(lfa::lfa_get_all_areas())\ndata = sf::st_join(data,neighbors, join = sf::st_within)\n```\n:::\nExamining the distribution of LiDAR returns per tree is the focus of our current investigation. Initial analysis involves the study of density graphs representing the distribution of LiDAR returns. The density curves for each species exhibit distinct peaks corresponding to their respective species, providing a clear differentiation in LiDAR return patterns. Notably, there is an exception observed in the Brilon patch (Spruce), where the curve deviates, possibly indicative of variations in forest age. A noteworthy trend is the divergent shape of density curves between coniferous and deciduous trees. Conifers exhibit steeper curves, indicating lower density for higher return values compared to deciduous trees. This disparity underscores the potential of LiDAR data to distinguish between tree types based on return density characteristics. In the case of Beech trees, the peaks' heights vary among different curves, suggesting nuanced variations within the species. Despite these differences, all species consistently peak in similar regions, emphasizing the overarching similarities in LiDAR return patterns across diverse tree species.\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_density_plots(data, value_column = \"number_of_returns\", category_column1 = \"area\", category_column2 = \"specie\", title = \"Density of the distribution of LiDAR returns per individual tree\", xlims = c(0,10000))\n```\n\n::: {.cell-output-display}\n![Density of the amount of LiDAR returns per detectected tree. Splitted by the different researched areas and grouped by the dominant specie in this area.](report_files/figure-html/fig-density-number-returns-1.png){#fig-density-number-returns width=672}\n:::\n:::\n\nCurrently, our investigation focuses on boxplots representing each patch. We observe significant size variations among plots within the same species. Notably, numerous outliers are present above the box in each patch. For Pines, the boxes exhibit a notable similarity. However, the box for Brilon is entirely shifted from other boxes associated with patches featuring Spruce forest.\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlfa::lfa_create_boxplot(data, value_column = \"number_of_returns\", category_column1 = \"area\", category_column2 = \"specie\", title = \"Boxplots of the distribution of LiDAR returns per individual tree\")\n```\n\n::: {.cell-output-display}\n![Boxplots of the the amount of LiDAR returns per detectected tree. Splitted by the different researched areas and grouped by the dominant specie in this area.](report_files/figure-html/fig-boxplot-number-returns-1.png){#fig-boxplot-number-returns width=672}\n:::\n:::\n\nOverall, our analysis reveals very low results for both Kullback-Leibler Divergence (KLD) and Jensen-Shannon Divergence (JSD) metrics across different species. Within species, there is high explainability observed for the different LiDAR return curves between patches.\n\nThis suggests that the number of returns alone may not be a robust predictor for identifying the dominant species in a forest. However, the curves indicate a clear potential for distinguishing between conifers (Pine and Spruce) and deciduous trees (Beech and Oak) based on the number of returns. This observation is further supported by the JSD scores, as detailed in @tbl-number-of-returns-jsd_specie.\n\n## Density of forest patches\nExamining densities provides valuable insights into identifying the dominant species within patches. Spruce stands out as the densest species, surpassing all other patches. Following closely in density is Pine, as depicted in Figure 1 (@fig-density-bar).\n\nBeech and Oak exhibit similar density levels, with Beech consistently denser across all patches. When comparing the highest density patches for each species, Beech consistently outpaces Oak. While Oak is slightly less dense overall ($8.354499 \\times 10^{-3} \\frac{1}{m^2}$) than Beech ($8.727781 \\times 10^{-3} \\frac{1}{m^2}$), the distinction in density remains noticeable.\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nlibrary(units)\nlfa::lfa_calculate_patch_density() |>\n lfa::lfa_create_grouped_bar_plot(grouping_var = \"species\", value_col = \"density\", label_col = \"name\")\n```\n\n::: {.cell-output-display}\n![Barplot of the densitys of all patches (#detected trees/area of patch). Colorized by the dominant tree species of each patch.](report_files/figure-html/fig-density-bar-1.png){#fig-density-bar width=672}\n:::\n:::\nIn summary, our findings indicate that the density of each patch proves highly effective in distinguishing dominant species. Furthermore, the differentiation between conifers (Pine and Spruce) and deciduous trees (Beech and Oak) based on density aligns with patterns observed in the number of return points per detected tree. While distinguishing within conifers is straightforward, discerning between deciduous tree species, especially Beech and Oak, is possible but poses a moderate challenge.\n\n\n\n\n\n\n\n\n# References\n\n::: {#refs}\n:::\n\n# Appendix\n## Script which can be used to do all preprocessing {#sec-appendix-preprocessing}\n\n::: {.cell}\n\n:::\n\n\nLoad the file with the research areas\n::: {.cell}\n\n```{.r .cell-code}\nsf <- sf::read_sf(here::here(\"research_areas.shp\"))\nprint(sf)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nSimple feature collection with 12 features and 3 fields\nGeometry type: POLYGON\nDimension: XY\nBounding box: xmin: 7.071625 ymin: 51.0895 xmax: 8.539877 ymax: 52.25983\nGeodetic CRS: WGS 84\n# A tibble: 12 × 4\n id species name geometry\n \n 1 1 oak rinkerode ((7.678922 51.85789, 7.675446 51.85752, 7.…\n 2 2 oak hamm ((7.858955 51.66699, 7.866444 51.66462, 7.…\n 3 3 oak muenster ((7.618908 51.9154, 7.617384 51.9172, 7.61…\n 4 4 pine greffen ((8.168691 51.98965, 8.167178 51.99075, 8.…\n 5 5 pine telgte ((7.779728 52.00662, 7.781616 52.00662, 7.…\n 6 6 pine mesum ((7.534424 52.25499, 7.53378 52.25983, 7.5…\n 7 7 beech bielefeld_brackwede ((8.524749 51.9921, 8.528418 51.99079, 8.5…\n 8 8 beech wuelfenrath ((7.071625 51.29256, 7.072311 51.29334, 7.…\n 9 9 beech billerbeck ((7.324729 51.99783, 7.323548 51.99923, 7.…\n10 11 spruce brilon ((8.532195 51.41029, 8.535027 51.41064, 8.…\n11 12 spruce osterwald ((8.369328 51.21693, 8.371238 51.21718, 8.…\n12 10 spruce oberhundem ((8.18082 51.08999, 8.180868 51.09143, 8.1…\n```\n:::\n:::\n\n\nInit the project\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(lfa)\nsf::sf_use_s2(FALSE)\nlocations <- lfa_init(\"research_areas.shp\")\n```\n:::\n\nDo all of the prprocessing steps\n::: {.cell}\n\n```{.r .cell-code}\nlfa_map_tile_locations(locations,retile,check_flag = \"retile\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNo further processing: flag retile is set!Function is already computed, no further computings here\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\nNULL\n```\n:::\n\n```{.r .cell-code}\nlfa_map_tile_locations(locations, lfa_intersect_areas, ctg = NULL, areas_sf = sf,check_flag = \"intersect\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNo further processing: flag intersect is set!Function is already computed, no further computings here\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\nNULL\n```\n:::\n\n```{.r .cell-code}\nlfa_map_tile_locations(locations, lfa_ground_correction, ctg = NULL,check_flag = \"z_correction\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNo further processing: flag z_correction is set!Function is already computed, no further computings here\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\nNULL\n```\n:::\n\n```{.r .cell-code}\nlfa_map_tile_locations(locations, lfa_segmentation, ctg = NULL,check_flag = \"segmentation\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNo further processing: flag segmentation is set!Function is already computed, no further computings here\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\nNULL\n```\n:::\n\n```{.r .cell-code}\nlfa_map_tile_locations(locations, lfa_detection, catalog = NULL, write_to_file = TRUE,check_flag = \"detection\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nNo further processing: flag detection is set!Function is already computed, no further computings here\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\nNULL\n```\n:::\n:::\n\n\n## Quantitative Results\n### Distribution of Z-Values\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndata <- lfa::lfa_get_detections()\nvalue_column <- \"Z\"\n```\n:::\n\n\n\n#### Kullback-Leibler-Divergence\n\n\n\n::: {#tbl-z-values-kld_specie .cell tbl-cap='Kullback-Leibler-Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nkld_results_specie <- lfa::lfa_run_test_asymmetric(data,value_column,\"specie\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_specie,\"Kullback-Leibler-Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between species
Beech Oak Pine Spruce
Beech 0.0 13.2 12.5 0.76
Oak 4.2 0.0 3.4 5.02
Pine 2.3 5.6 0.0 3.95
Spruce 2.4 14.7 16.1 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 5.252696\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-kld-beech .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie beech for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\nkld_results_beech <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_beech,\"Kullback-Leibler-Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0.00 0.4 3.1
Billerbeck 0.27 0.0 6.0
Wuelfenrath 1.13 2.4 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 1.473353\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-kld-oak .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie oak for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\nkld_results_oak <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_oak,\"Kullback-Leibler-Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0.0 2.1 16
Muenster 0.4 0.0 17
Rinkerode 7.6 17.8 0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 6.779863\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-kld-pine .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie pine for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\nkld_results_pine <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_pine,\"Kullback-Leibler-Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0.00 0.74 16
Mesum 0.43 0.00 18
Telgte 3.87 6.82 0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 5.129383\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-kld-spruce .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie spruce for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\nkld_results_spruce <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_spruce,\"Kullback-Leibler-Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0.000 0.092 1.7
Oberhundem 0.081 0.000 2.1
Osterwald 1.521 2.178 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.8509258\n```\n:::\n:::\n\n\n\n\n#### Jensen-Shannon Divergence\n\n\n\n::: {#tbl-z-values-jsd_specie .cell tbl-cap='Jensen-Shannon Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\njsd_results_specie <- lfa::lfa_run_test_symmetric(data,value_column,\"specie\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_specie,\"Jensen-Shannon Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between species
Beech Oak Pine Spruce
Beech 0 4.5 4.6 2.4
Oak NA 0.0 3.9 6.1
Pine NA NA 0.0 7.1
Spruce NA NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 2.246663\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-jsd-beech .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie beech for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\njsd_results_beech <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_beech,\"Jensen-Shannon Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0 1.1 3.3
Billerbeck NA 0.0 4.9
Wuelfenrath NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 1.10555\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-jsd-oak .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie oak for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\njsd_results_oak <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_oak,\"Jensen-Shannon Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0 1.6 6.5
Muenster NA 0.0 6.4
Rinkerode NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 1.692942\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-jsd-pine .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie pine for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\njsd_results_pine <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_pine,\"Jensen-Shannon Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0 3.1 12
Mesum NA 0.0 10
Telgte NA NA 0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 2.956354\n```\n:::\n:::\n\n\n\n\n::: {#tbl-z-values-jsd-spruce .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie spruce for the atrribute z-values'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\njsd_results_spruce <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_spruce,\"Jensen-Shannon Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0 0.31 4.0
Oberhundem NA 0.00 5.5
Osterwald NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 1.100383\n```\n:::\n:::\n\n\n\n\n### Nearest Neighbours\n#### Distribution of nearest neighbor distances\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndata <- lfa::lfa_combine_sf_obj(lfa::lfa_get_neighbor_paths(),lfa::lfa_get_all_areas())\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/bielefeld_brackwede/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1443 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 466999.8 ymin: 5759839 xmax: 467617.1 ymax: 5760261\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/billerbeck/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1732 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 384890.8 ymin: 5761918 xmax: 385590.9 ymax: 5762478\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/wuelfenrath/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2779 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 365546.3 ymin: 5683711 xmax: 366356.1 ymax: 5684321\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/hamm/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2441 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 420953.3 ymin: 5723884 xmax: 421596 ymax: 5724609\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/muenster/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1270 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 404615.6 ymin: 5752535 xmax: 405396.8 ymax: 5752971\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/rinkerode/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1643 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 408428.2 ymin: 5746021 xmax: 409014.8 ymax: 5746511\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/greffen/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 513 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442816.1 ymin: 5760217 xmax: 443148.9 ymax: 5760567\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/mesum/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 5031 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 399930.6 ymin: 5790412 xmax: 400969.7 ymax: 5790950\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/telgte/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3368 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 416135.1 ymin: 5761663 xmax: 416697.1 ymax: 5762477\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/brilon/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3342 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 467305.7 ymin: 5695055 xmax: 467996.9 ymax: 5695593\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/oberhundem/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2471 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442631.7 ymin: 5660096 xmax: 443309.5 ymax: 5660502\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/osterwald/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2806 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 455822 ymin: 5673761 xmax: 456483.2 ymax: 5674162\nProjected CRS: ETRS89 / UTM zone 32N\n```\n:::\n\n```{.r .cell-code code-fold=\"true\"}\nvalue_column <- \"Neighbor_1\"\n```\n:::\n\n\n\n##### Kullback-Leibler-Divergence\n\n\n\n::: {#tbl-nearest-neighbor-1-kld_specie .cell tbl-cap='Kullback-Leibler-Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nkld_results_specie <- lfa::lfa_run_test_asymmetric(data,value_column,\"specie\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_specie,\"Kullback-Leibler-Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between species
Beech Oak Pine Spruce
Beech 0.000 0.029 0.40 3.3
Oak 0.031 0.000 0.25 3.9
Pine 0.213 0.128 0.00 4.9
Spruce 2.735 3.199 4.52 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 1.477983\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-kld-beech .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\nkld_results_beech <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_beech,\"Kullback-Leibler-Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0.000 0.35 0.051
Billerbeck 0.380 0.00 0.138
Wuelfenrath 0.059 0.15 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1249588\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-kld-oak .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\nkld_results_oak <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_oak,\"Kullback-Leibler-Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0.000 0.079 0.078
Muenster 0.092 0.000 0.019
Rinkerode 0.086 0.020 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.04167636\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-kld-pine .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\nkld_results_pine <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_pine,\"Kullback-Leibler-Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0.00 0.495 0.258
Mesum 0.48 0.000 0.098
Telgte 0.22 0.076 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1812239\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-kld-spruce .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\nkld_results_spruce <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_spruce,\"Kullback-Leibler-Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0.00 0.67 5.1
Oberhundem 0.41 0.00 7.2
Osterwald 6.09 6.23 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 2.863587\n```\n:::\n:::\n\n\n\n\n##### Jensen-Shannon Divergence\n\n\n\n::: {#tbl-nearest-neighbor-1-jsd_specie .cell tbl-cap='Jensen-Shannon Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\njsd_results_specie <- lfa::lfa_run_test_symmetric(data,value_column,\"specie\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_specie,\"Jensen-Shannon Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between species
Beech Oak Pine Spruce
Beech 0 0.22 2.1 9.3
Oak NA 0.00 1.3 10.6
Pine NA NA 0.0 14.7
Spruce NA NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 2.470051\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-jsd-beech .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\njsd_results_beech <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_beech,\"Jensen-Shannon Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0 2.2 0.39
Billerbeck NA 0.0 0.85
Wuelfenrath NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.5042359\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-jsd-oak .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\njsd_results_oak <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_oak,\"Jensen-Shannon Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0 0.57 0.61
Muenster NA 0.00 0.17
Rinkerode NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1803836\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-jsd-pine .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\njsd_results_pine <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_pine,\"Jensen-Shannon Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0 3.6 1.89
Mesum NA 0.0 0.68
Telgte NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.891592\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-1-jsd-spruce .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-1'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\njsd_results_spruce <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_spruce,\"Jensen-Shannon Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0 4.1 16
Oberhundem NA 0.0 18
Osterwald NA NA 0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 4.471632\n```\n:::\n:::\n\n\n#### Distribution of distances to 100th nearest neighbor\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndata <- lfa::lfa_combine_sf_obj(lfa::lfa_get_neighbor_paths(),lfa::lfa_get_all_areas())\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/bielefeld_brackwede/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1443 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 466999.8 ymin: 5759839 xmax: 467617.1 ymax: 5760261\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/billerbeck/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1732 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 384890.8 ymin: 5761918 xmax: 385590.9 ymax: 5762478\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/wuelfenrath/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2779 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 365546.3 ymin: 5683711 xmax: 366356.1 ymax: 5684321\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/hamm/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2441 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 420953.3 ymin: 5723884 xmax: 421596 ymax: 5724609\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/muenster/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1270 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 404615.6 ymin: 5752535 xmax: 405396.8 ymax: 5752971\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/rinkerode/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1643 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 408428.2 ymin: 5746021 xmax: 409014.8 ymax: 5746511\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/greffen/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 513 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442816.1 ymin: 5760217 xmax: 443148.9 ymax: 5760567\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/mesum/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 5031 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 399930.6 ymin: 5790412 xmax: 400969.7 ymax: 5790950\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/telgte/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3368 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 416135.1 ymin: 5761663 xmax: 416697.1 ymax: 5762477\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/brilon/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3342 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 467305.7 ymin: 5695055 xmax: 467996.9 ymax: 5695593\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/oberhundem/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2471 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442631.7 ymin: 5660096 xmax: 443309.5 ymax: 5660502\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/osterwald/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2806 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 455822 ymin: 5673761 xmax: 456483.2 ymax: 5674162\nProjected CRS: ETRS89 / UTM zone 32N\n```\n:::\n\n```{.r .cell-code code-fold=\"true\"}\nvalue_column <- \"Neighbor_100\"\n```\n:::\n\n\n\n##### Kullback-Leibler-Divergence\n\n\n\n::: {#tbl-nearest-neighbor-100-kld_specie .cell tbl-cap='Kullback-Leibler-Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nkld_results_specie <- lfa::lfa_run_test_asymmetric(data,value_column,\"specie\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_specie,\"Kullback-Leibler-Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between species
Beech Oak Pine Spruce
Beech 0.000 0.194 0.082 0.89
Oak 0.183 0.000 0.063 0.67
Pine 0.084 0.069 0.000 0.86
Spruce 1.083 0.809 1.200 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.3862841\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-kld-beech .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\nkld_results_beech <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_beech,\"Kullback-Leibler-Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0.00 0.12 0.12
Billerbeck 0.14 0.00 0.40
Wuelfenrath 0.12 0.31 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1338066\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-kld-oak .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\nkld_results_oak <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_oak,\"Kullback-Leibler-Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0.00 0.19 0.11
Muenster 0.20 0.00 0.06
Rinkerode 0.11 0.07 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.08182597\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-kld-pine .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\nkld_results_pine <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_pine,\"Kullback-Leibler-Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0.00 0.25 0.51
Mesum 0.20 0.00 0.25
Telgte 0.54 0.26 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.22229\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-kld-spruce .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\nkld_results_spruce <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_spruce,\"Kullback-Leibler-Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0.000 0.05 0.23
Oberhundem 0.046 0.00 0.37
Osterwald 0.276 0.46 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1591879\n```\n:::\n:::\n\n\n\n\n##### Jensen-Shannon Divergence\n\n\n\n::: {#tbl-nearest-neighbor-100-jsd_specie .cell tbl-cap='Jensen-Shannon Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\njsd_results_specie <- lfa::lfa_run_test_symmetric(data,value_column,\"specie\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_specie,\"Jensen-Shannon Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between species
Beech Oak Pine Spruce
Beech 0 0.38 0.14 1.27
Oak NA 0.00 0.30 0.78
Pine NA NA 0.00 1.39
Spruce NA NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.2997233\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-jsd-beech .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\njsd_results_beech <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_beech,\"Jensen-Shannon Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0 0.22 0.21
Billerbeck NA 0.00 0.57
Wuelfenrath NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.124106\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-jsd-oak .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\njsd_results_oak <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_oak,\"Jensen-Shannon Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0 0.34 0.17
Muenster NA 0.00 0.23
Rinkerode NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1007612\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-jsd-pine .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\njsd_results_pine <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_pine,\"Jensen-Shannon Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0 0.45 0.86
Mesum NA 0.00 0.50
Telgte NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.2265055\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-100-jsd-spruce .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-100'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\njsd_results_spruce <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_spruce,\"Jensen-Shannon Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0 0.1 0.57
Oberhundem NA 0.0 0.73
Osterwald NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1613747\n```\n:::\n:::\n\n\n#### Distribution of average nearest neighbor distances\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndata <- lfa::lfa_combine_sf_obj(lfa::lfa_get_neighbor_paths(),lfa::lfa_get_all_areas())\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/bielefeld_brackwede/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1443 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 466999.8 ymin: 5759839 xmax: 467617.1 ymax: 5760261\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/billerbeck/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1732 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 384890.8 ymin: 5761918 xmax: 385590.9 ymax: 5762478\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/beech/wuelfenrath/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2779 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 365546.3 ymin: 5683711 xmax: 366356.1 ymax: 5684321\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/hamm/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2441 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 420953.3 ymin: 5723884 xmax: 421596 ymax: 5724609\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/muenster/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1270 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 404615.6 ymin: 5752535 xmax: 405396.8 ymax: 5752971\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/oak/rinkerode/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 1643 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 408428.2 ymin: 5746021 xmax: 409014.8 ymax: 5746511\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/greffen/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 513 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442816.1 ymin: 5760217 xmax: 443148.9 ymax: 5760567\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/mesum/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 5031 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 399930.6 ymin: 5790412 xmax: 400969.7 ymax: 5790950\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/pine/telgte/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3368 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 416135.1 ymin: 5761663 xmax: 416697.1 ymax: 5762477\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/brilon/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 3342 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 467305.7 ymin: 5695055 xmax: 467996.9 ymax: 5695593\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/oberhundem/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2471 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 442631.7 ymin: 5660096 xmax: 443309.5 ymax: 5660502\nProjected CRS: ETRS89 / UTM zone 32N\nReading layer `neighbours' from data source \n `/home/jakob/gi-master/project-courses/lidar-forest-analysis/src/data/spruce/osterwald/neighbours.gpkg' \n using driver `GPKG'\nSimple feature collection with 2806 features and 102 fields\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: 455822 ymin: 5673761 xmax: 456483.2 ymax: 5674162\nProjected CRS: ETRS89 / UTM zone 32N\n```\n:::\n\n```{.r .cell-code code-fold=\"true\"}\nnames <- paste0(\"Neighbor_\",1:100)\ndata$avg = rowMeans(dplyr::select(as.data.frame(data),names))\nvalue_column <- \"avg\"\n```\n:::\n\n\n\n##### Kullback-Leibler-Divergence\n\n\n\n::: {#tbl-nearest-neighbor-avg-kld_specie .cell tbl-cap='Kullback-Leibler-Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nkld_results_specie <- lfa::lfa_run_test_asymmetric(data,value_column,\"specie\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_specie,\"Kullback-Leibler-Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between species
Beech Oak Pine Spruce
Beech 0.000 0.31 0.065 1.28
Oak 0.302 0.00 0.178 0.83
Pine 0.067 0.17 0.000 1.23
Spruce 1.660 0.92 1.869 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.5552882\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-kld-beech .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\nkld_results_beech <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_beech,\"Kullback-Leibler-Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0.000 0.052 0.50
Billerbeck 0.052 0.000 0.91
Wuelfenrath 0.348 0.612 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.27574\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-kld-oak .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\nkld_results_oak <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_oak,\"Kullback-Leibler-Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0.00 0.166 0.217
Muenster 0.16 0.000 0.031
Rinkerode 0.21 0.037 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.09154318\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-kld-pine .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\nkld_results_pine <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_pine,\"Kullback-Leibler-Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0.00 0.17 0.29
Mesum 0.14 0.00 0.30
Telgte 0.26 0.32 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1637513\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-kld-spruce .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\nkld_results_spruce <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_spruce,\"Kullback-Leibler-Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0.000 0.11 0.29
Oberhundem 0.097 0.00 0.59
Osterwald 0.341 0.75 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.2404004\n```\n:::\n:::\n\n\n\n\n##### Jensen-Shannon Divergence\n\n\n\n::: {#tbl-nearest-neighbor-avg-jsd_specie .cell tbl-cap='Jensen-Shannon Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\njsd_results_specie <- lfa::lfa_run_test_symmetric(data,value_column,\"specie\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_specie,\"Jensen-Shannon Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between species
Beech Oak Pine Spruce
Beech 0 0.73 0.19 2.6
Oak NA 0.00 0.64 1.4
Pine NA NA 0.00 3.0
Spruce NA NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.5999417\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-jsd-beech .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie beech for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\njsd_results_beech <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_beech,\"Jensen-Shannon Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0 0.14 1.0
Billerbeck NA 0.00 1.7
Wuelfenrath NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.3215991\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-jsd-oak .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie oak for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\njsd_results_oak <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_oak,\"Jensen-Shannon Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0 0.41 0.53
Muenster NA 0.00 0.26
Rinkerode NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.1558436\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-jsd-pine .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie pine for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\njsd_results_pine <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_pine,\"Jensen-Shannon Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0 0.44 0.76
Mesum NA 0.00 0.89
Telgte NA NA 0.00
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.2560143\n```\n:::\n:::\n\n\n\n\n::: {#tbl-nearest-neighbor-avg-jsd-spruce .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie spruce for the atrribute nearest-neighbor-avg'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\njsd_results_spruce <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_spruce,\"Jensen-Shannon Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0 0.32 1.1
Oberhundem NA 0.00 1.8
Osterwald NA NA 0.0
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.3713411\n```\n:::\n:::\n\n\n### Distribution of the number of returns\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ndata <- sf::st_read(\"data/tree_properties.gpkg\")\nneighbors <- lfa::lfa_get_neighbor_paths() |> lfa::lfa_combine_sf_obj(lfa::lfa_get_all_areas())\ndata = sf::st_join(data,neighbors, join = sf::st_within)\nvalue_column <- \"number_of_returns\"\n```\n:::\n\n\n\n#### Kullback-Leibler-Divergence\n\n\n\n::: {#tbl-number-of-returns-kld_specie .cell tbl-cap='Kullback-Leibler-Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute number-of-returns'}\n\n```{.r .cell-code code-fold=\"true\"}\nkld_results_specie <- lfa::lfa_run_test_asymmetric(data,value_column,\"specie\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_specie,\"Kullback-Leibler-Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between species
Beech Oak Pine Spruce
Beech 0.000 0.083 0.57 0.049
Oak 0.051 0.000 0.84 0.059
Pine 0.432 0.833 0.00 0.526
Spruce 0.036 0.059 0.54 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.2550987\n```\n:::\n:::\n\n\n\n\n::: {#tbl-number-of-returns-kld-beech .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie beech for the atrribute number-of-returns'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\nkld_results_beech <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_beech,\"Kullback-Leibler-Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0.00 0.15 0.082
Billerbeck 0.21 0.00 0.136
Wuelfenrath 0.13 0.19 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.09985223\n```\n:::\n:::\n\n\n\n\n::: {#tbl-number-of-returns-kld-oak .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie oak for the atrribute number-of-returns'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\nkld_results_oak <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_oak,\"Kullback-Leibler-Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0.00 0.46 0.846
Muenster 0.41 0.00 0.077
Rinkerode 0.81 0.09 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.2994815\n```\n:::\n:::\n\n\n\n\n::: {#tbl-number-of-returns-kld-pine .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie pine for the atrribute number-of-returns'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\nkld_results_pine <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_pine,\"Kullback-Leibler-Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0.00 0.1444 0.1773
Mesum 0.14 0.0000 0.0047
Telgte 0.16 0.0045 0.0000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.07005788\n```\n:::\n:::\n\n\n\n\n::: {#tbl-number-of-returns-kld-spruce .cell tbl-cap='Kullback-Leibler-Divergence between the researched areas which have the dominante specie spruce for the atrribute number-of-returns'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\nkld_results_spruce <- lfa::lfa_run_test_asymmetric(specie,value_column,\"area\",lfa::lfa_kld_from_vec)\nlfa::lfa_generate_result_table_tests(kld_results_spruce,\"Kullback-Leibler-Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Kullback-Leibler-Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0.000 0.04 0.034
Oberhundem 0.041 0.00 0.079
Osterwald 0.045 0.10 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(kld_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.03779495\n```\n:::\n:::\n\n\n\n\n#### Jensen-Shannon Divergence\n\n\n\n::: {#tbl-number-of-returns-jsd_specie .cell tbl-cap='Jensen-Shannon Divergence between the researched species Beech, Oak, Pine and Spruce for the atrribute number-of-returns'}\n\n```{.r .cell-code code-fold=\"true\"}\njsd_results_specie <- lfa::lfa_run_test_symmetric(data,value_column,\"specie\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_specie,\"Jensen-Shannon Divergence between species\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between species
Beech Oak Pine Spruce
Beech 0 3e-04 0.019 0.0014
Oak NA 0e+00 0.021 0.0016
Pine NA NA 0.000 0.0143
Spruce NA NA NA 0.0000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_specie, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.004419638\n```\n:::\n:::\n\n\n\n\n::: {#tbl-number-of-returns-jsd-beech .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie beech for the atrribute number-of-returns'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"beech\",]\njsd_results_beech <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_beech,\"Jensen-Shannon Divergence between areas with beech\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with beech
Bielefeld_brackwede Billerbeck Wuelfenrath
Bielefeld_brackwede 0 0.0035 0.00099
Billerbeck NA 0.0000 0.00554
Wuelfenrath NA NA 0.00000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_beech, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.001314268\n```\n:::\n:::\n\n\n\n\n::: {#tbl-number-of-returns-jsd-oak .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie oak for the atrribute number-of-returns'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"oak\",]\njsd_results_oak <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_oak,\"Jensen-Shannon Divergence between areas with oak\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with oak
Hamm Muenster Rinkerode
Hamm 0 0.0068 0.0128
Muenster NA 0.0000 0.0017
Rinkerode NA NA 0.0000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_oak, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.002747351\n```\n:::\n:::\n\n\n\n\n::: {#tbl-number-of-returns-jsd-pine .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie pine for the atrribute number-of-returns'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"pine\",]\njsd_results_pine <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_pine,\"Jensen-Shannon Divergence between areas with pine\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with pine
Greffen Mesum Telgte
Greffen 0 0.0035 0.00458
Mesum NA 0.0000 0.00037
Telgte NA NA 0.00000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_pine, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.001130537\n```\n:::\n:::\n\n\n\n\n::: {#tbl-number-of-returns-jsd-spruce .cell tbl-cap='Jensen-Shannon Divergence between the researched areas which have the dominante specie spruce for the atrribute number-of-returns'}\n\n```{.r .cell-code code-fold=\"true\"}\nspecie <- data[data$specie==\"spruce\",]\njsd_results_spruce <- lfa::lfa_run_test_symmetric(specie,value_column,\"area\",lfa::lfa_jsd_from_vec)\nlfa::lfa_generate_result_table_tests(jsd_results_spruce,\"Jensen-Shannon Divergence between areas with spruce\")\n```\n\n::: {.cell-output-display}\n`````{=html}\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
Jensen-Shannon Divergence between areas with spruce
Brilon Oberhundem Osterwald
Brilon 0 0.0069 0.005
Oberhundem NA 0.0000 0.002
Osterwald NA NA 0.000
\n\n`````\n:::\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncolMeans(jsd_results_spruce, na.rm = TRUE) |> mean()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 0.001939104\n```\n:::\n:::\n\n\n\n\n\n## Documentation\n### `lfa_calculate_patch_density`\n\nCalculate patch density for specified areas based on detection data\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`areas_location` | The file path to a shapefile containing spatial polygons representing the areas for which patch density needs to be calculated. Default is \"research_areas.shp\".\n`detections` | A data frame containing detection information, where each row represents a detection and includes the 'area' column specifying the corresponding area. Default is obtained using lfa_get_detections().\n\n\n#### Description\n\nThis function calculates patch density for specified areas using detection data.\n It reads the spatial polygons from a shapefile, computes the area size for each patch,\n counts the number of detections in each patch, and calculates the patch density.\n\n\n#### Value\n\nA data frame with patch density information for each specified area.\n Columns include 'name' (area name), 'geometry' (polygon geometry), 'area_size' (patch area size),\n 'detections' (number of detections in the patch), and 'density' (computed patch density).\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming you have a shapefile 'your_research_areas.shp' and detection data\n# from lfa_get_detections()\ndensity_data <- lfa_calculate_patch_density(areas_location = \"your_research_areas.shp\")\nprint(density_data)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_calculate_patch_density(\n areas_location = \"research_areas.shp\",\n detections = lfa::lfa_get_detections()\n)\n```\n:::\n\n\n\n### `lfa_capitalize_first_char`\n\nCapitalize First Character of a String\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`input_string` | A single-character string to be processed.\n\n\n#### Concept\n\nString Manipulation\n\n\n#### Description\n\nThis function takes a string as input and returns the same string with the\n first character capitalized. If the first character is already capitalized,\n the function does nothing. If the first character is not from the alphabet,\n an error is thrown.\n\n\n#### Details\n\nThis function performs the following steps:\n \n\n* Checks if the input is a single-character string. \n\n* Verifies if the first character is from the alphabet (A-Z or a-z). \n\n* If the first character is not already capitalized, it capitalizes it. \n\n* Returns the modified string.\n\n\n#### Keyword\n\nalphabet\n\n\n#### Note\n\nThis function is case-sensitive and assumes ASCII characters.\n\n\n#### References\n\nNone\n\n\n#### Seealso\n\nThis function is related to the basic string manipulation functions in base R.\n\n\n#### Value\n\nA modified string with the first character capitalized if it is\n not already. If the first character is already capitalized, the original\n string is returned.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Capitalize the first character of a string\ncapitalize_first_char(\"hello\") # Returns \"Hello\"\ncapitalize_first_char(\"World\") # Returns \"World\"\n\n# Error example (non-alphabetic first character)\ncapitalize_first_char(\"123abc\") # Throws an error\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_capitalize_first_char(input_string)\n```\n:::\n\n\n\n### `lfa_check_flag`\n\nCheck if a flag is set, indicating the completion of a specific process.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`flag_name` | A character string specifying the name of the flag file. It should be a descriptive and unique identifier for the process being checked.\n\n\n#### Description\n\nThis function checks for the existence of a hidden flag file at a specified location within the working directory. If the flag file is found, a message is printed, and the function returns `TRUE` to indicate that the associated processing step has already been completed. If the flag file is not found, the function returns `FALSE` , indicating that further processing can proceed.\n\n\n#### Value\n\nA logical value indicating whether the flag is set ( `TRUE` ) or not ( `FALSE` ).\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Check if the flag for a process named \"data_processing\" is set\nlfa_check_flag(\"data_processing\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_check_flag(flag_name)\n```\n:::\n\n\n\n### `lfa_combine_sf_obj`\n\nCombine Spatial Feature Objects from Multiple GeoPackage Files\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`paths` | A character vector containing file paths to GeoPackage files with neighbor information.\n`area_infos` | A data frame or list containing information about the corresponding detection areas, including \"area\" and \"specie\" columns.\n\n\n#### Description\n\nThis function reads spatial feature objects (sf) from multiple GeoPackage files and combines them into a single sf object.\n Each GeoPackage file is assumed to contain neighbor information for a specific detection area, and the resulting sf object\n includes additional columns indicating the corresponding area and species information.\n\n\n#### Value\n\nA combined sf object with additional columns for area and specie information.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming paths and area_infos are defined\ncombined_sf <- lfa_combine_sf_obj(paths, area_infos)\n\n# Print the combined sf object\nprint(combined_sf)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_combine_sf_obj(paths, area_infos)\n```\n:::\n\n\n\n### `lfa_count_returns_all_areas`\n\nCount tree returns for all species and areas, returning a consolidated data frame.\n\n\n#### Description\n\nThis function iterates through all species and areas obtained from the function\n [`lfa_get_all_areas`](#lfagetallareas) . For each combination of species and area, it reads\n the corresponding area as a catalog, counts the returns per tree using\n [`lfa_count_returns_per_tree`](#lfacountreturnspertree) , and consolidates the results into a data frame.\n The resulting data frame includes columns for the species, area, and return counts per tree.\n\n\n#### Keyword\n\ncounting\n\n\n#### Seealso\n\n[`lfa_get_all_areas`](#lfagetallareas) , [`lfa_read_area_as_catalog`](#lfareadareaascatalog) ,\n [`lfa_count_returns_per_tree`](#lfacountreturnspertree)\n\n\n#### Value\n\nA data frame with columns for species, area, and return counts per tree.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Count tree returns for all species and areas\nreturns_counts <- lfa_count_returns_all_areas()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_count_returns_all_areas()\n```\n:::\n\n\n\n### `lfa_count_returns_per_tree`\n\nCount returns per tree for a given lidR catalog.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`ctg` | A lidR catalog object containing LAS files to be processed.\n\n\n#### Description\n\nThis function takes a lidR catalog as input and counts the returns per tree.\n It uses the lidR package to read LAS files from the catalog and performs the counting\n operation on each tree. The result is a data frame containing the counts of returns\n for each unique tree ID within the lidR catalog.\n\n\n#### Keyword\n\ncounting\n\n\n#### Seealso\n\n[`lidR::readLAS`](#lidr::readlas) , [`lidR::is.empty`](#lidr::is.empty) ,\n [`base::table`](#base::table) , [`dplyr::bind_rows`](#dplyr::bindrows)\n\n\n#### Value\n\nA data frame with columns for tree ID and the corresponding count of returns.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Count returns per tree for a lidR catalog\nctg <- lfa_read_area_as_catalog(\"SpeciesA\", \"Area1\")\nreturns_counts_per_tree <- lfa_count_returns_per_tree(ctg)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_count_returns_per_tree(ctg)\n```\n:::\n\n\n\n### `lfa_create_boxplot`\n\nCreate a box plot from a data frame\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`data` | A data frame containing the data.\n`value_column` | The name of the column containing the values for the box plot.\n`category_column1` | The name of the column containing the first categorical variable.\n`category_column2` | The name of the column containing the second categorical variable.\n`title` | An optional title for the plot. If not provided, a default title is generated based on the data frame name.\n\n\n#### Description\n\nThis function generates a box plot using ggplot2 based on the specified data frame and columns.\n\n\n#### Details\n\nThe function creates a box plot where the x-axis is based on the second categorical variable,\n the y-axis is based on the specified value column, and the box plots are colored based on the first\n categorical variable. The grouping of box plots is done based on the unique values in the second categorical variable.\n\n\n#### Value\n\nA ggplot object representing the box plot.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming you have a data frame 'your_data' with columns 'value', 'category1', and 'category2'\ncreate_boxplot(your_data, \"value\", \"category1\", \"category2\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_boxplot(\n data,\n value_column,\n category_column1,\n category_column2,\n title = NULL\n)\n```\n:::\n\n\n\n### `lfa_create_density_plots`\n\nCreate density plots for groups in a data frame\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`data` | A data frame containing the data.\n`value_column` | The name of the column containing the values for the density plot.\n`category_column1` | The name of the column containing the categorical variable for grouping.\n`category_column2` | The name of the column containing the categorical variable for arranging plots.\n`title` | An optional title for the plot. If not provided, a default title is generated based on the data frame name.\n`xlims` | Optional limits for the x-axis. Should be a numeric vector with two elements (lower and upper bounds).\n`ylims` | Optional limits for the y-axis. Should be a numeric vector with two elements (lower and upper bounds).\n\n\n#### Description\n\nThis function generates density plots using ggplot2 based on the specified data frame and columns.\n\n\n#### Details\n\nThe function creates density plots where the x-axis is based on the specified value column,\n and the density plots are colored based on the first categorical variable. The arrangement of plots\n is done based on the unique values in the second categorical variable. The plots are arranged in a 2x2 grid.\n\n\n#### Value\n\nA ggplot object representing the density plots arranged in a 2x2 grid.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming you have a data frame 'your_data' with columns 'value', 'category1', and 'category2'\ncreate_density_plots(your_data, \"value\", \"category1\", \"category2\", title = \"Density Plots\", xlims = c(0, 10), ylims = c(0, 0.5))\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_density_plots(\n data,\n value_column,\n category_column1 = \"area\",\n category_column2 = \"specie\",\n title = NULL,\n xlims = NULL,\n ylims = NULL\n)\n```\n:::\n\n\n\n### `lfa_create_grouped_bar_plot`\n\nCreate a barplot using ggplot2\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`df` | A data frame containing the relevant columns for the barplot.\n`value_column` | The column containing the values to be plotted.\n`label_column` | The column used for labeling the bars on the x-axis. Default is \"name\".\n`grouping_column` | The column used for grouping the bars. Default is \"species\".\n\n\n#### Description\n\nThis function generates a barplot using ggplot2 based on the specified data frame columns.\n The barplot displays the values from the specified column, grouped by another column.\n The grouping can be further differentiated by color if desired.\n\n\n#### Value\n\nA ggplot2 barplot.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming you have a data frame 'your_data_frame' with columns \"name\", \"species\", and \"value\"\nlfa_create_barplot(your_data_frame, value_column = \"value\", label_column = \"name\", grouping_column = \"species\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_grouped_bar_plot(data, grouping_var, value_col, label_col)\n```\n:::\n\n\n\n### `lfa_create_neighbor_mean_curves`\n\nCreate neighbor mean curves for specified areas\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`neighbors` | A data frame containing information about neighbors, where each column represents a specific neighbor, and each row corresponds to an area.\n`use_avg` | Logical. If TRUE, the function computes average curves across all neighbors. If FALSE, it computes curves for individual neighbors.\n\n\n#### Description\n\nThis function generates mean curves for a specified set of areas based on neighbor data.\n The user can choose to compute mean curves for individual neighbors or averages across neighbors.\n\n\n#### Value\n\nA data frame with mean curves for each specified area.\n Columns represent areas, and rows represent index values.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming you have a data frame 'your_neighbors_data' with neighbor information\nmean_curves <- lfa_create_neighbor_mean_curves(your_neighbors_data, use_avg = TRUE)\nprint(mean_curves)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_neighbor_mean_curves(neighbors, use_avg = FALSE)\n```\n:::\n\n\n\n### `lfa_create_plot_per_area`\n\nCreate a line plot per area with one color per specie\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`data` | A data frame with numeric columns and a column named 'specie' for species information.\n\n\n#### Description\n\nThis function takes a data frame containing numeric columns and creates a line plot\n using ggplot2. Each line in the plot represents a different area, with one color per specie.\n\n\n#### Value\n\nA ggplot2 line plot.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\ndata <- data.frame(\nspecie = rep(c(\"Species1\", \"Species2\", \"Species3\"), each = 10),\ncolumn1 = rnorm(30),\ncolumn2 = rnorm(30),\ncolumn3 = rnorm(30)\n)\nlfa_create_plot_per_area(data)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_plot_per_area(data)\n```\n:::\n\n\n\n### `lfa_create_stacked_distributions_plot`\n\nCreate a stacked distribution plot for tree detections, visualizing the distribution\n of a specified variable on the x-axis, differentiated by another variable.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`trees` | A data frame containing tree detection data.\n`x_value` | A character string specifying the column name used for finding the values on the x-axis of the histogram.\n`fill_value` | A character string specifying the column name by which the data are differentiated in the plot.\n`bin` | An integer specifying the number of bins for the histogram. Default is 100.\n`ylab` | A character string specifying the y-axis label. Default is \"Amount trees.\"\n`xlim` | A numeric vector of length 2 specifying the x-axis limits. Default is c(0, 100).\n`ylim` | A numeric vector of length 2 specifying the y-axis limits. Default is c(0, 1000).\n`title` | The title of the plot.\n\n\n#### Description\n\nThis function generates a stacked distribution plot using the ggplot2 package,\n providing a visual representation of the distribution of a specified variable\n ( `x_value` ) on the x-axis, with differentiation based on another variable\n ( `fill_value` ). The data for the plot are derived from the provided `trees` \n data frame.\n\n\n#### Keyword\n\ndata\n\n\n#### Seealso\n\n[`ggplot2::geom_histogram`](#ggplot2::geomhistogram) , [`ggplot2::facet_wrap`](#ggplot2::facetwrap) ,\n [`ggplot2::ylab`](#ggplot2::ylab) , [`ggplot2::scale_fill_brewer`](#ggplot2::scalefillbrewer) ,\n [`ggplot2::coord_cartesian`](#ggplot2::coordcartesian)\n\n\n#### Value\n\nA ggplot object representing the stacked distribution plot.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Create a stacked distribution plot for variable \"Z,\" differentiated by \"area\"\ntrees <- lfa_get_detections()\nlfa_create_stacked_distributions_plot(trees, \"Z\", \"area\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_stacked_distributions_plot(\n trees,\n x_value,\n fill_value,\n bin = 100,\n ylab = \"Amount trees\",\n xlim = c(0, 100),\n ylim = c(0, 1000),\n title =\n \"Histograms of height distributions between species 'beech', 'oak', 'pine' and 'spruce' divided by the different areas of Interest\"\n)\n```\n:::\n\n\n\n### `lfa_create_stacked_histogram`\n\nCreate a stacked histogram for tree detections, summing up the values for each species.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`trees` | A data frame containing tree detection data.\n`x_value` | A character string specifying the column name used for finding the values on the x-axis of the histogram.\n`fill_value` | A character string specifying the column name by which the data are differentiated in the plot.\n`bin` | An integer specifying the number of bins for the histogram. Default is 30.\n`ylab` | A character string specifying the y-axis label. Default is \"Frequency.\"\n`xlim` | A numeric vector of length 2 specifying the x-axis limits. Default is c(0, 100).\n`ylim` | A numeric vector of length 2 specifying the y-axis limits. Default is NULL.\n\n\n#### Description\n\nThis function generates a stacked histogram using the ggplot2 package,\n summing up the values for each species and visualizing the distribution of\n a specified variable ( `x_value` ) on the x-axis, differentiated by another\n variable ( `fill_value` ). The data for the plot are derived from the provided\n `trees` data frame.\n\n\n#### Keyword\n\ndata\n\n\n#### Seealso\n\n[`ggplot2::geom_histogram`](#ggplot2::geomhistogram) , [`ggplot2::ylab`](#ggplot2::ylab) ,\n [`ggplot2::scale_fill_brewer`](#ggplot2::scalefillbrewer) , [`ggplot2::coord_cartesian`](#ggplot2::coordcartesian)\n\n\n#### Value\n\nA ggplot object representing the stacked histogram.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Create a stacked histogram for variable \"Z,\" differentiated by \"area\"\ntrees <- lfa_get_detections()\nlfa_create_stacked_histogram(trees, \"Z\", \"area\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_stacked_histogram(\n trees,\n x_value,\n fill_value,\n bin = 30,\n ylab = \"Frequency\",\n xlim = c(0, 100),\n ylim = NULL\n)\n```\n:::\n\n\n\n### `lfa_create_tile_location_objects`\n\nCreate tile location objects\n\n\n#### Author\n\nJakob Danel\n\n\n#### Description\n\nThis function traverses a directory structure to find LAZ files and creates\n tile location objects for each file. The function looks into the the `data` \n directory of the repository/working directory. It then creates `tile_location` \n objects based on the folder structure. The folder structure should not be\n touched by hand, but created by `lfa_init_data_structure()` which builds the\n structure based on a shape file.\n\n\n#### Seealso\n\n[`tile_location`](#tilelocation)\n\n\n#### Value\n\nA vector containing tile location objects.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_tile_location_objects()\n\nlfa_create_tile_location_objects()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_create_tile_location_objects()\n```\n:::\n\n\n\n### `lfa_detection`\n\nPerform tree detection on a lidar catalog and optionally save the results to a file.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`catalog` | A lidar catalog containing point cloud data. If set to NULL, the function attempts to read the catalog from the specified tile location.\n`tile_location` | An object specifying the location of the lidar tile. If catalog is NULL, the function attempts to read the catalog from this tile location.\n`write_to_file` | A logical value indicating whether to save the detected tree information to a file. Default is TRUE.\n\n\n#### Description\n\nThis function utilizes lidar data to detect trees within a specified catalog. The detected tree information can be optionally saved to a file in the GeoPackage format. The function uses parallel processing to enhance efficiency.\n\n\n#### Value\n\nA sf style data frame containing information about the detected trees.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Perform tree detection on a catalog and save the results to a file\nlfa_detection(catalog = my_catalog, tile_location = my_tile_location, write_to_file = TRUE)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_detection(catalog, tile_location, write_to_file = TRUE)\n```\n:::\n\n\n\n### `lfa_download_areas`\n\nDownload areas based on spatial features\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`sf_areas` | Spatial features representing areas to be downloaded. It must include columns like \"species\" \"name\" See details for more information.\n\n\n#### Author\n\nJakob Danel\n\n\n#### Description\n\nThis function initiates the data structure and downloads areas based on spatial features.\n\n\n#### Details\n\nThe input data frame, `sf_areas` , must have the following columns:\n \n\n* \"species\": The species associated with the area. \n\n* \"name\": The name of the area. \n \n The function uses the `lfa_init_data_structure` function to set up the data structure\n and then iterates through the rows of `sf_areas` to download each specified area.\n\n\n#### Value\n\nNone\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_download_areas(sf_areas)\n\n\n# Example spatial features data frame\nsf_areas <- data.frame(\nspecies = c(\"SpeciesA\", \"SpeciesB\"),\nname = c(\"Area1\", \"Area2\"),\n# Must include also other attributes specialized to sf objects\n# such as geometry, for processing of the download\n)\n\nlfa_download_areas(sf_areas)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_download_areas(sf_areas)\n```\n:::\n\n\n\n### `lfa_download`\n\nDownload an las file from the state NRW from a specific location\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`species` | The species of the tree which is observed at this location\n`name` | The name of the area that is observed\n`location` | An sf object, which holds the location information for the area where the tile should be downloaded from.\n\n\n#### Description\n\nIt will download the file and save it to data/ list(list(\"html\"), list(list(\"\"))) / list(list(\"html\"), list(list(\"\"))) with the name of the tile\n\n\n#### Value\n\nThe LASCatalog object of the downloaded file\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_download(species, name, location)\n```\n:::\n\n\n\n### `lfa_find_n_nearest_trees`\n\nFind n Nearest Trees\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`trees` | A sf object containing tree coordinates.\n`n` | The number of nearest trees to find for each tree (default is 100).\n\n\n#### Description\n\nThis function calculates the distances to the n nearest trees for each tree in the input dataset.\n\n\n#### Value\n\nA data frame with additional columns representing the distances to the n nearest trees.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Load tree data using lfa_get_detections() (not provided)\ntree_data <- lfa_get_detections()\n\n# Filter tree data for a specific species and area\ntree_data = tree_data[tree_data$specie == \"pine\" & tree_data$area == \"greffen\", ]\n\n# Find the 100 nearest trees for each tree in the filtered dataset\ntree_data <- lfa_find_n_nearest_trees(tree_data)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_find_n_nearest_trees(trees, n = 100)\n```\n:::\n\n\n\n### `lfa_generate_result_table_tests`\n\nGenerate Result Table for Tests\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`table` | A data frame representing the result table.\n\n\n#### Description\n\nThis function generates a result table for tests using the knitr::kable function.\n\n\n#### Details\n\nThis function uses the knitr::kable function to create a formatted table, making it suitable for HTML output.\n The input table is expected to be a data frame with test results, and the resulting table will have capitalized\n row and column names with lines between columns and rows.\n\n\n#### Value\n\nA formatted table suitable for HTML output with lines between columns and rows.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Generate a result table for tests\nresult_table <- data.frame(\nTest1 = c(0.05, 0.10, 0.03),\nTest2 = c(0.02, 0.08, 0.01),\nTest3 = c(0.08, 0.12, 0.05)\n)\nformatted_table <- lfa_generate_result_table_tests(result_table)\nprint(formatted_table)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_generate_result_table_tests(table, caption = \"Table Caption\")\n```\n:::\n\n\n\n### `lfa_get_all_areas`\n\nRetrieve a data frame containing all species and corresponding areas.\n\n\n#### Description\n\nThis function scans the \"data\" directory within the current working directory to\n obtain a list of species. It then iterates through each species to retrieve the list\n of areas associated with that species. The resulting data frame contains two columns:\n \"specie\" representing the species and \"area\" representing the corresponding area.\n\n\n#### Keyword\n\ndata\n\n\n#### Seealso\n\n[`list.dirs`](#list.dirs)\n\n\n#### Value\n\nA data frame with columns \"specie\" and \"area\" containing information about\n all species and their associated areas.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Retrieve a data frame with information about all species and areas\nall_areas_df <- lfa_get_all_areas()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_all_areas()\n```\n:::\n\n\n\n### `lfa_get_detection_area`\n\nGet Detection for an area\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`species` | A character string specifying the target species.\n`name` | A character string specifying the name of the tile.\n\n\n#### Description\n\nRetrieves the tree detection information for a specified species and tile.\n\n\n#### Details\n\nThis function reads tree detection data from geopackage files within the specified tile location for a given species. It then combines the data into a single SF data frame and returns it. The function assumes that the tree detection files follow a naming convention with the pattern \"_detection.gpkg\".\n\n\n#### Keyword\n\nspatial\n\n\n#### References\n\nThis function is part of the LiDAR Forest Analysis (LFA) package.\n\n\n#### Seealso\n\n[`get_tile_dir`](#gettiledir)\n\n\n#### Value\n\nA Simple Features (SF) data frame containing tree detection information for the specified species and tile.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Retrieve tree detection data for species \"example_species\" in tile \"example_tile\"\ntrees_data <- lfa_get_detection_tile_location(\"example_species\", \"example_tile\")\n\n# Example usage:\ntrees_data <- lfa_get_detection_tile_location(\"example_species\", \"example_tile\")\n\n# No trees found scenario:\nempty_data <- lfa_get_detection_tile_location(\"nonexistent_species\", \"nonexistent_tile\")\n# The result will be an empty data frame if no trees are found for the specified species and tile.\n\n# Error handling:\n# In case of invalid inputs, the function may throw errors. Ensure correct species and tile names are provided.\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_detection_area(species, name)\n```\n:::\n\n\n\n### `lfa_get_detections_species`\n\nRetrieve detections for a specific species.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`species` | A character string specifying the target species.\n\n\n#### Description\n\nThis function retrieves detection data for a given species from multiple areas.\n\n\n#### Details\n\nThe function looks for detection data in the \"data\" directory for the specified species.\n It then iterates through each subdirectory (representing different areas) and consolidates the\n detection data into a single data frame.\n\n\n#### Value\n\nA data frame containing detection information for the specified species in different areas.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Example usage:\ndetections_data <- lfa_get_detections_species(\"example_species\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_detections_species(species)\n```\n:::\n\n\n\n### `lfa_get_detections`\n\nRetrieve aggregated detection data for multiple species.\n\n\n#### Concept\n\ndata retrieval functions\n\n\n#### Description\n\nThis function obtains aggregated detection data for multiple species by iterating\n through the list of species obtained from [`lfa_get_species`](#lfagetspecies) . For each\n species, it calls [`lfa_get_detections_species`](#lfagetdetectionsspecies) to retrieve the\n corresponding detection data and aggregates the results into a single data frame.\n The resulting data frame includes columns for the species, tree detection data,\n and the area in which the detections occurred.\n\n\n#### Keyword\n\naggregation\n\n\n#### Seealso\n\n[`lfa_get_species`](#lfagetspecies) , [`lfa_get_detections_species`](#lfagetdetectionsspecies) \n \n Other data retrieval functions:\n [`lfa_get_species`](#lfagetspecies)\n\n\n#### Value\n\nA data frame containing aggregated detection data for multiple species.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_detections()\n\n# Retrieve aggregated detection data for multiple species\ndetections_data <- lfa_get_detections()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_detections()\n```\n:::\n\n\n\n### `lfa_get_flag_path`\n\nGet the path to a flag file indicating the completion of a specific process.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`flag_name` | A character string specifying the name of the flag file. It should be a descriptive and unique identifier for the process being flagged.\n\n\n#### Description\n\nThis function constructs and returns the path to a hidden flag file, which serves as an indicator that a particular processing step has been completed. The flag file is created in a designated location within the working directory.\n\n\n#### Value\n\nA character string representing the absolute path to the hidden flag file.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Get the flag path for a process named \"data_processing\"\nlfa_get_flag_path(\"data_processing\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_flag_path(flag_name)\n```\n:::\n\n\n\n### `lfa_get_neighbor_paths`\n\nGet Paths to Neighbor GeoPackage Files\n\n\n#### Description\n\nThis function retrieves the file paths to GeoPackage files containing neighbor information for each detection area.\n The GeoPackage files are assumed to be named \"neighbours.gpkg\" and organized in a directory structure under the \"data\" folder.\n\n\n#### Value\n\nA character vector containing file paths to GeoPackage files for each detection area's neighbors.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Get paths to neighbor GeoPackage files for all areas\npaths <- lfa_get_neighbor_paths()\n\n# Print the obtained file paths\nprint(paths)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_neighbor_paths()\n```\n:::\n\n\n\n### `lfa_get_species`\n\nGet a list of species from the data directory.\n\n\n#### Concept\n\ndata retrieval functions\n\n\n#### Description\n\nThis function retrieves a list of species by scanning the \"data\" directory\n located in the current working directory.\n\n\n#### Keyword\n\ndata\n\n\n#### References\n\nThis function relies on the [`list.dirs`](#list.dirs) function for directory listing.\n\n\n#### Seealso\n\n[`list.dirs`](#list.dirs) \n \n Other data retrieval functions:\n [`lfa_get_detections`](#lfagetdetections)\n\n\n#### Value\n\nA character vector containing the names of species found in the \"data\" directory.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Retrieve the list of species\nspecies_list <- lfa_get_species()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_get_species()\n```\n:::\n\n\n\n### `lfa_ground_correction`\n\nCorrect the point clouds for correct ground imagery\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`ctg` | An LASCatalog object. If not null, it will perform the actions on this object, if NULL inferring the catalog from the tile_location\n`tile_location` | A tile_location type object holding the information about the location of the cataog. This is used to save the catalog after processing too.\n\n\n#### Author\n\nJakob Danel\n\n\n#### Description\n\nThis function is needed to correct the Z value of the point cloud, relative to the real\n ground height. After using this function to your catalog, the Z values can be seen as the\n real elevation about the ground. At the moment the function uses the `tin()` function from\n the `lidr` package. NOTE : The operation is inplace and can not be reverted, the old values\n of the point cloud will be deleted!\n\n\n#### Value\n\nA catalog with the corrected z values. The catalog is always stored at tile_location and\n holding only the transformed values.\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_ground_correction(ctg, tile_location)\n```\n:::\n\n\n\n### `lfa_init_data_structure`\n\nInitialize data structure for species and areas\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`sf_species` | A data frame with information about species and associated areas.\n\n\n#### Description\n\nThis function initializes the data structure for storing species and associated areas.\n\n\n#### Details\n\nThe input data frame, `sf_species` , should have at least the following columns:\n \n\n* \"species\": The names of the species for which the data structure needs to be initialized. \n\n* \"name\": The names of the associated areas. \n \n The function creates directories based on the species and area information provided in\n the `sf_species` data frame. It checks whether the directories already exist and creates\n them if they don't.\n\n\n#### Value\n\nNone\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Example species data frame\nsf_species <- data.frame(\nspecies = c(\"SpeciesA\", \"SpeciesB\"),\nname = c(\"Area1\", \"Area2\"),\n# Other necessary columns\n)\n\nlfa_init_data_structure(sf_species)\n\n# Example species data frame\nsf_species <- data.frame(\nspecies = c(\"SpeciesA\", \"SpeciesB\"),\nname = c(\"Area1\", \"Area2\"),\n# Other necessary columns\n)\n\nlfa_init_data_structure(sf_species)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_init_data_structure(sf_species)\n```\n:::\n\n\n\n### `lfa_init`\n\nInitialize LFA (LiDAR forest analysis) data processing\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`sf_file` | A character string specifying the path to the shapefile containing spatial features of research areas.\n\n\n#### Description\n\nThis function initializes the LFA data processing by reading a shapefile containing\n spatial features of research areas, downloading the specified areas, and creating\n tile location objects for each area.\n\n\n#### Details\n\nThis function reads a shapefile ( `sf_file` ) using the `sf` package, which should\n contain information about research areas. It then calls the `lfa_download_areas` \n function to download the specified areas and `lfa_create_tile_location_objects` \n to create tile location objects based on Lidar data files in those areas. The\n shapefile MUST follow the following requirements:\n \n\n* Each geometry must be a single object of type polygon \n\n* Each entry must have the following attributes: \n\n* species: A string describing the tree species of the area. \n\n* name: A string describing the location of the area.\n\n\n#### Value\n\nA vector containing tile location objects.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Initialize LFA processing with the default shapefile\nlfa_init()\n\n# Initialize LFA processing with a custom shapefile\nlfa_init(\"custom_areas.shp\")\n\n# Example usage with the default shapefile\nlfa_init()\n\n# Example usage with a custom shapefile\nlfa_init(\"custom_areas.shp\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_init(sf_file = \"research_areas.shp\")\n```\n:::\n\n\n\n### `lfa_intersect_areas`\n\nIntersect Lidar Catalog with Spatial Features\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`ctg` | A LAScatalog object representing the Lidar data to be processed.\n`tile_location` | A tile location object representing the specific area of interest.\n`areas_sf` | Spatial features defining areas.\n\n\n#### Description\n\nThis function intersects a Lidar catalog with a specific area defined by spatial features.\n\n\n#### Details\n\nThe function intersects the Lidar catalog specified by `ctg` with a specific area defined by\n the `tile_location` object and `areas_sf` . It removes points outside the specified area and\n returns a modified LAScatalog object.\n \n The specified area is identified based on the `species` and `name` attributes in the\n `tile_location` object. If a matching area is not found in `areas_sf` , the function\n stops with an error.\n \n The function then transforms the spatial reference of the identified area to match that of\n the Lidar catalog using `sf::st_transform` .\n \n The processing is applied to each chunk in the catalog using the `identify_area` function,\n which merges spatial information and filters out points that are not classified as inside\n the identified area. After processing, the function writes the modified LAS files back to\n the original file locations, removing points outside the specified area.\n \n If an error occurs during the processing of a chunk, a warning is issued, and the function\n continues processing the next chunks. If no points are found after filtering, a warning is\n issued, and NULL is returned.\n\n\n#### Seealso\n\nOther functions in the Lidar forest analysis (LFA) package.\n\n\n#### Value\n\nA modified LAScatalog object with points outside the specified area removed.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Example usage\nlfa_intersect_areas(ctg, tile_location, areas_sf)\n\n# Example usage\nlfa_intersect_areas(ctg, tile_location, areas_sf)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_intersect_areas(ctg, tile_location, areas_sf)\n```\n:::\n\n\n\n### `lfa_jsd_from_vec`\n\nCompute Jensen-Shannon Divergence from Vectors\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`x` | A numeric vector.\n`y` | A numeric vector.\n\n\n#### Description\n\nThis function calculates the Jensen-Shannon Divergence (JSD) between two vectors.\n\n\n#### Value\n\nJensen-Shannon Divergence between the density distributions of x and y.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nx <- rnorm(100)\ny <- rnorm(100, mean = 2)\nlfa_jsd_from_vec(x, y)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_jsd_from_vec(x, y)\n```\n:::\n\n\n\n### `lfa_jsd`\n\nJensen-Shannon Divergence Calculation\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`p` | A numeric vector representing the probability distribution P.\n`q` | A numeric vector representing the probability distribution Q.\n`epsilon` | A small positive constant added to both P and Q to avoid logarithm of zero. Default is 1e-10.\n\n\n#### Description\n\nThis function calculates the Jensen-Shannon Divergence (JSD) between two probability distributions P and Q.\n\n\n#### Details\n\nThe JSD is computed using the Kullback-Leibler Divergence (KLD) as follows:\n `sum((p * log((p + epsilon) / (m + epsilon)) + q * log((q + epsilon) / (m + epsilon))) / 2)` \n where `m = (p + q) / 2` .\n\n\n#### Seealso\n\n[`kld`](#kld) , [`sum`](#sum) , [`log`](#log)\n\n\n#### Value\n\nA numeric value representing the Jensen-Shannon Divergence between P and Q.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Calculate JSD between two probability distributions\np_distribution <- c(0.2, 0.3, 0.5)\nq_distribution <- c(0.1, 0, 0.9)\njsd_result <- jsd(p_distribution, q_distribution)\nprint(jsd_result)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_jsd(p, q, epsilon = 1e-10)\n```\n:::\n\n\n\n### `lfa_kld_from_vec`\n\nCompute Kullback-Leibler Divergence from Vectors\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`x` | A numeric vector.\n`y` | A numeric vector.\n\n\n#### Description\n\nThis function calculates the Kullback-Leibler Divergence (KLD) between two vectors.\n\n\n#### Value\n\nKullback-Leibler Divergence between the density distributions of x and y.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nx <- rnorm(100)\ny <- rnorm(100, mean = 2)\nlfa_kld_from_vec(x, y)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_kld_from_vec(x, y)\n```\n:::\n\n\n\n### `lfa_kld`\n\nKullback-Leibler Divergence Calculation\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`p` | A numeric vector representing the probability distribution P.\n`q` | A numeric vector representing the probability distribution Q.\n`epsilon` | A small positive constant added to both P and Q to avoid logarithm of zero. Default is 1e-10.\n\n\n#### Description\n\nThis function calculates the Kullback-Leibler Divergence (KLD) between two probability distributions P and Q.\n\n\n#### Details\n\nThe KLD is computed using the formula:\n `sum(p * log((p + epsilon) / (q + epsilon)))` \n This avoids issues when the denominator (Q) contains zero probabilities.\n\n\n#### Seealso\n\n[`sum`](#sum) , [`log`](#log)\n\n\n#### Value\n\nA numeric value representing the Kullback-Leibler Divergence between P and Q.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Calculate KLD between two probability distributions\np_distribution <- c(0.2, 0.3, 0.5)\nq_distribution <- c(0.1, 0, 0.9)\nkld_result <- kld(p_distribution, q_distribution)\nprint(kld_result)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_kld(p, q, epsilon = 1e-10)\n```\n:::\n\n\n\n### `lfa_ks_test`\n\nKolmogorov-Smirnov Test Wrapper Function\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`x` | A numeric vector representing the first sample.\n`y` | A numeric vector representing the second sample.\n`output_variable` | A character string specifying the output variable to extract from the ks.test result. Default is \"p.value\". Other possible values include \"statistic\" and \"alternative\".\n`...` | Additional arguments to be passed to the ks.test function.\n\n\n#### Description\n\nThis function serves as a wrapper for the Kolmogorov-Smirnov (KS) test between two samples.\n\n\n#### Details\n\nThe function uses the ks.test function to perform a two-sample KS test and returns the specified output variable.\n The default output variable is the p-value. Other possible output variables include \"statistic\" and \"alternative\".\n\n\n#### Seealso\n\n[`ks.test`](#ks.test)\n\n\n#### Value\n\nA numeric value representing the specified output variable from the KS test result.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Perform KS test and extract the p-value\nresult <- lfa_ks_test(sample1, sample2)\nprint(result)\n\n# Perform KS test and extract the test statistic\nresult_statistic <- lfa_ks_test(sample1, sample2, output_variable = \"statistic\")\nprint(result_statistic)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_ks_test(x, y, output_variable = \"p.value\", ...)\n```\n:::\n\n\n\n### `lfa_load_ctg_if_not_present`\n\nLoading the catalog if it is not present\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`ctg` | Catalog object. Can be NULL\n`tile_location` | The location to look for the catalog tiles, if their are not present\n\n\n#### Description\n\nThis function checks if the catalog is `NULL` . If it is it will load the\n catalog from the `tile_location`\n\n\n#### Value\n\nThe provided ctg object if not null, else the catalog for the tiles\n of the tile_location.\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_load_ctg_if_not_present(ctg, tile_location)\n```\n:::\n\n\n\n### `lfa_map_tile_locations`\n\nMap Function Over Tile Locations\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`tile_locations` | A list of tile location objects.\n`map_function` | The mapping function to be applied to each tile location.\n`...` | Additional arguments to be passed to the mapping function.\n\n\n#### Description\n\nThis function applies a specified mapping function to each tile location in a list.\n\n\n#### Details\n\nThis function iterates over each tile location in the provided list ( `tile_locations` )\n and applies the specified mapping function ( `map_function` ) to each tile location.\n The mapping function should accept a tile location object as its first argument, and\n additional arguments can be passed using the ellipsis ( `...` ) syntax.\n \n This function is useful for performing operations on multiple tile locations concurrently,\n such as loading Lidar data, processing areas, or other tasks that involve tile locations.\n\n\n#### Seealso\n\nThe mapping function provided should be compatible with the structure and requirements\n of the tile locations and the specific task being performed.\n\n\n#### Value\n\nNone\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Example usage\nlfa_map_tile_locations(tile_locations, my_mapping_function, param1 = \"value\")\n\n# Example usage\nlfa_map_tile_locations(tile_locations, my_mapping_function, param1 = \"value\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_map_tile_locations(tile_locations, map_function, check_flag = NULL, ...)\n```\n:::\n\n\n\n### `lfa_merge_and_save`\n\nMerge and Save Text Files in a Directory\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`input_directory` | The path to the input directory containing text files.\n`output_name` | The name for the output file where the merged content will be saved.\n\n\n#### Description\n\nThis function takes an input directory and an output name as arguments.\n It merges the textual content of all files in the specified directory into\n a single string, with each file's content separated by a newline character.\n The merged content is then saved into a file named after the output name\n in the same directory. After the merging is complete, all input files are\n deleted.\n\n\n#### Details\n\nThis function reads the content of each text file in the specified input directory\n and concatenates them into a single string. Each file's content is separated by a newline\n character. The merged content is then saved into a file named after the output name\n in the same directory. Finally, all input files are deleted from the directory.\n\n\n#### Seealso\n\n[`readLines`](#readlines) , [`writeLines`](#writelines) , [`file.remove`](#file.remove)\n\n\n#### Value\n\nThis function does not explicitly return any value. It prints a message\n indicating the successful completion of the merging and saving process.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Merge text files in the \"data_files\" directory and save the result in \"merged_output\"\nlfa_merge_and_save(\"data_files\", \"merged_output\")\n\n# Merge text files in the \"data_files\" directory and save the result in \"merged_output\"\nlfa_merge_and_save(\"data_files\", \"merged_output\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_merge_and_save(input_directory, output_name)\n```\n:::\n\n\n\n### `lfa_random_forest`\n\nRandom Forest Classifier with Leave-One-Out Cross-Validation\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`tree_data` | A data frame containing the tree data, including the response variable (\"specie\") and predictor variables.\n`excluded_input_columns` | A character vector specifying columns to be excluded from predictor variables.\n`response_variable` | The response variable to be predicted (default is \"specie\").\n`seed` | An integer to set the seed for reproducibility (default is 123).\n`...` | Additional parameters to be passed to the randomForest function.\n\n\n#### Description\n\nThis function performs a random forest classification using leave-one-out cross-validation for each area in the input tree data.\n It returns a list containing various results, including predicted species, confusion matrix, accuracy, and the formula used for modeling.\n\n\n#### Value\n\nA list containing the following elements:\n \n\n* `predicted_species_absolute` : A data frame with observed and predicted species for each area. \n\n* `predicted_species_relative` : A data frame wit the relative precictions per speices and areas, normalized by the total predictions in each area. \n\n* `confusion_matrix` : A confusion matrix showing the counts of predicted vs. observed species. \n\n* `accuracy` : The accuracy of the model, calculated as the sum of diagonal elements in the confusion matrix divided by the total count. \n\n* `formula` : The formula used for modeling.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Assuming tree_data is defined\nresults <- lfa_random_forest(tree_data, excluded_input_columns = c(\"column1\", \"column2\"))\n\n# Print the list of results\nprint(results)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_random_forest(\n tree_data,\n excluded_input_columns,\n response_variable = \"specie\",\n ntree = 100,\n seed = 123,\n ...\n)\n```\n:::\n\n\n\n### `lfa_rd_to_qmd`\n\nConvert Rd File to Markdown\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`rdfile` | The path to the Rd file or a parsed Rd object.\n`outfile` | The path to the output Markdown file (including the file extension).\n`append` | Logical, indicating whether to append to an existing file (default is FALSE).\n\n\n#### Description\n\nIMPORTANT NOTE: \n This function is nearly identical to the `Rd2md::Rd2markdown` function from the `Rd2md` \n package. We needed to implement our own version of it because of various reasons:\n \n\n* The algorithm uses hardcoded header sizes (h1 and h2 in original) which is not feasible for our use-case of the markdown. \n\n* We needed to add some Quarto Markdown specifics, e.g. to make sure that the examples will not be runned. \n\n* We want to exclude certain tags from our implementation.\n\n\n#### Details\n\nFor that reason we copied the method and made changes as needed and also added this custom documentation.\n \n This function converts an Rd (R documentation) file to Markdown format (.md) and\n saves the converted file at the specified location. The function allows appending\n to an existing file or creating a new one. The resulting Markdown file includes\n sections for the function's name, title, and additional content such as examples,\n usage, arguments, and other sections present in the Rd file.\n \n The function performs the following steps:\n \n\n* Parses the Rd file using the Rd2md package. \n\n* Creates a Markdown file with sections for the function's name, title, and additional content. \n\n* Appends the content to an existing file if `append` is set to TRUE. \n\n* Saves the resulting Markdown file at the specified location.\n\n\n#### Seealso\n\n[`Rd2md::parseRd`](#rd2md::parserd)\n\n\n#### Value\n\nThis function does not explicitly return any value. It saves the converted Markdown file\n at the specified location as described in the details section.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Convert Rd file to Markdown and save it\nlfa_rd_to_md(\"path/to/your/file.Rd\", \"path/to/your/output/file.md\")\n\n# Convert Rd file to Markdown and append to an existing file\nlfa_rd_to_md(\"path/to/your/file.Rd\", \"path/to/existing/output/file.md\", append = TRUE)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_rd_to_qmd(rdfile, outfile, append = FALSE)\n```\n:::\n\n\n\n### `lfa_rd_to_results`\n\nConvert Rd Files to Markdown and Merge Results\n\n\n#### Description\n\nThis function converts all Rd (R documentation) files in the \"man\" directory\n to Markdown format (.qmd) and saves the converted files in the \"results/appendix/package-docs\" directory.\n It then merges the converted Markdown files into a single string and saves\n the merged content into a file named \"docs.qmd\" in the \"results/appendix/package-docs\" directory.\n\n\n#### Details\n\nThe function performs the following steps:\n \n\n* Removes any existing \"docs.qmd\" file in the \"results/appendix/package-docs\" directory. \n\n* Finds all Rd files in the \"man\" directory. \n\n* Converts each Rd file to Markdown format (.qmd) using the `lfa_rd_to_qmd` function. \n\n* Saves the converted Markdown files in the \"results/appendix/package-docs\" directory. \n\n* Merges the content of all converted Markdown files into a single string. \n\n* Saves the merged content into a file named \"docs.qmd\" in the \"results/appendix/package-docs\" directory.\n\n\n#### Seealso\n\n[`lfa_rd_to_qmd`](#lfardtoqmd) , [`lfa_merge_and_save`](#lfamergeandsave)\n\n\n#### Value\n\nThis function does not explicitly return any value. It performs the conversion,\n merging, and saving operations as described in the details section.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Convert Rd files to Markdown and merge the results\nlfa_rd_to_results()\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_rd_to_results()\n```\n:::\n\n\n\n### `lfa_read_area_as_catalog`\n\nRead LiDAR data from a specified species and location as a catalog.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`specie` | A character string specifying the species of interest.\n`location_name` | A character string specifying the name of the location.\n\n\n#### Description\n\nThis function constructs the file path based on the specified `specie` and `location_name` ,\n lists the directories at that path, and reads the LiDAR data into a `lidR::LAScatalog` .\n\n\n#### Value\n\nA `lidR::LAScatalog` object containing the LiDAR data from the specified location and species.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_read_area_as_catalog(\"beech\", \"location1\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_read_area_as_catalog(specie, location_name)\n```\n:::\n\n\n\n### `lfa_run_test_asymmetric`\n\nAsymmetric Pairwise Test for Categories\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`data` | A data frame containing the relevant columns.\n`data_column` | A character string specifying the column containing the numerical data.\n`category_column` | A character string specifying the column containing the categorical variable.\n`test_function` | A function used to perform the pairwise test between two sets of data. It should accept two vectors of numeric data and additional parameters specified by `...` . The function should return a numeric value representing the test result.\n`...` | Additional parameters to be passed to the `test_function` .\n\n\n#### Description\n\nThis function performs an asymmetric pairwise test for categories using a user-defined `test_function` .\n\n\n#### Details\n\nThe function calculates the test results for each unique combination of categories using the specified\n `test_function` . The resulting table is asymmetric, containing the test results for comparisons\n from the rows to the columns.\n\n\n#### Seealso\n\n[`outer`](#outer) , [`Vectorize`](#vectorize)\n\n\n#### Value\n\nA data frame representing the results of the asymmetric pairwise tests between categories.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Define a custom test function\ncustom_test_function <- function(x, y) {\n# Your test logic here\n# Return a numeric result\nreturn(mean(x) - mean(y))\n}\n\n# Perform an asymmetric pairwise test\nresult <- lfa_run_test_asymmetric(your_data, \"numeric_column\", \"category_column\", custom_test_function)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_run_test_asymmetric(data, data_column, category_column, test_function, ...)\n```\n:::\n\n\n\n### `lfa_run_test_symmetric`\n\nSymmetric Pairwise Test for Categories\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`data` | A data frame containing the relevant columns.\n`data_column` | A character string specifying the column containing the numerical data.\n`category_column` | A character string specifying the column containing the categorical variable.\n`test_function` | A function used to perform the pairwise test between two sets of data. It should accept two vectors of numeric data and additional parameters specified by `...` . The function should return a numeric value representing the test result.\n`...` | Additional parameters to be passed to the `test_function` .\n\n\n#### Description\n\nThis function performs a symmetric pairwise test for categories using a user-defined `test_function` .\n\n\n#### Details\n\nThe function calculates the test results for each unique combination of categories using the specified\n `test_function` . The resulting table is symmetric, containing the test results for comparisons\n from the rows to the columns. The upper triangle of the matrix is filled with `NA` to avoid duplicate results.\n\n\n#### Seealso\n\n[`outer`](#outer) , [`Vectorize`](#vectorize)\n\n\n#### Value\n\nA data frame representing the results of the symmetric pairwise tests between categories.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Define a custom test function\ncustom_test_function <- function(x, y) {\n# Your test logic here\n# Return a numeric result\nreturn(mean(x) - mean(y))\n}\n\n# Perform a symmetric pairwise test\nresult <- lfa_run_test_symmetric(your_data, \"numeric_column\", \"category_column\", custom_test_function)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_run_test_symmetric(data, data_column, category_column, test_function, ...)\n```\n:::\n\n\n\n### `lfa_save_all_neighbours`\n\nSave Neighbors for All Areas\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`n` | The number of nearest trees to find for each tree (default is 100).\n\n\n#### Description\n\nThis function iterates through all detection areas, finds the n nearest trees for each tree,\n and saves the result to a GeoPackage file for each area.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Save neighbors for all areas with default value (n=100)\nlfa_save_all_neighbours()\n\n# Save neighbors for all areas with a specific value of n (e.g., n=50)\nlfa_save_all_neighbours(n = 50)\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_save_all_neighbours(n = 100)\n```\n:::\n\n\n\n### `lfa_segmentation`\n\nSegment the elements of an point cloud by trees\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`ctg` | An LASCatalog object. If not null, it will perform the actions on this object, if NULL inferring the catalog from the tile_location\n`tile_location` | A tile_location type object holding the information about the location of the catalog. This is used to save the catalog after processing too.\n\n\n#### Author\n\nJakob Danel\n\n\n#### Description\n\nThis function will try to to divide the hole point cloud into unique trees.\n Therefore it is assigning for each chunk of the catalog a `treeID` for each\n point. Therefore the algorithm uses the `li2012` implementation with the\n following parameters: `li2012(dt1 = 2, dt2 = 3, R = 2, Zu = 10, hmin = 5, speed_up = 12)` \n NOTE : The operation is in place and can not be reverted, the old values\n of the point cloud will be deleted!\n\n\n#### Value\n\nA catalog where each chunk has additional `treeID` values indicating the belonging tree.\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_segmentation(ctg, tile_location)\n```\n:::\n\n\n\n### `lfa_set_flag`\n\nSet a flag to indicate the completion of a specific process.\n\n\n#### Arguments\n\nArgument |Description\n------------- |----------------\n`flag_name` | A character string specifying the name of the flag file. It should be a descriptive and unique identifier for the process being flagged.\n\n\n#### Description\n\nThis function creates a hidden flag file at a specified location within the working directory to indicate that a particular processing step has been completed. If the flag file already exists, a warning is issued.\n\n\n#### Value\n\nThis function does not have a formal return value.\n\n\n#### Examples\n\n::: {.cell}\n\n```{.r .cell-code}\n# Set the flag for a process named \"data_processing\"\nlfa_set_flag(\"data_processing\")\n```\n:::\n\n\n#### Usage\n\n::: {.cell}\n\n```{.r .cell-code}\nlfa_set_flag(flag_name)\n```\n:::\n\n\n\n", "supporting": [ "report_files/figure-html" ], diff --git a/results/_freeze/report/figure-html/fig-density-bar-1.png b/results/_freeze/report/figure-html/fig-density-bar-1.png new file mode 100644 index 0000000000000000000000000000000000000000..a8042b5225320f0be03ac526a6f774a2b621a0fd GIT binary patch literal 61687 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≧`j@+8bbKA9YZVA-Z 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 literal 0 HcmV?d00001