├── .github ├── .gitignore └── workflows │ └── check-standard.yaml ├── R ├── globals.R ├── nichevol.R ├── read_bin_table.R ├── set_uncertainty.R ├── bin_ml_rec.R ├── bin_par_rec.R ├── data_doc.R ├── smooth_rec.R ├── hist_evalues.R ├── bin_tables.R ├── niche_bars.R ├── stats_eval.R ├── bin_table.R ├── niche_diffbars.R ├── stats_evalues.R ├── bin_tables0.R └── histograms_env.R ├── .gitignore ├── data ├── tree.rda ├── tree5.rda ├── occ_list.rda ├── tree_data.rda ├── par_rec_table.rda └── character_table.rda ├── inst ├── extdata │ ├── m1.gpkg │ ├── m2.gpkg │ ├── m3.gpkg │ ├── m4.gpkg │ ├── m5.gpkg │ ├── m6.gpkg │ └── temp.tif └── CITATION ├── wiki_files ├── hist.png ├── nichevol_logo.png ├── nichevol_plot.png └── data_structure.png ├── CRAN-SUBMISSION ├── README_files └── figure-gfm │ ├── an_niches-1.png │ ├── histogram-1.png │ ├── niche_evol-1.png │ ├── tree_data-1.png │ ├── map_nichevol-1.png │ ├── niche_evolfin-1.png │ └── tree_niches-1.png ├── CRAN-RELEASE ├── .Rbuildignore ├── .travis.yml ├── nichevol.Rproj ├── man ├── tree.Rd ├── tree5.Rd ├── temp.Rd ├── m.Rd ├── occ_list.Rd ├── tree_data.Rd ├── character_table.Rd ├── rename_tips.Rd ├── read_bin_table.Rd ├── par_rec_table.Rd ├── sig_sq.Rd ├── smooth_rec.Rd ├── bin_par_rec.Rd ├── score_tree.Rd ├── bin_ml_rec.Rd ├── bin_env.Rd ├── nichevol.Rd ├── score_tip.Rd ├── set_uncertainty.Rd ├── niche_legend.Rd ├── pdf_histograms.Rd ├── hist_evalues.Rd ├── nichevol_legend.Rd ├── niche_labels.Rd ├── niche_bars.Rd ├── stats_eval.Rd ├── map_nichevol.Rd ├── bin_tables.Rd ├── nichevol_labels.Rd ├── bin_table.Rd ├── nichevol_bars.Rd ├── histograms_env.Rd ├── stats_evalues.Rd └── bin_tables0.Rd ├── NEWS.md ├── NAMESPACE ├── DESCRIPTION └── cran-comments.md /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /R/globals.R: -------------------------------------------------------------------------------- 1 | utils::globalVariables(c(".PlotPhyloEnv")) 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /data/tree.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/data/tree.rda -------------------------------------------------------------------------------- /data/tree5.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/data/tree5.rda -------------------------------------------------------------------------------- /data/occ_list.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/data/occ_list.rda -------------------------------------------------------------------------------- /data/tree_data.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/data/tree_data.rda -------------------------------------------------------------------------------- /inst/extdata/m1.gpkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/inst/extdata/m1.gpkg -------------------------------------------------------------------------------- /inst/extdata/m2.gpkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/inst/extdata/m2.gpkg -------------------------------------------------------------------------------- /inst/extdata/m3.gpkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/inst/extdata/m3.gpkg -------------------------------------------------------------------------------- /inst/extdata/m4.gpkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/inst/extdata/m4.gpkg -------------------------------------------------------------------------------- /inst/extdata/m5.gpkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/inst/extdata/m5.gpkg -------------------------------------------------------------------------------- /inst/extdata/m6.gpkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/inst/extdata/m6.gpkg -------------------------------------------------------------------------------- /wiki_files/hist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/wiki_files/hist.png -------------------------------------------------------------------------------- /data/par_rec_table.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/data/par_rec_table.rda -------------------------------------------------------------------------------- /inst/extdata/temp.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/inst/extdata/temp.tif -------------------------------------------------------------------------------- /data/character_table.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/data/character_table.rda -------------------------------------------------------------------------------- /wiki_files/nichevol_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/wiki_files/nichevol_logo.png -------------------------------------------------------------------------------- /wiki_files/nichevol_plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/wiki_files/nichevol_plot.png -------------------------------------------------------------------------------- /wiki_files/data_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/wiki_files/data_structure.png -------------------------------------------------------------------------------- /CRAN-SUBMISSION: -------------------------------------------------------------------------------- 1 | Version: 0.1.20 2 | Date: 2023-03-08 16:36:43 UTC 3 | SHA: c03881ec5fb0205ff4060ffcc710ca13b9883319 4 | -------------------------------------------------------------------------------- /README_files/figure-gfm/an_niches-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/README_files/figure-gfm/an_niches-1.png -------------------------------------------------------------------------------- /README_files/figure-gfm/histogram-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/README_files/figure-gfm/histogram-1.png -------------------------------------------------------------------------------- /README_files/figure-gfm/niche_evol-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/README_files/figure-gfm/niche_evol-1.png -------------------------------------------------------------------------------- /README_files/figure-gfm/tree_data-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/README_files/figure-gfm/tree_data-1.png -------------------------------------------------------------------------------- /README_files/figure-gfm/map_nichevol-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/README_files/figure-gfm/map_nichevol-1.png -------------------------------------------------------------------------------- /README_files/figure-gfm/niche_evolfin-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/README_files/figure-gfm/niche_evolfin-1.png -------------------------------------------------------------------------------- /README_files/figure-gfm/tree_niches-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marlonecobos/nichevol/HEAD/README_files/figure-gfm/tree_niches-1.png -------------------------------------------------------------------------------- /CRAN-RELEASE: -------------------------------------------------------------------------------- 1 | This package was submitted to CRAN on 2020-02-21. 2 | Once it is accepted, delete this file and tag the release (commit 2290111842). 3 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^README.Rmd 4 | ^README_files 5 | ^wiki_files 6 | ^cran-comments.md$ 7 | ^\.travis\.yml$ 8 | ^CRAN-RELEASE$ 9 | ^\.github$ 10 | ^CRAN-SUBMISSION$ 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | sudo: required 5 | 6 | before_install: 7 | - sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable --yes 8 | - sudo apt-get --yes --force-yes update -qq 9 | - sudo apt-get install -y libudunits2-dev libproj-dev libgeos++-dev libgdal-dev libv8-3.14-dev libmagick++-dev 10 | 11 | cache: packages 12 | -------------------------------------------------------------------------------- /nichevol.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | -------------------------------------------------------------------------------- /man/tree.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_doc.R 3 | \docType{data} 4 | \name{tree} 5 | \alias{tree} 6 | \title{Example of a phylogenetic tree for six species} 7 | \format{ 8 | An object of class phylo for 6 species. 9 | } 10 | \usage{ 11 | tree 12 | } 13 | \description{ 14 | A phylogenetic tree with 6 species and their relationships. 15 | } 16 | \examples{ 17 | data("tree", package = "nichevol") 18 | 19 | str(tree) 20 | } 21 | \keyword{datasets} 22 | -------------------------------------------------------------------------------- /man/tree5.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_doc.R 3 | \docType{data} 4 | \name{tree5} 5 | \alias{tree5} 6 | \title{Example of a phylogenetic tree for five species} 7 | \format{ 8 | An object of class phylo for 5 species. 9 | } 10 | \usage{ 11 | tree5 12 | } 13 | \description{ 14 | A phylogenetic tree with 5 species and their relationships. 15 | } 16 | \examples{ 17 | data("tree5", package = "nichevol") 18 | 19 | str(tree5) 20 | } 21 | \keyword{datasets} 22 | -------------------------------------------------------------------------------- /man/temp.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_doc.R 3 | \name{temp} 4 | \alias{temp} 5 | \title{Example of an environmental variable used in analysis} 6 | \format{ 7 | A SpatRaster object. 8 | } 9 | \value{ 10 | No return value, used with function \code{\link[terra]{rast}} to 11 | bring an example of an environmental variable used in analysis. 12 | } 13 | \description{ 14 | A SpatRaster object representing the variable temperature. 15 | } 16 | \examples{ 17 | temp <- terra::rast(system.file("extdata", "temp.tif", package = "nichevol")) 18 | 19 | terra::plot(temp) 20 | } 21 | -------------------------------------------------------------------------------- /man/m.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_doc.R 3 | \name{m} 4 | \alias{m} 5 | \alias{m1} 6 | \alias{m2} 7 | \alias{m3} 8 | \alias{m4} 9 | \alias{m5} 10 | \alias{m6} 11 | \title{Example of accessible areas for a species} 12 | \format{ 13 | A SpatVector object. 14 | } 15 | \value{ 16 | No return value, used with function \code{\link[terra]{vect}} to 17 | bring an example of an accessible area for a species. 18 | } 19 | \description{ 20 | A SpatVector object representing the accessible area for a species. 21 | } 22 | \examples{ 23 | m1 <- terra::vect(system.file("extdata", "m1.gpkg", package = "nichevol")) 24 | 25 | terra::plot(m1) 26 | } 27 | -------------------------------------------------------------------------------- /man/occ_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_doc.R 3 | \docType{data} 4 | \name{occ_list} 5 | \alias{occ_list} 6 | \title{Example of occurrence records for six species} 7 | \format{ 8 | A list of 6 data.frames: 9 | \describe{ 10 | \item{species}{species name, a code in this example} 11 | \item{x}{longitude, longitude value} 12 | \item{y}{latitude, latitude value} 13 | } 14 | } 15 | \usage{ 16 | occ_list 17 | } 18 | \description{ 19 | A list of 6 data.frames containing name and geographic coordinates for 20 | 6 species. 21 | } 22 | \examples{ 23 | data("occ_list", package = "nichevol") 24 | 25 | str(occ_list) 26 | } 27 | \keyword{datasets} 28 | -------------------------------------------------------------------------------- /man/tree_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_doc.R 3 | \docType{data} 4 | \name{tree_data} 5 | \alias{tree_data} 6 | \title{Example of a list containing a tree and a table of characters for six species} 7 | \format{ 8 | A list of 2 elements: 9 | \describe{ 10 | \item{phy}{object of class phylo for 6 species} 11 | \item{data}{matrix of 6 rows and 28 columns} 12 | } 13 | } 14 | \usage{ 15 | tree_data 16 | } 17 | \description{ 18 | A list of 2 elements (phy and data) resulting from using the function 19 | \code{\link[geiger]{treedata}}. 20 | } 21 | \examples{ 22 | data("tree_data", package = "nichevol") 23 | 24 | str(tree_data) 25 | } 26 | \keyword{datasets} 27 | -------------------------------------------------------------------------------- /man/character_table.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_doc.R 3 | \docType{data} 4 | \name{character_table} 5 | \alias{character_table} 6 | \title{Example of character table for six species} 7 | \format{ 8 | A character matrix with 6 rows and 28 columns. 9 | } 10 | \usage{ 11 | character_table 12 | } 13 | \description{ 14 | A character table representing species ecological niches derived from 15 | previous preparation processes. Each row represents a species and each column 16 | a binary character in which one or more values of the environmental variable 17 | are categorized as used "1", non used "0", or uncertain "?". 18 | } 19 | \examples{ 20 | data("character_table", package = "nichevol") 21 | 22 | head(character_table) 23 | } 24 | \keyword{datasets} 25 | -------------------------------------------------------------------------------- /man/rename_tips.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{rename_tips} 4 | \alias{rename_tips} 5 | \title{Helper function to rename tips of trees for simulations} 6 | \usage{ 7 | rename_tips(tree, names) 8 | } 9 | \arguments{ 10 | \item{tree}{an object of class "phylo".} 11 | 12 | \item{names}{(character) vector of new names. Length must be equal to number 13 | of tips. They will be assigned in the order given.} 14 | } 15 | \value{ 16 | Tree of class "phylo" with specified names 17 | } 18 | \description{ 19 | Helper function to rename tips of trees for simulations 20 | } 21 | \examples{ 22 | # a simple tree 23 | data("tree5", package = "nichevol") 24 | 25 | # renaming tips 26 | renamedTree <- rename_tips(tree5, c("a", "b", "c", "d", "e")) 27 | } 28 | -------------------------------------------------------------------------------- /man/read_bin_table.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/read_bin_table.R 3 | \name{read_bin_table} 4 | \alias{read_bin_table} 5 | \alias{read_bin_tables} 6 | \title{Read tables of binary niche characters from directory} 7 | \usage{ 8 | read_bin_table(file) 9 | 10 | read_bin_tables(directory) 11 | } 12 | \arguments{ 13 | \item{file}{(character) name of CSV file containing a table of binary niche 14 | characters.} 15 | 16 | \item{directory}{(character) name of directory where tables of binary niche 17 | characters were written as CSV files.} 18 | } 19 | \value{ 20 | A matrix if \code{read_bin_table} is used. 21 | 22 | A list of matrices if \code{read_bin_tables} is used. 23 | } 24 | \description{ 25 | Read one or multiple tables binary niche characters from 26 | directory. 27 | } 28 | -------------------------------------------------------------------------------- /man/par_rec_table.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_doc.R 3 | \docType{data} 4 | \name{par_rec_table} 5 | \alias{par_rec_table} 6 | \title{Example of table with results from parsimony reconstructions} 7 | \format{ 8 | A character matrix with 11 rows and 20 columns. 9 | } 10 | \usage{ 11 | par_rec_table 12 | } 13 | \description{ 14 | A character table representing species ecological niches derived from 15 | previous preparation processes and reconstructed niches for ancestors. 16 | Each row represents a species or a node and each column a binary 17 | character in which one or more values of the environmental variable 18 | are categorized as used "1", non used "0", or uncertain "?". 19 | } 20 | \examples{ 21 | data("par_rec_table", package = "nichevol") 22 | 23 | head(par_rec_table) 24 | } 25 | \keyword{datasets} 26 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | citHeader("To cite nichevol in publications use:") 2 | 3 | bibentry( 4 | bibtype = "Article", 5 | title = "Acknowledging uncertainty in evolutionary reconstructions of ecological niches", 6 | author = c(person("Hannah L.", "Owens"), 7 | person("Vivian", "Ribeiro"), 8 | person("Erin E.", "Saupe"), 9 | person("Marlon E.", "Cobos"), 10 | person("Peter A.", "Hosner"), 11 | person("Jacob C.", "Cooper"), 12 | person("Abdallah M.", "Samy"), 13 | person("Vijay", "Barve"), 14 | person("Narayani", "Barve"), 15 | person("Carlos J.", "Muñoz-R"), 16 | person("A. Townsend", "Peterson")), 17 | journal = "Ecology and Evolution", 18 | year = "2020", 19 | volume = "10", 20 | number = "14", 21 | pages = "6967–6977", 22 | url = "https://doi.org/10.1002/ece3.6359", 23 | doi = "10.1002/ece3.6359", 24 | ) 25 | -------------------------------------------------------------------------------- /man/sig_sq.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{sig_sq} 4 | \alias{sig_sq} 5 | \title{Helper function to get sigma squared values for a given dataset} 6 | \usage{ 7 | sig_sq(tree_data, model = "BM") 8 | } 9 | \arguments{ 10 | \item{tree_data}{a list of two elements (phy and data) resulted from using 11 | the function \code{\link[geiger]{treedata}}. NOTE: data must be a single 12 | vector (i.e., a single column).} 13 | 14 | \item{model}{model to fit to comparative data; see 15 | \code{\link[geiger]{fitContinuous}}. Default = "BM".} 16 | } 17 | \value{ 18 | the sigma squared value (evolutionary rate) for the data, given the 19 | tree. 20 | } 21 | \description{ 22 | Sigma squared values for a single niche summary statistic 23 | are calculated using \code{\link[geiger]{fitContinuous}}. 24 | } 25 | \examples{ 26 | # a simple tree 27 | data("tree5", package = "nichevol") 28 | 29 | # simple data 30 | data <- rnorm(n = length(tree5$tip.label)) 31 | names(data) <- tree5$tip.label 32 | # tree with data 33 | treeWdata <- geiger::treedata(tree5, data) 34 | 35 | # Estimating sigma squared for the dataset 36 | sig_sq(treeWdata) 37 | } 38 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # nichevol 0.1.20 2 | Fourth release with all tools working and with the following updates: 3 | 4 | * Improved algorithms to prepare data for analysis. 5 | * Replaced functions from the packages sp, raster, and rgdal, with functions from terra. 6 | * Deprecated the argument bin_size and replace it with n_bins to make data processing more efficient when creating tables of binary niche characters. 7 | * Improved error and warning messages. 8 | * Added the argument verbose to make message suppression easier in functions that needed it. 9 | * Improved documentation of most functions. 10 | * Added functions to help mapping niche evolution detected based on reconstructions. 11 | * Added function to help read prepared data written in a directory. 12 | * Added function to help set uncertainty manually in examples with poorly known species. 13 | 14 | 15 | # nichevol 0.1.19 16 | Third release with all tools working 17 | 18 | 19 | # nichevol 0.1.17 20 | Second release after changes suggested by CRAN-member 21 | 22 | * Messages are written using `messages()` 23 | * Examples are running while checking 24 | * Examples write info in temporal directory 25 | * Scientific references added to Description 26 | 27 | Also, reconstruction smoothing has been improved. 28 | 29 | # nichevol 0.1.16 30 | Initial release after checking 31 | -------------------------------------------------------------------------------- /man/smooth_rec.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/smooth_rec.R 3 | \name{smooth_rec} 4 | \alias{smooth_rec} 5 | \title{Smooth character table values resulted from ancestral character state reconstructions} 6 | \usage{ 7 | smooth_rec(whole_rec_table) 8 | } 9 | \arguments{ 10 | \item{whole_rec_table}{matrix containing all reconstructed characters for all 11 | tips and nodes. It results from using the functions \code{\link{bin_par_rec}} 12 | or \code{\link{bin_ml_rec}}.} 13 | } 14 | \value{ 15 | The matrix of reconstructed characters with smoothed values. 16 | } 17 | \description{ 18 | Smooth character table values resulted from ancestral character state reconstructions 19 | } 20 | \examples{ 21 | # a simple tree 22 | data("tree5", package = "nichevol") 23 | 24 | # simple matrix of data 25 | dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 26 | "242" = rep("1", length(tree5$tip.label)), 27 | "243" = c("1", "1", "0", "0", "0"), 28 | "244" = c("1", "1", "0", "0", "0"), 29 | "245" = c("1", "?", "0", "0", "0")) 30 | rownames(dataTable) <- tree5$tip.label 31 | treeWdata <- geiger::treedata(tree5, dataTable) 32 | 33 | # ancestral reconstruction 34 | parsimonyReconstruction <- bin_par_rec(treeWdata) 35 | 36 | # smoothing reconstructions 37 | smooth_rec(parsimonyReconstruction) 38 | } 39 | -------------------------------------------------------------------------------- /.github/workflows/check-standard.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: macos-latest, r: 'release'} 22 | - {os: windows-latest, r: 'release'} 23 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 24 | - {os: ubuntu-latest, r: 'release'} 25 | - {os: ubuntu-latest, r: 'oldrel-1'} 26 | 27 | env: 28 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 29 | R_KEEP_PKG_SOURCE: yes 30 | 31 | steps: 32 | - uses: actions/checkout@v3 33 | 34 | - uses: r-lib/actions/setup-pandoc@v2 35 | 36 | - uses: r-lib/actions/setup-r@v2 37 | with: 38 | r-version: ${{ matrix.config.r }} 39 | http-user-agent: ${{ matrix.config.http-user-agent }} 40 | use-public-rspm: true 41 | 42 | - uses: r-lib/actions/setup-r-dependencies@v2 43 | with: 44 | extra-packages: any::rcmdcheck 45 | needs: check 46 | 47 | - uses: r-lib/actions/check-r-package@v2 48 | with: 49 | upload-snapshots: true 50 | -------------------------------------------------------------------------------- /man/bin_par_rec.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bin_par_rec.R 3 | \name{bin_par_rec} 4 | \alias{bin_par_rec} 5 | \title{Maximum parsimony reconstruction of ancestral character states} 6 | \usage{ 7 | bin_par_rec(tree_data, ...) 8 | } 9 | \arguments{ 10 | \item{tree_data}{a list of two elements (phy and data) resulting from using 11 | the function \code{\link[geiger]{treedata}}.} 12 | 13 | \item{...}{other arguments from \code{\link[castor]{asr_max_parsimony}}. 14 | Arguments \code{tree} and \code{tip_states} are fixed.} 15 | } 16 | \value{ 17 | A table with columns representing bins, rows representing first tip 18 | states and then reconstructed nodes. 19 | } 20 | \description{ 21 | Maximum parsimony reconstruction of ancestral character states 22 | } 23 | \details{ 24 | Reconstructions are done using the \code{\link[castor]{asr_max_parsimony}} 25 | function from the \code{castor} package. 26 | } 27 | \examples{ 28 | # a simple tree 29 | data("tree5", package = "nichevol") 30 | 31 | # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 32 | dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 33 | "242" = rep("1", length(tree5$tip.label)), 34 | "243" = c("1", "1", "0", "0", "0"), 35 | "244" = c("1", "1", "0", "0", "0"), 36 | "245" = c("1", "?", "0", "0", "0")) 37 | rownames(dataTable) <- tree5$tip.label 38 | 39 | # list with two objects (tree and character table) 40 | treeWdata <- geiger::treedata(tree5, dataTable) 41 | 42 | # Maximum parsimony reconstruction 43 | par_rec <- bin_par_rec(treeWdata) 44 | } 45 | -------------------------------------------------------------------------------- /man/score_tree.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{score_tree} 4 | \alias{score_tree} 5 | \title{Helper function to assign bin scores to every tip in a given tree} 6 | \usage{ 7 | score_tree(tree_data, include_unknown = FALSE) 8 | } 9 | \arguments{ 10 | \item{tree_data}{a list of two elements (phy and data) resulting from using 11 | the function \code{\link[geiger]{treedata}}.} 12 | 13 | \item{include_unknown}{(logical) whether or not there are unknown tips.} 14 | } 15 | \value{ 16 | a list of two elements (phy and data). Data is the median bin scored 17 | as present or present + unknown. 18 | } 19 | \description{ 20 | Helper function to assign bin scores to every tip in a given tree 21 | } 22 | \examples{ 23 | # Simulate data table 24 | dataTable <- cbind("241" = rep("1", 5), 25 | "242" = rep("1", 5), 26 | "243" = c("1", "1", "0", "0", "0"), 27 | "244" = c("1", "1", "0", "0", "0"), 28 | "245" = c("1", "?", "0", "0", "0")) 29 | rownames(dataTable) <- c("GadusMorhua", "GadusMacrocephalus", 30 | "GadusChalcogrammus", "ArctogadusGlacials", 31 | "BoreogadusSaida") 32 | 33 | # a simple tree 34 | data("tree5", package = "nichevol") 35 | tree5$tip.label <- c("GadusMorhua", "GadusMacrocephalus", 36 | "GadusChalcogrammus", "ArctogadusGlacials", 37 | "BoreogadusSaida") 38 | 39 | # Unite data 40 | treeWithData <- geiger::treedata(tree5, dataTable) 41 | 42 | # Get a new tree with tips scored from median bin scores 43 | score_tree(treeWithData, include_unknown = TRUE) 44 | } 45 | -------------------------------------------------------------------------------- /man/bin_ml_rec.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bin_ml_rec.R 3 | \name{bin_ml_rec} 4 | \alias{bin_ml_rec} 5 | \title{Maximum likelihood reconstruction of ancestral character states} 6 | \usage{ 7 | bin_ml_rec(tree_data, ...) 8 | } 9 | \arguments{ 10 | \item{tree_data}{a list of two elements (phy and data) resulting from using the 11 | function \code{\link[geiger]{treedata}}.} 12 | 13 | \item{...}{other arguments from \code{\link[ape]{ace}}. Arguments \code{x}, 14 | \code{phy}, \code{type}, and \code{method} are fixed.} 15 | } 16 | \value{ 17 | A table with columns representing bins, rows representing first tip 18 | states and then reconstructed nodes. 19 | } 20 | \description{ 21 | Maximum likelihood reconstruction of ancestral character states 22 | } 23 | \details{ 24 | Reconstructions are done using the function \code{\link[ape]{ace}} from the 25 | \code{ape} package. The argument method is set as "ML" and the type 26 | of variable is "discrete". 27 | } 28 | \examples{ 29 | # a simple tree 30 | data("tree5", package = "nichevol") 31 | 32 | # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 33 | dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 34 | "242" = rep("1", length(tree5$tip.label)), 35 | "243" = c("1", "1", "0", "0", "0"), 36 | "244" = c("1", "1", "0", "0", "0"), 37 | "245" = c("1", "?", "0", "0", "0")) 38 | rownames(dataTable) <- tree5$tip.label 39 | 40 | # list with two objects (tree and character table) 41 | treeWdata <- geiger::treedata(tree5, dataTable) 42 | 43 | # Maximum likelihood reconstruction 44 | ml_rec <- bin_ml_rec(treeWdata) 45 | } 46 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(bin_env) 4 | export(bin_ml_rec) 5 | export(bin_par_rec) 6 | export(bin_table) 7 | export(bin_tables) 8 | export(bin_tables0) 9 | export(hist_evalues) 10 | export(histograms_env) 11 | export(map_nichevol) 12 | export(niche_bars) 13 | export(niche_labels) 14 | export(niche_legend) 15 | export(nichevol_bars) 16 | export(nichevol_labels) 17 | export(nichevol_legend) 18 | export(pdf_histograms) 19 | export(read_bin_table) 20 | export(read_bin_tables) 21 | export(rename_tips) 22 | export(score_tip) 23 | export(score_tree) 24 | export(set_uncertainty) 25 | export(sig_sq) 26 | export(smooth_rec) 27 | export(stats_eval) 28 | export(stats_evalues) 29 | importFrom(ape,ace) 30 | importFrom(ape,reorder.phylo) 31 | importFrom(castor,asr_max_parsimony) 32 | importFrom(geiger,fitContinuous) 33 | importFrom(geiger,treedata) 34 | importFrom(grDevices,dev.off) 35 | importFrom(grDevices,gray.colors) 36 | importFrom(grDevices,pdf) 37 | importFrom(grDevices,png) 38 | importFrom(graphics,abline) 39 | importFrom(graphics,hist) 40 | importFrom(graphics,layout) 41 | importFrom(graphics,legend) 42 | importFrom(graphics,lines) 43 | importFrom(graphics,par) 44 | importFrom(graphics,plot) 45 | importFrom(graphics,plot.new) 46 | importFrom(graphics,points) 47 | importFrom(graphics,polygon) 48 | importFrom(graphics,title) 49 | importFrom(stats,median) 50 | importFrom(stats,na.omit) 51 | importFrom(stats,smooth) 52 | importFrom(stringr,str_extract) 53 | importFrom(stringr,str_replace) 54 | importFrom(terra,NAflag) 55 | importFrom(terra,classify) 56 | importFrom(terra,crop) 57 | importFrom(terra,extract) 58 | importFrom(terra,minmax) 59 | importFrom(terra,nlyr) 60 | importFrom(terra,rast) 61 | importFrom(terra,unique) 62 | importFrom(terra,vect) 63 | importFrom(utils,combn) 64 | importFrom(utils,read.csv) 65 | importFrom(utils,write.csv) 66 | -------------------------------------------------------------------------------- /man/bin_env.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{bin_env} 4 | \alias{bin_env} 5 | \title{Helper function to prepare bin tables} 6 | \usage{ 7 | bin_env(overall_range, M_range, sp_range, bin_size) 8 | } 9 | \arguments{ 10 | \item{overall_range}{(numeric) minimum and maximum values of all species and 11 | Ms to be analyzed.} 12 | 13 | \item{M_range}{matrix of ranges of environmental values in M for all species. 14 | Columns must be minimum and maximum, and rows correspond to species.} 15 | 16 | \item{sp_range}{matrix of ranges of environmental values in occurrences 17 | for all species. Columns must be minimum and maximum, and rows correspond to 18 | species.} 19 | 20 | \item{bin_size}{(numeric) size of bins. Range of environmental values to 21 | be considered when creating each character in bin tables. See details.} 22 | } 23 | \value{ 24 | A character matrix (table of characters) containing bins for a given variable 25 | and for all species considered. See more details in \code{\link{bin_tables}}. 26 | } 27 | \description{ 28 | Helper function to prepare bin tables 29 | } 30 | \details{ 31 | The argument \code{bin_size} helps to create characters that represent not 32 | only one value of an environmental variable, but a range of environmental 33 | conditions. For instance, if a variable of precipitation in mm is used, a 34 | value of 10 for \code{bin_size} indicates that each character will represent 35 | a class that correspond to 10 continuous values of precipitation (e.g., from 36 | 100 to 110 mm). 37 | } 38 | \examples{ 39 | # example 40 | o_range <- c(1, 25) 41 | m_range <- rbind(c(5, 15), c(10, 23), c(4, 20)) 42 | s_range <- rbind(c(7, 15), c(12, 21), c(3, 18)) 43 | 44 | # bin preparation 45 | bins <- bin_env(overall_range = o_range, M_range = m_range, 46 | sp_range = s_range, bin_size = 1) 47 | } 48 | -------------------------------------------------------------------------------- /R/nichevol.R: -------------------------------------------------------------------------------- 1 | #' nichevol: Assessment of Species’ Ecological Niche Evolution Considering 2 | #' Uncertainty in Reconstructions 3 | #' 4 | #' nichevol is a collection of tools that allow users to perform critical steps 5 | #' in the process of assessing ecological niche evolution over phylogenies, with 6 | #' uncertainty incorporated explicitly in reconstructions. The method proposed 7 | #' here for ancestral reconstruction of ecological niches characterizes species' 8 | #' niches using a bin-based approach that incorporates uncertainty in estimations. 9 | #' Compared to other existing methods, the approaches presented here reduce risk 10 | #' of overestimation of amounts and rates of ecological niche evolution. The 11 | #' main analyses include: initial exploration of environmental data in occurrence 12 | #' records and accessible areas, preparation of data for phylogenetic analyses, 13 | #' executing comparative phylogenetic analyses of ecological niches, and plotting 14 | #' for interpretations. 15 | #' 16 | #' @section Main functions in nichevol: 17 | #' \code{\link{bin_ml_rec}}, \code{\link{bin_par_rec}}, \code{\link{bin_table}}, 18 | #' \code{\link{bin_tables}}, \code{\link{bin_tables0}}, \code{\link{hist_evalues}}, 19 | #' \code{\link{histograms_env}}, \code{\link{map_nichevol}}, 20 | #' \code{\link{niche_bars}}, \code{\link{nichevol_bars}}, 21 | #' \code{\link{niche_labels}}, \code{\link{nichevol_labels}}, 22 | #' \code{\link{niche_legend}}, \code{\link{nichevol_legend}}, 23 | #' \code{\link{set_uncertainty}}, \code{\link{smooth_rec}}, 24 | #' \code{\link{stats_eval}}, \code{\link{stats_evalues}} 25 | #' 26 | #' Other functions (important helpers) 27 | #' 28 | #' \code{\link{bin_env}}, \code{\link{pdf_histograms}}, 29 | #' \code{\link{rename_tips}}, \code{\link{score_tip}}, 30 | #' \code{\link{score_tree}}, \code{\link{sig_sq}} 31 | #' 32 | #' @docType package 33 | #' @name nichevol 34 | NULL 35 | -------------------------------------------------------------------------------- /man/nichevol.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/nichevol.R 3 | \docType{package} 4 | \name{nichevol} 5 | \alias{nichevol} 6 | \title{nichevol: Assessment of Species’ Ecological Niche Evolution Considering 7 | Uncertainty in Reconstructions} 8 | \description{ 9 | nichevol is a collection of tools that allow users to perform critical steps 10 | in the process of assessing ecological niche evolution over phylogenies, with 11 | uncertainty incorporated explicitly in reconstructions. The method proposed 12 | here for ancestral reconstruction of ecological niches characterizes species' 13 | niches using a bin-based approach that incorporates uncertainty in estimations. 14 | Compared to other existing methods, the approaches presented here reduce risk 15 | of overestimation of amounts and rates of ecological niche evolution. The 16 | main analyses include: initial exploration of environmental data in occurrence 17 | records and accessible areas, preparation of data for phylogenetic analyses, 18 | executing comparative phylogenetic analyses of ecological niches, and plotting 19 | for interpretations. 20 | } 21 | \section{Main functions in nichevol}{ 22 | 23 | \code{\link{bin_ml_rec}}, \code{\link{bin_par_rec}}, \code{\link{bin_table}}, 24 | \code{\link{bin_tables}}, \code{\link{bin_tables0}}, \code{\link{hist_evalues}}, 25 | \code{\link{histograms_env}}, \code{\link{map_nichevol}}, 26 | \code{\link{niche_bars}}, \code{\link{nichevol_bars}}, 27 | \code{\link{niche_labels}}, \code{\link{nichevol_labels}}, 28 | \code{\link{niche_legend}}, \code{\link{nichevol_legend}}, 29 | \code{\link{set_uncertainty}}, \code{\link{smooth_rec}}, 30 | \code{\link{stats_eval}}, \code{\link{stats_evalues}} 31 | 32 | Other functions (important helpers) 33 | 34 | \code{\link{bin_env}}, \code{\link{pdf_histograms}}, 35 | \code{\link{rename_tips}}, \code{\link{score_tip}}, 36 | \code{\link{score_tree}}, \code{\link{sig_sq}} 37 | } 38 | 39 | -------------------------------------------------------------------------------- /R/read_bin_table.R: -------------------------------------------------------------------------------- 1 | #' Read tables of binary niche characters from directory 2 | #' 3 | #' @description Read one or multiple tables binary niche characters from 4 | #' directory. 5 | #' 6 | #' @param file (character) name of CSV file containing a table of binary niche 7 | #' characters. 8 | #' 9 | #' @rdname read_bin_table 10 | #' 11 | #' @return 12 | #' A matrix if \code{read_bin_table} is used. 13 | #' 14 | #' A list of matrices if \code{read_bin_tables} is used. 15 | #' 16 | #' @export 17 | 18 | read_bin_table <- function(file) { 19 | if (missing(file)) {stop("Argument 'file' must be defined.")} 20 | if (class(file)[1] != "character") { 21 | stop("'file' must be a character.") 22 | } 23 | 24 | tab <- read.csv(file[1], row.names = 1) 25 | 26 | cnames <- colnames(tab) 27 | 28 | colnames(tab) <- gsub("X", "", 29 | gsub("X.", "-", 30 | gsub(".to.", " to ", 31 | gsub(".to..", " to -", cnames, fixed = TRUE), 32 | fixed = TRUE), 33 | fixed = TRUE)) 34 | 35 | return(as.matrix(tab)) 36 | } 37 | 38 | 39 | #' @param directory (character) name of directory where tables of binary niche 40 | #' characters were written as CSV files. 41 | #' 42 | #' @rdname read_bin_table 43 | #' 44 | #' @export 45 | 46 | read_bin_tables <- function(directory) { 47 | if (missing(directory)) {stop("Argument 'directory' must be defined.")} 48 | if (!dir.exists(directory)) {stop("'directory' does not exist.")} 49 | if (class(directory)[1] != "character") { 50 | stop("'directory' must be a character.") 51 | } 52 | 53 | files <- list.files(directory, pattern = ".csv$", full.names = TRUE) 54 | filenam <- list.files(directory, pattern = ".csv$") 55 | filenam <- gsub("_bin_table.csv", "", filenam) 56 | 57 | tabs <- lapply(files, read_bin_table) 58 | 59 | names(tabs) <- filenam 60 | 61 | return(tabs) 62 | } 63 | -------------------------------------------------------------------------------- /man/score_tip.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{score_tip} 4 | \alias{score_tip} 5 | \title{Helper function to calculate the median bin score for a given species} 6 | \usage{ 7 | score_tip(character_table, species_name, include_unknown = FALSE) 8 | } 9 | \arguments{ 10 | \item{character_table}{data.frame containing bin scores for all species. 11 | NOTE: row names must be species' names.} 12 | 13 | \item{species_name}{(character) name of the species to be analyzed.} 14 | 15 | \item{include_unknown}{(logical) whether or not unknown bin status should be 16 | included.} 17 | } 18 | \value{ 19 | Median bin value for a given species (for inferring sigma squared or 20 | other comparative phylogenetic analyses requiring a single continuous variable). 21 | } 22 | \description{ 23 | Helper function to calculate the median bin score for a given species 24 | } 25 | \examples{ 26 | # Simulate data for single number bin labels 27 | dataTable <- cbind("241" = rep("1", 5), 28 | "242" = rep("1", 5), 29 | "243" = c("1", "1", "0", "0", "0"), 30 | "244" = c("1", "1", "0", "0", "0"), 31 | "245" = c("1", "?", "0", "0", "0")) 32 | rownames(dataTable) <- c("GadusMorhua", "GadusMacrocephalus", 33 | "GadusChalcogrammus", "ArctogadusGlacials", 34 | "BoreogadusSaida") 35 | # Simulate data for bin labels as strings 36 | dataTableStringLabel <- cbind("241 to 244" = rep("1", 5), 37 | "244 to 246" = c("1", "1", "0", "0", "0"), 38 | "246 to 248" = c("1", "?", "0", "0", "0")) 39 | rownames(dataTableStringLabel) <- c("GadusMorhua", "GadusMacrocephalus", 40 | "GadusChalcogrammus", "ArctogadusGlacials", 41 | "BoreogadusSaida") 42 | # Use function 43 | score_tip(character_table = dataTable, species_name = "GadusMorhua", 44 | include_unknown = TRUE) 45 | score_tip(character_table = dataTableStringLabel, species_name = "GadusMorhua", 46 | include_unknown = FALSE) 47 | } 48 | -------------------------------------------------------------------------------- /man/set_uncertainty.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/set_uncertainty.R 3 | \name{set_uncertainty} 4 | \alias{set_uncertainty} 5 | \title{Set values of uncertainty towards one or both ends of the variable} 6 | \usage{ 7 | set_uncertainty(character_table, species, end) 8 | } 9 | \arguments{ 10 | \item{character_table}{a matrix of characters to represent ecological niches 11 | of the species of interest. A matrix containing values "1" = presence, 12 | "0" = absence, and "?" = uncertain. See \code{\link{bin_table}}.} 13 | 14 | \item{species}{(character) name of the species in the table for which values 15 | of uncertainty will be set.} 16 | 17 | \item{end}{(character) end towards which uncertainty values ("?") will be set. 18 | Options are: "high", "low", or "both".} 19 | } 20 | \value{ 21 | A modified matrix of characters to represent ecological niches of the 22 | species of interest. 23 | 24 | Potential values for characters are: 25 | \itemize{ 26 | \item "1" = the species is present in those environmental conditions. 27 | \item "0" = the species is not present in those environmental conditions. This is, 28 | those environmental conditions inside the accessible area (M) are more extreme 29 | than the ones used for the species. 30 | \item "?" = there is no certainty about the species presence in those environmental 31 | conditions. 32 | } 33 | } 34 | \description{ 35 | set_uncertainty allows to define uncertainty ("?") values 36 | around values denoting presence ("1") towards one or both ends of the 37 | variable in a table of binary characters. 38 | } 39 | \details{ 40 | Values of characters around those denoting presence ("1") are manually 41 | transformed to uncertain ("?") to help producing more conservative 42 | reconstructions of ancestral ecological niches. This increases uncertainty in 43 | reconstructions and further niche comparisons, which reduces the events of 44 | niche change that can be detected. This may be especially useful when dealing 45 | with species with one or just a few known records. 46 | } 47 | \examples{ 48 | # a character table 49 | data("character_table", package = "nichevol") 50 | 51 | character_table[, 20:28] 52 | 53 | # set values of uncertainty towards the lower end of the variable for species t3 54 | char_tableu <- set_uncertainty(character_table, species = "t2", end = "low") 55 | 56 | char_tableu[, 20:28] 57 | } 58 | -------------------------------------------------------------------------------- /man/niche_legend.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plotting_helpers.R 3 | \name{niche_legend} 4 | \alias{niche_legend} 5 | \title{Legends for niche labels in phylogenetic trees} 6 | \usage{ 7 | niche_legend(position, legend = c("Uncertain", "Present", "Not present"), 8 | pch = 22, pt.bg = c("#969696", "#e41a1c", "#377eb8"), 9 | col = "transparent", pt.cex = 2.2, bty = "n", ...) 10 | } 11 | \arguments{ 12 | \item{position}{(character or numeric) position of legend. If character, 13 | part of the plot (e.g., "topleft"), see \code{\link[graphics]{legend}}. If 14 | numeric, vector of two values indicating x and y position (e.g., c(0.1, 6)).} 15 | 16 | \item{legend}{(character) vector of length = three indicating the text to 17 | identify environments with uncertain presence, presence, and absence of the 18 | species. Default = c("Uncertain", "Present", "Not present").} 19 | 20 | \item{pch}{point type as in \code{\link[graphics]{points}}. Default = 22.} 21 | 22 | \item{pt.bg}{colors to represent what is in \code{legend}. 23 | Default = c("#969696", "#e41a1c", "#377eb8").} 24 | 25 | \item{col}{border of symbol (points). Default = "transparent".} 26 | 27 | \item{pt.cex}{size of symbol (points). Default = 2.2.} 28 | 29 | \item{bty}{legend border type. Default = "n".} 30 | 31 | \item{...}{Other arguments from function \code{\link[graphics]{legend}} other 32 | than the ones described above.} 33 | } 34 | \description{ 35 | Legends for niche labels in phylogenetic trees 36 | } 37 | \examples{ 38 | # a simple tree 39 | data("tree5", package = "nichevol") 40 | 41 | # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 42 | dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 43 | "242" = rep("1", length(tree5$tip.label)), 44 | "243" = c("1", "1", "0", "0", "0"), 45 | "244" = c("1", "1", "0", "0", "0"), 46 | "245" = c("1", "?", "0", "0", "0")) 47 | rownames(dataTable) <- tree5$tip.label 48 | 49 | # list with two objects (tree and character table) 50 | treeWdata <- geiger::treedata(tree5, dataTable) 51 | 52 | # Maximum parsimony reconstruction 53 | rec_tab <- smooth_rec(bin_par_rec(treeWdata)) 54 | 55 | # plotting and adding labels and legend 56 | ape::plot.phylo(tree5, label.offset = 0.04) 57 | niche_labels(tree5, rec_tab, height = 0.6) 58 | niche_legend(position = "topleft", cex = 0.7) 59 | } 60 | -------------------------------------------------------------------------------- /man/pdf_histograms.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers.R 3 | \name{pdf_histograms} 4 | \alias{pdf_histograms} 5 | \title{Helper function to create PDF files with histograms} 6 | \usage{ 7 | pdf_histograms(env_data, occ_data, y_values, sp_names, variable_name, 8 | CL_lines, limits, col, output_directory) 9 | } 10 | \arguments{ 11 | \item{env_data}{list of environmental values in M for all species.} 12 | 13 | \item{occ_data}{list of environmental values in occurrences for all species.} 14 | 15 | \item{y_values}{list of values for the y axis to be used to represent where 16 | occurrences are distributed across the environmental values in M.} 17 | 18 | \item{sp_names}{(character) names of the species for which the process will 19 | be performed.} 20 | 21 | \item{variable_name}{(character) name of the variable to be plotted.} 22 | 23 | \item{CL_lines}{(numeric) confidence limits to be plotted in the histograms.} 24 | 25 | \item{limits}{numeric matrix containing the actual values for the confidence 26 | limits of M.} 27 | 28 | \item{col}{color for lines representing the confidence limits of M.} 29 | 30 | \item{output_directory}{(character) name of the folder in which results will be 31 | written.} 32 | } 33 | \value{ 34 | A PDF file written in the output directory containing all resulting figures. 35 | } 36 | \description{ 37 | Helper function to create PDF files with histograms 38 | } 39 | \examples{ 40 | # example data 41 | e_data <- list(rnorm(1000, 15, 7), rnorm(800, 20, 6), rnorm(1000, 12, 3)) 42 | o_data <- list(sample(seq(5, 29, 0.1), 45), sample(seq(10, 33, 0.1), 40), 43 | sample(seq(1, 16, 0.1), 50)) 44 | for (i in 1:3) { 45 | names(e_data[[i]]) <- e_data[[i]] 46 | names(o_data[[i]]) <- o_data[[i]] 47 | } 48 | y_val <- list(rep(3, length(o_data)), rep(4, length(o_data)), 49 | rep(2, length(o_data))) 50 | s_names <- c("sp1", "sp2", "sp3") 51 | lims <- rbind(c(3.5, 26.47), c(10.83, 29.66), c(6.92, 16.91)) 52 | 53 | tmpd <- file.path(tempdir(), "Hist_to_check") # temporal directory 54 | dir.create(tmpd) 55 | 56 | # the running (before running, create output_directory in current directory) 57 | bins <- pdf_histograms(env_data = e_data, occ_data = o_data, y_values = y_val, 58 | sp_names = s_names, variable_name = "Temperature", 59 | CL_lines = 95, limits = lims, col = "green", 60 | output_directory = tmpd) 61 | } 62 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: nichevol 2 | Type: Package 3 | Title: Tools for Ecological Niche Evolution Assessment Considering Uncertainty 4 | Version: 0.1.20 5 | Authors@R: c( 6 | person("Marlon E.", "Cobos", email = "manubio13@gmail.com", role = c("aut","cre")), 7 | person("Hannah L.", "Owens", email = "hannah.owens@gmail.com", role = "aut"), 8 | person("A. Townsend", "Peterson", email = "town@ku.edu", role = "aut")) 9 | Author: Marlon E. Cobos [aut, cre], 10 | Hannah L. Owens [aut], 11 | A. Townsend Peterson [aut] 12 | Maintainer: Marlon E. Cobos 13 | Date: 2023-03-09 14 | Description: A collection of tools that allow users to perform critical steps 15 | in the process of assessing ecological niche evolution over phylogenies, with 16 | uncertainty incorporated explicitly in reconstructions. The method proposed 17 | here for ancestral reconstruction of ecological niches characterizes species' 18 | niches using a bin-based approach that incorporates uncertainty in estimations. 19 | Compared to other existing methods, the approaches presented here reduce risk 20 | of overestimation of amounts and rates of ecological niche evolution. The 21 | main analyses include: initial exploration of environmental data in occurrence 22 | records and accessible areas, preparation of data for phylogenetic analyses, 23 | executing comparative phylogenetic analyses of ecological niches, and plotting 24 | for interpretations. Details on the theoretical background and methods used 25 | can be found in: Owens et al. (2020) , 26 | Peterson et al. (1999) , 27 | Soberón and Peterson (2005) , 28 | Peterson (2011) , 29 | Barve et al. (2011) , 30 | Machado-Stredel et al. (2021) , 31 | Owens et al. (2013) , 32 | Saupe et al. (2018) , and 33 | Cobos et al. (2021) . 34 | URL: https://github.com/marlonecobos/nichevol 35 | BugReports: https://github.com/marlonecobos/nichevol/issues 36 | Imports: 37 | castor (>= 1.4), 38 | geiger (>= 2.0), 39 | graphics (>= 3.6), 40 | grDevices (>= 3.6), 41 | stringr (>= 1.4), 42 | stats (>= 3.6), 43 | terra (>= 1.6), 44 | utils (>= 3.6) 45 | Suggests: 46 | knitr(>= 1.25), 47 | phytools (>= 0.6) 48 | Depends: 49 | ape (>= 5.3), 50 | R (>= 3.5.0) 51 | License: GPL-3 52 | Encoding: UTF-8 53 | LazyData: true 54 | Roxygen: list(markdown = TRUE) 55 | RoxygenNote: 7.1.2 56 | -------------------------------------------------------------------------------- /R/set_uncertainty.R: -------------------------------------------------------------------------------- 1 | #' Set values of uncertainty towards one or both ends of the variable 2 | #' 3 | #' @description set_uncertainty allows to define uncertainty ("?") values 4 | #' around values denoting presence ("1") towards one or both ends of the 5 | #' variable in a table of binary characters. 6 | #' 7 | #' @param character_table a matrix of characters to represent ecological niches 8 | #' of the species of interest. A matrix containing values "1" = presence, 9 | #' "0" = absence, and "?" = uncertain. See \code{\link{bin_table}}. 10 | #' @param species (character) name of the species in the table for which values 11 | #' of uncertainty will be set. 12 | #' @param end (character) end towards which uncertainty values ("?") will be set. 13 | #' Options are: "high", "low", or "both". 14 | #' 15 | #' @details 16 | #' Values of characters around those denoting presence ("1") are manually 17 | #' transformed to uncertain ("?") to help producing more conservative 18 | #' reconstructions of ancestral ecological niches. This increases uncertainty in 19 | #' reconstructions and further niche comparisons, which reduces the events of 20 | #' niche change that can be detected. This may be especially useful when dealing 21 | #' with species with one or just a few known records. 22 | #' 23 | #' @return 24 | #' A modified matrix of characters to represent ecological niches of the 25 | #' species of interest. 26 | #' 27 | #' Potential values for characters are: 28 | #' - "1" = the species is present in those environmental conditions. 29 | #' - "0" = the species is not present in those environmental conditions. This is, 30 | #' those environmental conditions inside the accessible area (M) are more extreme 31 | #' than the ones used for the species. 32 | #' - "?" = there is no certainty about the species presence in those environmental 33 | #' conditions. 34 | #' 35 | #' @export 36 | #' 37 | #' @examples 38 | #' # a character table 39 | #' data("character_table", package = "nichevol") 40 | #' 41 | #' character_table[, 20:28] 42 | #' 43 | #' # set values of uncertainty towards the lower end of the variable for species t3 44 | #' char_tableu <- set_uncertainty(character_table, species = "t2", end = "low") 45 | #' 46 | #' char_tableu[, 20:28] 47 | 48 | set_uncertainty <- function(character_table, species, end) { 49 | species <- gsub("_", " ", species) 50 | n_col <- ncol(character_table) 51 | where <- which(character_table[species, ] == 1) 52 | 53 | if (end == "both") { 54 | character_table[species, character_table[species, ] != 1] <- "?" 55 | } 56 | if (end == "high") { 57 | if (max(where) < n_col) { 58 | start <- max(where) + 1 59 | character_table[species, start:n_col] <- "?" 60 | } 61 | } 62 | if (end == "low") { 63 | if (min(where) > 1) { 64 | end <- min(where) - 1 65 | character_table[species, 1:end] <- "?" 66 | } 67 | } 68 | 69 | return(character_table) 70 | } 71 | -------------------------------------------------------------------------------- /man/hist_evalues.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/hist_evalues.R 3 | \name{hist_evalues} 4 | \alias{hist_evalues} 5 | \title{Histograms of environmental conditions in M and for occurrences (one species)} 6 | \usage{ 7 | hist_evalues(M, occurrences, species, longitude, latitude, variable, 8 | CL_lines = c(95, 99), col = NULL) 9 | } 10 | \arguments{ 11 | \item{M}{a SpatVector object representing the accessible area (M) 12 | for one species. See details.} 13 | 14 | \item{occurrences}{a data.frame of occurrence records for one species. See 15 | details.} 16 | 17 | \item{species}{(character) name of the column in \code{occurrences} that 18 | contains the name of the species.} 19 | 20 | \item{longitude}{(character) name of the column in \code{occurrences} containing 21 | values of longitude.} 22 | 23 | \item{latitude}{(character) name of the column in \code{occurrences} containing 24 | values of latitude.} 25 | 26 | \item{variable}{a single SpatRaster layer representing an environmental 27 | variable of interest. See details.} 28 | 29 | \item{CL_lines}{(numeric) confidence limits of environmental values in M to 30 | be plotted as lines in the histograms. See details. Default = c(95, 99).} 31 | 32 | \item{col}{colors for lines representing confidence limits. If NULL, colors 33 | are selected from a gray palette. Default = NULL.} 34 | } 35 | \description{ 36 | hist_evalues helps in creating histograms to explore environmental 37 | conditions in M, lines for the confidence limits of values in M, and the 38 | location of values in occurrence records, for one species at the time. 39 | } 40 | \details{ 41 | Coordinates in \code{occurrences}, SpatVector object in \code{M}, and 42 | SpatRaster in \code{variable} must coincide in the geographic projection in 43 | which they are represented. WGS84 with no planar projection is recommended. 44 | 45 | The accessible area (M) is understood as the geographic area that has been 46 | accessible to a species over relevant periods of time. Defining M is usually 47 | a hard task, but also a very important one because it allows identifying 48 | uncertainties about the ability of a species to maintain populations under 49 | certain environmental conditions. For further details on this topic, see 50 | Barve et al. (2011) \url{doi:10.1016/j.ecolmodel.2011.02.011} 51 | and Machado-Stredel et al. (2021) \url{doi:10.21425/F5FBG48814}. 52 | } 53 | \examples{ 54 | # example data 55 | ## list of species records 56 | data("occ_list", package = "nichevol") 57 | 58 | ## list of species accessible areas 59 | m_files <- list.files(system.file("extdata", package = "nichevol"), 60 | pattern = "m\\\\d.gpkg", full.names = TRUE) 61 | 62 | m_list <- lapply(m_files, terra::vect) 63 | 64 | ## raster variable 65 | temp <- terra::rast(system.file("extdata", "temp.tif", package = "nichevol")) 66 | 67 | # running stats 68 | hist_evalues(M = m_list[[1]], occurrences = occ_list[[1]], species = "species", 69 | longitude = "x", latitude = "y", variable = temp, 70 | CL_lines = c(95, 99), col = c("blue", "red")) 71 | } 72 | -------------------------------------------------------------------------------- /man/nichevol_legend.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plotting_helpers.R 3 | \name{nichevol_legend} 4 | \alias{nichevol_legend} 5 | \title{Legends for niche evolution labels in phylogenetic trees} 6 | \usage{ 7 | nichevol_legend(position, ancestor_line = FALSE, 8 | ancestor_legend = c("Uncertain", "Present"), 9 | evol_legend = c("No change", "Retraction", "Expansion"), 10 | ancestor_col = c("#d9d9d9", "#252525"), 11 | evol_col = c("#b2df8a", "#984ea3", "#4daf4a"), 12 | pch = 22, pt.cex = 2.2, lty = 1, lwd = 1, cex = 1, bty = "n", ...) 13 | } 14 | \arguments{ 15 | \item{position}{(character or numeric) position of legend. If character, 16 | part of the plot (e.g., "topleft"), see \code{\link[graphics]{legend}}. If 17 | numeric, vector of two values indicating x and y position (e.g., c(0.1, 6)).} 18 | 19 | \item{ancestor_line}{whether or not ancestor line was plotted. 20 | Default = FALSE.} 21 | 22 | \item{ancestor_legend}{(character) vector of length = two indicating the text 23 | to identify environments with uncertain presence and true presence of the 24 | species. Default = c("Uncertain", "Present").} 25 | 26 | \item{evol_legend}{(character) vector of length = three indicating the text 27 | to identify environments where niches have not changed, have retracted or 28 | expanded. Default = c("No change", "Retraction", "Expansion").} 29 | 30 | \item{ancestor_col}{vector of two colors to represent what is indicated in 31 | \code{ancestor_legend}. Default = c("#d9d9d9", "#252525").} 32 | 33 | \item{evol_col}{vector of three colors to represent what is indicated in 34 | \code{evol_legend}. Default = c("#b2df8a", "#984ea3", "#4daf4a").} 35 | 36 | \item{pch}{point type as in \code{\link[graphics]{points}}. Default = 22.} 37 | 38 | \item{pt.cex}{size of symbol (points). Default = 2.2.} 39 | 40 | \item{lty}{line type see \code{\link[graphics]{par}}. Default = 1.} 41 | 42 | \item{lwd}{line width see \code{\link[graphics]{par}}. Default = 1.} 43 | 44 | \item{cex}{size of all elements in legend see \code{\link[graphics]{par}}. 45 | Default = 1.} 46 | 47 | \item{bty}{legend border type. Default = "n".} 48 | 49 | \item{...}{Other arguments from function \code{\link[graphics]{legend}} other 50 | than the ones described above.} 51 | } 52 | \description{ 53 | Legends for niche evolution labels in phylogenetic trees 54 | } 55 | \examples{ 56 | # a simple tree 57 | data("tree5", package = "nichevol") 58 | 59 | # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 60 | dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 61 | "242" = rep("1", length(tree5$tip.label)), 62 | "243" = c("1", "1", "0", "0", "0"), 63 | "244" = c("1", "1", "0", "0", "0"), 64 | "245" = c("1", "?", "0", "0", "0")) 65 | rownames(dataTable) <- tree5$tip.label 66 | 67 | # list with two objects (tree and character table) 68 | treeWdata <- geiger::treedata(tree5, dataTable) 69 | 70 | # Maximum parsimony reconstruction 71 | rec_tab <- smooth_rec(bin_par_rec(treeWdata)) 72 | 73 | # plotting and adding labels and legend 74 | ape::plot.phylo(tree5, label.offset = 0.04) 75 | nichevol_labels(tree5, rec_tab, height = 0.6) 76 | nichevol_legend(position = "bottomleft", cex = 0.7) 77 | } 78 | -------------------------------------------------------------------------------- /R/bin_ml_rec.R: -------------------------------------------------------------------------------- 1 | #' Maximum likelihood reconstruction of ancestral character states 2 | #' 3 | #' @param tree_data a list of two elements (phy and data) resulting from using the 4 | #' function \code{\link[geiger]{treedata}}. 5 | #' @param ... other arguments from \code{\link[ape]{ace}}. Arguments \code{x}, 6 | #' \code{phy}, \code{type}, and \code{method} are fixed. 7 | #' 8 | #' @return A table with columns representing bins, rows representing first tip 9 | #' states and then reconstructed nodes. 10 | #' 11 | #' @details 12 | #' Reconstructions are done using the function \code{\link[ape]{ace}} from the 13 | #' \code{ape} package. The argument method is set as "ML" and the type 14 | #' of variable is "discrete". 15 | #' 16 | #' @importFrom ape ace 17 | #' 18 | #' @export 19 | #' 20 | #' @examples 21 | #' # a simple tree 22 | #' data("tree5", package = "nichevol") 23 | #' 24 | #' # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 25 | #' dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 26 | #' "242" = rep("1", length(tree5$tip.label)), 27 | #' "243" = c("1", "1", "0", "0", "0"), 28 | #' "244" = c("1", "1", "0", "0", "0"), 29 | #' "245" = c("1", "?", "0", "0", "0")) 30 | #' rownames(dataTable) <- tree5$tip.label 31 | #' 32 | #' # list with two objects (tree and character table) 33 | #' treeWdata <- geiger::treedata(tree5, dataTable) 34 | #' 35 | #' # Maximum likelihood reconstruction 36 | #' ml_rec <- bin_ml_rec(treeWdata) 37 | 38 | 39 | bin_ml_rec <- function(tree_data, ...) { 40 | if (missing(tree_data)) {stop("Argument 'tree_data' needs to be defined.")} 41 | 42 | # Data from geiger::treedata 43 | tphy <- tree_data$phy 44 | ntips <- length(tphy$tip.label) 45 | nnode <- tphy$Nnode 46 | tdata <- tree_data$data 47 | 48 | # Matrix to fill with reconstructions 49 | reconMatrix <- matrix(nrow = nnode + 3, ncol = ncol(tdata)) 50 | colnames(reconMatrix) <- colnames(tdata) 51 | rownames(reconMatrix) <- c(seq.int(from = 1 + ntips, to = ntips + nnode), 52 | "LogLik", "Rates", "SE") 53 | 54 | # Reconstruct each column 55 | for (i in 1:ncol(tdata)) { 56 | # If all tips are the same, scores all the nodes for that column as the same 57 | if (all(tdata[, i] == tdata[1, i])) { 58 | reconMatrix[1:nnode, i] <- rep(tdata[1, i], nnode) 59 | } else{ 60 | # Reconstruction 61 | temp <- ape::ace(x = tdata[, i], phy = tphy, type = "discrete", 62 | method = "ML", ...) 63 | 64 | # Round each node to 0, 1, or ? 65 | alh <- temp$lik.anc 66 | maxlik <- round(apply(alh, 1, max), digits = 10) 67 | 68 | # Codes reconstructions conservatively if there is equivocation 69 | ancRes <- sapply(1:nnode, function(j) { 70 | matches <- round(alh[j, ], digits = 10) == maxlik[j] 71 | if (sum(matches) > 1) {return("?")} else {return(names(matches)[matches])} 72 | }) 73 | reconMatrix[1:nnode,i] <- ancRes 74 | 75 | # Reconstruction statistics 76 | reconMatrix[nnode + 1, i] <- temp$loglik 77 | reconMatrix[nnode + 2, i] <- temp$rates 78 | reconMatrix[nnode + 3, i] <- temp$se 79 | } 80 | } 81 | whole_rec_table <- rbind(tdata, reconMatrix) 82 | 83 | return(whole_rec_table) 84 | } 85 | -------------------------------------------------------------------------------- /man/niche_labels.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plotting_helpers.R 3 | \name{niche_labels} 4 | \alias{niche_labels} 5 | \title{Labels to represent niches of tips and ancestors} 6 | \usage{ 7 | niche_labels(tree, whole_rec_table, label_type = "tip_node", 8 | tip_offset = 0.015, present = "1", unknown = "?", 9 | present_col = "#e41a1c", unknown_col = "#969696", 10 | absent_col = "#377eb8", width = 1, height = 1) 11 | } 12 | \arguments{ 13 | \item{tree}{an object of class "phylo".} 14 | 15 | \item{whole_rec_table}{matrix of environmental bins for all tips and nodes 16 | derived from functions \code{\link{bin_par_rec}} or \code{\link{bin_ml_rec}}.} 17 | 18 | \item{label_type}{(character) type of label; options are: "tip", "node", and 19 | "tip_node". Default = "tip_node".} 20 | 21 | \item{tip_offset}{(numeric) space between tips and the labels. Default = 0.015.} 22 | 23 | \item{present}{(character) code indicating environmental bins in which the 24 | species is present. Default = "1".} 25 | 26 | \item{unknown}{(character) code indicating environmental bins in which the 27 | species presence is unknown (uncertain). Default = "?".} 28 | 29 | \item{present_col}{color for area of the bar representing environments where 30 | the species is present. Default = "#e41a1c".} 31 | 32 | \item{unknown_col}{color for area of the bar representing environments where 33 | the species presence is unknown (uncertain). Default = "#969696".} 34 | 35 | \item{absent_col}{color for area of the bar representing environments where 36 | no change has been detected. Default = "#377eb8".} 37 | 38 | \item{width}{value defining the width of niche bars; default = 1.} 39 | 40 | \item{height}{value defining the height of niche bars; default = 1.} 41 | } 42 | \description{ 43 | niche_labels helps in adding bar-type labels that represent 44 | species ecological niches in one environmental variable. 45 | } 46 | \details{ 47 | For the moment, only plots of type "phylogram" with "rightwards" or "leftwards" 48 | directions, created with the function \code{\link[ape]{plot.phylo}} from the 49 | package \code{ape} are supported. 50 | 51 | Ecological niches are represented in one environmental dimension with vertical 52 | bars that indicate if the species is present, absent, or if its presence is 53 | uncertain in the range of environmental conditions. Lower values of 54 | environmental variables are represented in the lower part of the bar, and the 55 | opposite part of the bar represents higher values. 56 | } 57 | \examples{ 58 | # a simple tree 59 | data("tree5", package = "nichevol") 60 | 61 | # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 62 | dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 63 | "242" = rep("1", length(tree5$tip.label)), 64 | "243" = c("1", "1", "0", "0", "0"), 65 | "244" = c("1", "1", "0", "0", "0"), 66 | "245" = c("1", "?", "0", "0", "0")) 67 | rownames(dataTable) <- tree5$tip.label 68 | 69 | # list with two objects (tree and character table) 70 | treeWdata <- geiger::treedata(tree5, dataTable) 71 | 72 | # Maximum parsimony reconstruction 73 | rec_tab <- smooth_rec(bin_par_rec(treeWdata)) 74 | 75 | # plotting and adding labels 76 | ape::plot.phylo(tree5, label.offset = 0.04) 77 | niche_labels(tree5, rec_tab, height = 0.6) 78 | } 79 | -------------------------------------------------------------------------------- /man/niche_bars.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/niche_bars.R 3 | \name{niche_bars} 4 | \alias{niche_bars} 5 | \title{PNG bar figures to represent ecological niches of distinct taxa} 6 | \usage{ 7 | niche_bars(tree, whole_rec_table, present = "1", unknown = "?", 8 | present_col = "#e41a1c", unknown_col = "#969696", 9 | absent_col = "#377eb8", width = 50, height = 5, res = 300, 10 | output_directory, overwrite = FALSE) 11 | } 12 | \arguments{ 13 | \item{tree}{an object of class "phylo".} 14 | 15 | \item{whole_rec_table}{matrix of environmental bins for all tips and nodes 16 | derived from functions \code{\link{bin_par_rec}} or \code{\link{bin_ml_rec}}.} 17 | 18 | \item{present}{(character) code indicating environmental bins in which the 19 | species is present. Default = "1".} 20 | 21 | \item{unknown}{(character) code indicating environmental bins in which the 22 | species presence is unknown (uncertain). Default = "?".} 23 | 24 | \item{present_col}{color for area of the bar representing environments where 25 | the species is present. Default = "#e41a1c".} 26 | 27 | \item{unknown_col}{color for area of the bar representing environments where 28 | the species presence is unknown (uncertain). Default = "#969696".} 29 | 30 | \item{absent_col}{color for area of the bar representing environments where 31 | no change has been detected. Default = "#377eb8".} 32 | 33 | \item{width}{(numeric) width of the device in mm to be passed to the 34 | \code{\link[grDevices]{png}} function. Default = 50.} 35 | 36 | \item{height}{(numeric) height of the device in mm to be passed to the 37 | \code{\link[grDevices]{png}} function. Default = 5.} 38 | 39 | \item{res}{(numeric) nominal resolution in ppi to be passed to the 40 | \code{\link[grDevices]{png}} function. Default = 300.} 41 | 42 | \item{output_directory}{(character) name of the folder in which results will 43 | be written. The directory will be created as part of the process.} 44 | 45 | \item{overwrite}{(logical) whether or not to overwrite existing results in 46 | \code{output_directory}. Default = FALSE.} 47 | } 48 | \value{ 49 | A folder named as in \code{output_directory} containing all bar figures 50 | produced, as well as a legend to describe what is plotted. 51 | } 52 | \description{ 53 | niche_bars produces bar plots that represent species 54 | ecological niches in one environmental variable. Bars are exported as png 55 | figures to an output directory for posterior use. 56 | } 57 | \details{ 58 | Ecological niches are represented in one environmental dimension with vertical 59 | bars that indicate if the species is present, absent, or if its presence is 60 | uncertain in the range of environmental conditions. Lower values of 61 | environmental variables are represented in the left part of the bar, and the 62 | opposite part of the bar represents higher values. 63 | } 64 | \examples{ 65 | # a simple tree 66 | data("tree5", package = "nichevol") 67 | 68 | # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 69 | dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 70 | "242" = rep("1", length(tree5$tip.label)), 71 | "243" = c("1", "1", "0", "0", "0"), 72 | "244" = c("1", "1", "0", "0", "0"), 73 | "245" = c("1", "?", "0", "0", "0")) 74 | rownames(dataTable) <- tree5$tip.label 75 | 76 | # list with two objects (tree and character table) 77 | treeWdata <- geiger::treedata(tree5, dataTable) 78 | 79 | # Maximum parsimony reconstruction 80 | rec_tab <- smooth_rec(bin_par_rec(treeWdata)) 81 | 82 | # the running (before running, define a working directory) 83 | niche_bars(tree5, rec_tab, output_directory = file.path(tempdir(), "nichebars")) 84 | } 85 | -------------------------------------------------------------------------------- /R/bin_par_rec.R: -------------------------------------------------------------------------------- 1 | #' Maximum parsimony reconstruction of ancestral character states 2 | #' 3 | #' @param tree_data a list of two elements (phy and data) resulting from using 4 | #' the function \code{\link[geiger]{treedata}}. 5 | #' @param ... other arguments from \code{\link[castor]{asr_max_parsimony}}. 6 | #' Arguments \code{tree} and \code{tip_states} are fixed. 7 | #' 8 | #' @return A table with columns representing bins, rows representing first tip 9 | #' states and then reconstructed nodes. 10 | #' 11 | #' @details 12 | #' Reconstructions are done using the \code{\link[castor]{asr_max_parsimony}} 13 | #' function from the \code{castor} package. 14 | #' 15 | #' @importFrom ape reorder.phylo 16 | #' @importFrom castor asr_max_parsimony 17 | #' 18 | #' @export 19 | #' 20 | #' @examples 21 | #' # a simple tree 22 | #' data("tree5", package = "nichevol") 23 | #' 24 | #' # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 25 | #' dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 26 | #' "242" = rep("1", length(tree5$tip.label)), 27 | #' "243" = c("1", "1", "0", "0", "0"), 28 | #' "244" = c("1", "1", "0", "0", "0"), 29 | #' "245" = c("1", "?", "0", "0", "0")) 30 | #' rownames(dataTable) <- tree5$tip.label 31 | #' 32 | #' # list with two objects (tree and character table) 33 | #' treeWdata <- geiger::treedata(tree5, dataTable) 34 | #' 35 | #' # Maximum parsimony reconstruction 36 | #' par_rec <- bin_par_rec(treeWdata) 37 | 38 | 39 | bin_par_rec <- function(tree_data, ...) { 40 | if (missing(tree_data)) {stop("Argument 'tree_data' needs to be defined.")} 41 | 42 | # Data for analyses 43 | tphy <- ape::reorder.phylo(tree_data$phy, order = "cladewise") 44 | ntips <- length(tphy$tip.label) 45 | nnode <- tphy$Nnode 46 | tdata <- tree_data$data 47 | tdata <- tdata[match(tphy$tip.label,row.names(tdata)),] 48 | tdata[tdata == 1] <- "3" 49 | tdata[tdata == "?"] <- "2" 50 | tdata[tdata == 0] <- "1" 51 | tdata <- apply(tdata,c(1,2),as.numeric) 52 | 53 | # Matrix to fill with reconstructions 54 | reconMatrix <- matrix(nrow = nnode, ncol = ncol(tdata)) 55 | colnames(reconMatrix) <- colnames(tdata) 56 | rownames(reconMatrix) <- c(seq.int(from = 1 + ntips, to = ntips + nnode)) 57 | 58 | # Reconstruct each column 59 | for (i in 1:ncol(tdata)) { 60 | # If all tips are the same, scores all the nodes for that column as the same 61 | if (all(tdata[, i] == tdata[1, i])) { 62 | reconMatrix[1:nnode, i] <- rep(tdata[1, i], nnode) 63 | } else{ 64 | # Reconstruction 65 | cdat <- tdata[, i] 66 | temp <- castor::asr_max_parsimony(tree = tphy, tip_states = cdat, ...) 67 | if (length(unique(tdata[,i])) < ncol(temp$ancestral_likelihoods)){ 68 | colnames(temp$ancestral_likelihoods) <- as.character(c(1,2,3)) 69 | } 70 | else {colnames(temp$ancestral_likelihoods) <- as.character(unique(tdata[, i]))} 71 | 72 | # Round each node to 0, 1, or ? based on likelihood 73 | alh <- temp$ancestral_likelihoods 74 | maxlik <- round(apply(alh, 1, max), digits = 10) 75 | 76 | # Codes reconstructions conservatively if there is equivocation 77 | ancRes <- sapply(1:nnode, function(j) { 78 | matches <- round(alh[j, ], digits = 10) == maxlik[j] 79 | if (sum(matches) > 1) {return(2)} else {return(names(matches)[matches])} 80 | }) 81 | reconMatrix[1:nnode, i] <- ancRes 82 | } 83 | } 84 | 85 | tdata <- tdata[match(tree_data$phy$tip.label,row.names(tdata)),] #Change order back to original 86 | whole_rec_table <- rbind(tdata, reconMatrix) 87 | 88 | #Converting it back to original coding 89 | whole_rec_table[whole_rec_table == "1"] <- "0" 90 | whole_rec_table[whole_rec_table == "3"] <- "1" 91 | whole_rec_table[whole_rec_table == "2"] <- "?" 92 | 93 | return(whole_rec_table) 94 | } 95 | -------------------------------------------------------------------------------- /man/stats_eval.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stats_eval.R 3 | \name{stats_eval} 4 | \alias{stats_eval} 5 | \title{Statistics of environmental conditions in M and for occurrences (one variable)} 6 | \usage{ 7 | stats_eval(stats = c("median", "range"), Ms, occurrences, species, 8 | longitude, latitude, variable, percentage_out = 0, verbose = TRUE) 9 | } 10 | \arguments{ 11 | \item{stats}{(character) name or vector of names of functions to be applied 12 | to get basic statistics of environmental values.} 13 | 14 | \item{Ms}{a list of SpatVector objects representing the accessible area 15 | (M) for each species to be analyzed. The order of species represented by each 16 | object here must coincide with the one in \code{occurrences}. See details.} 17 | 18 | \item{occurrences}{a list of data.frames of occurrence records for all species. 19 | The order of species represented by each data.frame must coincide with the one 20 | in \code{Ms}. See details.} 21 | 22 | \item{species}{(character) name of the column in occurrence data.frames that 23 | contains the name of the species.} 24 | 25 | \item{longitude}{(character) name of the column in occurrence files containing 26 | values of longitude.} 27 | 28 | \item{latitude}{(character) name of the column in occurrence files containing 29 | values of latitude.} 30 | 31 | \item{variable}{a single SpatRaster layer of an environmental variable of 32 | interest. See details.} 33 | 34 | \item{percentage_out}{(numeric) percentage of extreme environmental data in M 35 | to be excluded in bin creation for further analyses. See details. Default = 0.} 36 | 37 | \item{verbose}{(logical) whether messages should be printed. Default = TRUE.} 38 | } 39 | \value{ 40 | A list containing tables with statistics of the values in \code{variable}, 41 | for the species M and occurrences. 42 | } 43 | \description{ 44 | stats_eval helps in creating tables of descriptive statistics 45 | of environmental conditions in accessible areas (M) and occurrence 46 | records for one environmental variable at a time. 47 | } 48 | \details{ 49 | Coordinates in \code{occurrences}, SpatVector objects in \code{Ms}, and 50 | SpatRaster in \code{variable} must coincide in the geographic projection in 51 | which they are represented. WGS84 with no planar projection is recommended. 52 | 53 | Accessible area (M) is understood as the geographic area that has been 54 | accessible for a species for relevant periods of time. Defining M is usually 55 | a hard task, but also a very important one, because it allows identifying 56 | uncertainties about the ability of a species to maintain populations in 57 | certain environmental conditions. For further details on this topic, see 58 | Barve et al. (2011) \url{doi:10.1016/j.ecolmodel.2011.02.011} 59 | and Machado-Stredel et al. (2021) \url{doi:10.21425/F5FBG48814}. 60 | 61 | The percentage to be defined in \code{percentage_out} excludes a percentage 62 | of extreme environmental values to prevent from considering extremely rare 63 | environmental values in the accessible area for the species (M). Being too 64 | rare, these values may have never been explored by the species; therefore, 65 | including them in the process of preparation of the table of characters 66 | (bin table) is risky. 67 | } 68 | \examples{ 69 | # example data 70 | ## list of species records 71 | data("occ_list", package = "nichevol") 72 | 73 | ## list of species accessible areas 74 | m_files <- list.files(system.file("extdata", package = "nichevol"), 75 | pattern = "m\\\\d.gpkg", full.names = TRUE) 76 | 77 | m_list <- lapply(m_files, terra::vect) 78 | 79 | ## raster variable 80 | temp <- terra::rast(system.file("extdata", "temp.tif", package = "nichevol")) 81 | 82 | # running stats 83 | stat <- stats_eval(stats = c("mean", "sd", "median", "range", "quantile"), 84 | Ms = m_list, occurrences = occ_list, species = "species", 85 | longitude = "x", latitude = "y", variable = temp, 86 | percentage_out = 0) 87 | } 88 | -------------------------------------------------------------------------------- /R/data_doc.R: -------------------------------------------------------------------------------- 1 | #' Example of character table for six species 2 | #' 3 | #' A character table representing species ecological niches derived from 4 | #' previous preparation processes. Each row represents a species and each column 5 | #' a binary character in which one or more values of the environmental variable 6 | #' are categorized as used "1", non used "0", or uncertain "?". 7 | #' 8 | #' @format A character matrix with 6 rows and 28 columns. 9 | #' 10 | #' @examples 11 | #' data("character_table", package = "nichevol") 12 | #' 13 | #' head(character_table) 14 | "character_table" 15 | 16 | 17 | #' Example of table with results from parsimony reconstructions 18 | #' 19 | #' A character table representing species ecological niches derived from 20 | #' previous preparation processes and reconstructed niches for ancestors. 21 | #' Each row represents a species or a node and each column a binary 22 | #' character in which one or more values of the environmental variable 23 | #' are categorized as used "1", non used "0", or uncertain "?". 24 | #' 25 | #' @format A character matrix with 11 rows and 20 columns. 26 | #' 27 | #' @examples 28 | #' data("par_rec_table", package = "nichevol") 29 | #' 30 | #' head(par_rec_table) 31 | "par_rec_table" 32 | 33 | 34 | 35 | #' Example of a phylogenetic tree for six species 36 | #' 37 | #' A phylogenetic tree with 6 species and their relationships. 38 | #' 39 | #' @format An object of class phylo for 6 species. 40 | #' 41 | #' @examples 42 | #' data("tree", package = "nichevol") 43 | #' 44 | #' str(tree) 45 | "tree" 46 | 47 | 48 | #' Example of a phylogenetic tree for five species 49 | #' 50 | #' A phylogenetic tree with 5 species and their relationships. 51 | #' 52 | #' @format An object of class phylo for 5 species. 53 | #' 54 | #' @examples 55 | #' data("tree5", package = "nichevol") 56 | #' 57 | #' str(tree5) 58 | "tree5" 59 | 60 | 61 | #' Example of a list containing a tree and a table of characters for six species 62 | #' 63 | #' A list of 2 elements (phy and data) resulting from using the function 64 | #' \code{\link[geiger]{treedata}}. 65 | #' 66 | #' @format A list of 2 elements: 67 | #' \describe{ 68 | #' \item{phy}{object of class phylo for 6 species} 69 | #' \item{data}{matrix of 6 rows and 28 columns} 70 | #' } 71 | #' 72 | #' @examples 73 | #' data("tree_data", package = "nichevol") 74 | #' 75 | #' str(tree_data) 76 | "tree_data" 77 | 78 | 79 | #' Example of occurrence records for six species 80 | #' 81 | #' A list of 6 data.frames containing name and geographic coordinates for 82 | #' 6 species. 83 | #' 84 | #' @format A list of 6 data.frames: 85 | #' \describe{ 86 | #' \item{species}{species name, a code in this example} 87 | #' \item{x}{longitude, longitude value} 88 | #' \item{y}{latitude, latitude value} 89 | #' } 90 | #' 91 | #' @examples 92 | #' data("occ_list", package = "nichevol") 93 | #' 94 | #' str(occ_list) 95 | "occ_list" 96 | 97 | 98 | #' Example of accessible areas for a species 99 | #' 100 | #' A SpatVector object representing the accessible area for a species. 101 | #' 102 | #' @format A SpatVector object. 103 | #' 104 | #' @name m 105 | #' @aliases m1 m2 m3 m4 m5 m6 106 | #' 107 | #' @return No return value, used with function \code{\link[terra]{vect}} to 108 | #' bring an example of an accessible area for a species. 109 | #' 110 | #' @examples 111 | #' m1 <- terra::vect(system.file("extdata", "m1.gpkg", package = "nichevol")) 112 | #' 113 | #' terra::plot(m1) 114 | NULL 115 | 116 | 117 | #' Example of an environmental variable used in analysis 118 | #' 119 | #' A SpatRaster object representing the variable temperature. 120 | #' 121 | #' @format A SpatRaster object. 122 | #' 123 | #' @name temp 124 | #' 125 | #' @return No return value, used with function \code{\link[terra]{rast}} to 126 | #' bring an example of an environmental variable used in analysis. 127 | #' 128 | #' @examples 129 | #' temp <- terra::rast(system.file("extdata", "temp.tif", package = "nichevol")) 130 | #' 131 | #' terra::plot(temp) 132 | NULL 133 | -------------------------------------------------------------------------------- /man/map_nichevol.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/map_nichevol.R 3 | \name{map_nichevol} 4 | \alias{map_nichevol} 5 | \title{Maps of niche reconstructions and changes detected} 6 | \usage{ 7 | map_nichevol(whole_rec_table, variable, return = "niche", from, to = NULL, 8 | id_unknown = TRUE, verbose = TRUE) 9 | } 10 | \arguments{ 11 | \item{whole_rec_table}{matrix of environmental bins for all tips and nodes 12 | derived from functions \code{\link{bin_par_rec}} or \code{\link{bin_ml_rec}}.} 13 | 14 | \item{variable}{a SpatRaster layer corresponding to the variable for which 15 | the reconstruction was performed (represented in \code{whole_rec_table}).} 16 | 17 | \item{return}{(character) type of result to return. Options are: "niche", 18 | "evolution", or "nichevol" (a combination of both). Default = "niche". If 19 | "niche", values correspond to that defined in \code{from}. See Value.} 20 | 21 | \item{from}{(character) if \code{return} = "niche" tip or node for which layer 22 | will be prepared, otherwise, initial node from which niche comparison will be 23 | performed. See example.} 24 | 25 | \item{to}{(character) valid if \code{return} = "evolution" or "nichevol". 26 | Tip or node to compare against \code{from} to detected changes. 27 | Default = NULL. See example.} 28 | 29 | \item{id_unknown}{(logical) whether to identify areas of unknown or uncertain 30 | change. Default = TRUE. See details.} 31 | 32 | \item{verbose}{(logical) whether messages should be printed. Default = TRUE.} 33 | } 34 | \value{ 35 | A SpatRaster object classified according to values of niche in 36 | \code{whole_rec_table}, and/or according to niche changes detected in 37 | comparisons between an ancestor and a tip, or another more recent ancestor. 38 | 39 | Options of values resulting from classifications are as follow: 40 | 41 | If \code{return} = "niche":\tabular{ll}{ 42 | ID \tab category \cr 43 | 0 \tab Absent \cr 44 | 10 \tab Unknown \cr 45 | 100 \tab Present \cr 46 | } 47 | 48 | 49 | If \code{return} = "evolution":\tabular{ll}{ 50 | ID \tab category \cr 51 | 0 \tab Stable \cr 52 | 1 \tab Expansion low \cr 53 | 3 \tab Expansion high \cr 54 | 2 \tab Retraction high \cr 55 | 4 \tab Retraction low \cr 56 | 10 \tab Unknown \cr 57 | } 58 | 59 | 60 | If \code{return} = "nichevol":\tabular{ll}{ 61 | ID \tab category \cr 62 | 0 \tab Stable \cr 63 | 1 \tab Expansion low \cr 64 | 3 \tab Expansion high \cr 65 | 10 \tab Unknown \cr 66 | 100 \tab Present \cr 67 | 102 \tab Retraction high \cr 68 | 104 \tab Retraction low \cr 69 | } 70 | } 71 | \description{ 72 | map_nichevol produces a SpatRaster layer representing 73 | geographic areas corresponding to environmental bins of niche or events of 74 | niche evolution detected in reconstructions. 75 | } 76 | \details{ 77 | Mapping is done following Cobos et al. (2021) \url{doi:10.1111/jav.02868}. 78 | This allows to represent geographic areas with environments where 79 | niche expanded, retracted, or stayed stable (evolution). Niche is 80 | represented as presence, absence, or unknown. 81 | 82 | Defining \code{id_unknown} = TRUE allows to map areas where niche or niche 83 | change are uncertain. \code{id_unknown} = FALSE returns NA in areas with these 84 | characteristics, hence they will not be visible when plotting the resulting 85 | map. 86 | } 87 | \examples{ 88 | # a tree 89 | data("tree", package = "nichevol") 90 | 91 | # raster variable 92 | temp <- terra::rast(system.file("extdata", "temp.tif", package = "nichevol")) 93 | 94 | # results from reconstruction 95 | data("par_rec_table", package = "nichevol") 96 | 97 | # rename tree tips 98 | tree$tip.label <- rownames(par_rec_table)[1:6] 99 | 100 | # check in plot 101 | plot.phylo(tree, label.offset = 0.02) 102 | nodelabels() 103 | nichevol_labels(tree, par_rec_table) 104 | 105 | # mapping nichevol 106 | nevol_map <- map_nichevol(whole_rec_table = par_rec_table, variable = temp, 107 | return = "nichevol", from = "9", to = "RD 6933") 108 | 109 | terra::plot(nevol_map) 110 | } 111 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Resubmission 0.1.20 2 | This is a resubmission. In this version I have made the following changes: 3 | 4 | * Changed package CITATION file to replace old-style personList() or as.personList(). 5 | * Changed package CITATION file to replace old-style citEntry() with bibentry(). 6 | * Replaced URLs by dois in documentation for functions: bin_table, bin_tables0, hist_evalues, histograms_env, stats_eval, and stats_evalues. 7 | 8 | ## Test environments 9 | * Ubuntu 22.04 LTS, R 4.2.2 (local) 10 | * MacOS 12.6.3, R release (GitHub Actions) 11 | * Windows 10.0.20348, R release (GitHub Actions) 12 | * Ubuntu 22.04 LTS, R release (GitHub Actions) 13 | * Ubuntu 22.04 LTS, R devel (GitHub Actions) 14 | * Ubuntu 22.04 LTS, R oldrel-1 (GitHub Actions) 15 | 16 | 17 | ## R CMD check results 18 | There were no ERRORs: 19 | 20 | There were no WARNINGs: 21 | 22 | There were no NOTEs: 23 | 24 | 25 | ## Downstream dependencies 26 | There are currently no downstream dependencies for this package. 27 | 28 |
29 |
30 | 31 | ## V 0.1.20 first submission 32 | In this version I have made the following changes: 33 | 34 | * Replaced functions from the packages sp, raster, and rgdal, with functions from terra. 35 | * Deprecated the argument bin_size and replace it with n_bins to make data processing more efficient in functions: bin_table, bin_tables0, and bin_tables. 36 | * Added the argument verbose to make message suppression easier in functions that needed it: bin_table, bin_tables0, bin_tables, histograms_env, stats_eval, stats_evalues, and map_nichevol (new). 37 | * Added functions to help mapping niche evolution detected based on reconstructions, map_nichevol and helpers. 38 | * Added function to help read prepared data written in a directory: read_bin_table and read_bin_tables. 39 | * Added function to help set uncertainty manually in examples with poorly known species: set_uncertainty. 40 | 41 | ## Test environments 42 | * Ubuntu 22.04 LTS, R 4.2.2 (local) 43 | * MacOS 12.6.3, R release (GitHub Actions) 44 | * Windows 10.0.20348, R release (GitHub Actions) 45 | * Ubuntu 22.04 LTS, R release (GitHub Actions) 46 | * Ubuntu 22.04 LTS, R devel (GitHub Actions) 47 | * Ubuntu 22.04 LTS, R oldrel-1 (GitHub Actions) 48 | 49 | 50 | ## R CMD check results 51 | There were no ERRORs: 52 | 53 | There were no WARNINGs: 54 | 55 | There were no NOTEs: 56 | 57 | 58 | ## Downstream dependencies 59 | There are currently no downstream dependencies for this package. 60 | 61 |
62 |
63 | 64 | 65 | ## Resubmission 0.1.19 66 | This is a resubmission. In this version I have made the following changes: 67 | 68 | * Updated the Date field in DESCRIPTION. 69 | 70 | **Comments** 71 | 72 | * NOTES may be produced because some names of researchers cited in the 73 | Description file are considered misspelled words; however, the names are correct. 74 | 75 | 76 | ## Test environments 77 | * local windows 10, R 3.6.2 78 | * local macOS 10.14.6 Mojave, R 3.6.2 79 | * ubuntu 16.04.6 LTS (on travis), R 3.6.2 80 | * macOS 10.11 El Capitan (on rhub), R 3.6.2 81 | * windows server 2008 R2 SP1 32/64 bit (on rhub), R-devel 82 | 83 | ## R CMD check results 84 | There were no ERRORs: 85 | 86 | There were no WARNINGs: 87 | 88 | There were no NOTEs: 89 | 90 | 91 | ## Downstream dependencies 92 | There are currently no downstream dependencies for this package. 93 | 94 |
95 |
96 | 97 | 98 | ## Resubmission 99 | This is a resubmission. In this version I have made the following changes: 100 | 101 | * Shortened the package title to less than 65 characters. 102 | * Changed some examples so no package installations are performed; example-data 103 | and documentation were added instead. 104 | * Prevented writing information in the working directory for a few non-tested 105 | examples that were still doing it. Now info is written in temporary directories. 106 | * Package ape was added as a dependency to avoid problems when trying to obtain 107 | characteristics of phylogenetic plots for adding niche labels. 108 | 109 | **Comments** 110 | 111 | * NOTES may be produced because some names of researchers cited in the 112 | Description file are considered misspelled words; however, the names are correct. 113 | 114 | 115 | ## Test environments 116 | * local windows 10, R 3.6.2 117 | * local macOS 10.14.6 Mojave, R 3.6.2 118 | * ubuntu 16.04.6 LTS (on travis), R 3.6.2 119 | * macOS 10.11 El Capitan (on rhub), R 3.6.2 120 | * windows server 2008 R2 SP1 32/64 bit (on rhub), R-devel 121 | 122 | ## R CMD check results 123 | There were no ERRORs: 124 | 125 | There were no WARNINGs: 126 | 127 | There were no NOTEs: 128 | 129 | 130 | ## Downstream dependencies 131 | There are currently no downstream dependencies for this package. 132 | -------------------------------------------------------------------------------- /R/smooth_rec.R: -------------------------------------------------------------------------------- 1 | #' Smooth character table values resulted from ancestral character state reconstructions 2 | #' 3 | #' @param whole_rec_table matrix containing all reconstructed characters for all 4 | #' tips and nodes. It results from using the functions \code{\link{bin_par_rec}} 5 | #' or \code{\link{bin_ml_rec}}. 6 | #' 7 | #' @return 8 | #' The matrix of reconstructed characters with smoothed values. 9 | #' 10 | #' @importFrom stats smooth 11 | #' @importFrom stringr str_extract str_replace 12 | #' @export 13 | #' 14 | #' @examples 15 | #' # a simple tree 16 | #' data("tree5", package = "nichevol") 17 | #' 18 | #' # simple matrix of data 19 | #' dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 20 | #' "242" = rep("1", length(tree5$tip.label)), 21 | #' "243" = c("1", "1", "0", "0", "0"), 22 | #' "244" = c("1", "1", "0", "0", "0"), 23 | #' "245" = c("1", "?", "0", "0", "0")) 24 | #' rownames(dataTable) <- tree5$tip.label 25 | #' treeWdata <- geiger::treedata(tree5, dataTable) 26 | #' 27 | #' # ancestral reconstruction 28 | #' parsimonyReconstruction <- bin_par_rec(treeWdata) 29 | #' 30 | #' # smoothing reconstructions 31 | #' smooth_rec(parsimonyReconstruction) 32 | 33 | smooth_rec <- function(whole_rec_table) { 34 | if (missing(whole_rec_table)) {stop("Argument 'whole_rec_table' needs to be defined.")} 35 | 36 | statRows <- NULL 37 | nrows <- nrow(whole_rec_table) 38 | 39 | if ("LogLik" %in% rownames(whole_rec_table)) { 40 | statRows <- whole_rec_table[(nrows - 2):nrows, ] 41 | whole_rec_table <- whole_rec_table[1:(nrows - 3), ] 42 | nrows <- nrows - 3 43 | } 44 | 45 | for (k in 1:nrows){ 46 | test <- paste(whole_rec_table[k, ], collapse = "") 47 | test <- gsub("?", replacement = "u", x = test, fixed = TRUE) 48 | 49 | # 0s between unknowns 50 | if (grepl(x = test, pattern = "u0+u")) { 51 | while (grepl(x = test, pattern = "u0+u")) { 52 | pull <- stringr::str_extract(string = test, pattern = "u0+u")[1] 53 | pull <- gsub(unlist(strsplit(pull, split = "")), pattern = "0", replacement = "u") 54 | test <- stringr::str_replace(test, "u0+u", paste(pull, collapse= "")) 55 | } 56 | } 57 | 58 | # Unknowns between 1s 59 | if (grepl(x = test, pattern = "1u+1")) {#fills in unknowns sandwiched between 1s 60 | while (grepl(x = test, pattern = "1u+1")) { 61 | pull <- stringr::str_extract(string = test, pattern = "1u+1")[1] 62 | pull <- gsub(unlist(strsplit(pull,split = "")), pattern = "u", replacement = 1) 63 | test <- stringr::str_replace(test, "1u+1", paste(pull, collapse= "")) 64 | } 65 | } 66 | 67 | # Algorithmically smooth if there are 0s and 1s alternating, in order to yield unimodal response 68 | midString <- stringr::str_extract(test, "1[01]+") 69 | if(!is.na(midString)){ 70 | if(nchar(midString) > 3){ 71 | if (grepl(pattern = "10+1", x = test)){ 72 | midString <- as.numeric(unlist(strsplit(midString, split = ""))) 73 | midString <- paste(smooth(midString), collapse = "") 74 | } 75 | test <- stringr::str_replace(test, "1[01]+", midString) 76 | } 77 | } 78 | 79 | # Last check to clear any 0 or unknowns flanked by 1s 80 | if (grepl(x = test, pattern = "1[0u]+1")) {#fills in unknowns sandwiched between 1s 81 | while (grepl(x = test, pattern = "1[0u]+1")) { 82 | pull <- stringr::str_extract(string = test, pattern = "1[0u]+1")[1] 83 | pull <- gsub(unlist(strsplit(pull,split = "")), pattern = "[0u]", replacement = 1) 84 | test <- stringr::str_replace(test, "1[0u]+1", paste(pull, collapse= "")) 85 | } 86 | } 87 | 88 | # Check for 0s flanked by a 1 and an unknown 89 | if (grepl(x = test, pattern = "u0+1")) { 90 | while (grepl(x = test, pattern = "u0+1")) { 91 | pull <- stringr::str_extract(string = test, pattern = "u0+1")[1] 92 | pull <- gsub(unlist(strsplit(pull,split = "")), pattern = "u", replacement = "0") 93 | test <- stringr::str_replace(test, "u0+1", paste(pull, collapse= "")) 94 | } 95 | } 96 | 97 | if (grepl(x = test, pattern = "10+u")) { 98 | while (grepl(x = test, pattern = "10+u")) { 99 | pull <- stringr::str_extract(string = test, pattern = "10+u")[1] 100 | pull <- gsub(unlist(strsplit(pull,split = "")), pattern = "u", replacement = "0") 101 | test <- stringr::str_replace(test, "10+u", paste(pull, collapse= "")) 102 | } 103 | } 104 | 105 | test <- gsub("u", replacement = "?", x = test, fixed = TRUE) 106 | whole_rec_table[k, ] <- unlist(strsplit(test, split = "")) 107 | } 108 | if (!is.null(statRows)){ 109 | whole_rec_table <- rbind(whole_rec_table, statRows) 110 | } 111 | 112 | return(whole_rec_table) 113 | } 114 | -------------------------------------------------------------------------------- /man/bin_tables.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bin_tables.R 3 | \name{bin_tables} 4 | \alias{bin_tables} 5 | \title{Bin tables of environmental conditions in M and for occurrences from objects} 6 | \usage{ 7 | bin_tables(ranges, percentage_out = 5, n_bins = 20, bin_size, save = FALSE, 8 | output_directory, overwrite = FALSE, verbose = TRUE) 9 | } 10 | \arguments{ 11 | \item{ranges}{list of ranges of environmental values in M and in species 12 | occurrences derived from using the function \code{\link{histograms_env}}.} 13 | 14 | \item{percentage_out}{(numeric) percentage of extreme environmental data in M 15 | to be excluded in bin creation for further analyses. See details. Default = 5.} 16 | 17 | \item{n_bins}{(numeric) number of bins to be created from the range of 18 | environmental values considered when creating each character in bin tables. 19 | Default = 20. See details.} 20 | 21 | \item{bin_size}{(numeric) argument deprecated, use n_bins instead.} 22 | 23 | \item{save}{(logical) whether or not to save the results in working directory. 24 | Default = FALSE.} 25 | 26 | \item{output_directory}{(character) name of the folder in which results will be 27 | written.} 28 | 29 | \item{overwrite}{(logical) whether or not to overwrite existing results 30 | in \code{output_directory}. Default = FALSE.} 31 | 32 | \item{verbose}{(logical) whether messages should be printed. Default = TRUE.} 33 | } 34 | \value{ 35 | A list named as in \code{ranges} containing the table(s) of characters. 36 | A folder named as in \code{output_directory} containing all resulting csv 37 | files with the tables of characters will be created if \code{save} is set as 38 | TRUE. 39 | 40 | Potential values for characters are: 41 | \itemize{ 42 | \item "1" = the species is present in those environmental conditions. 43 | \item "0" = the species is not present in those environmental conditions. This is, 44 | those environmental conditions inside the accessible area (M) are more extreme 45 | than the ones used for the species. 46 | \item "?" = there is no certainty about the species presence in those environmental 47 | conditions. This happens if environmental combinations are more extreme than 48 | the ones found in the accessible area (M), when environmental conditions in 49 | species records are as extreme as the most extreme ones in M. 50 | } 51 | } 52 | \description{ 53 | bin_tables helps in creating bin tables of environmental 54 | conditions in accessible areas (M) and species occurrence records 55 | (i.e., table of characters). This is done using results from previous 56 | analyses, and can be applied to various species and multiple variables. 57 | } 58 | \details{ 59 | The percentage to be defined in \code{percentage_out} must correspond with 60 | one of the confidence limits defined in \code{\link{histograms_env}} 61 | (argument \code{CL_lines}). For instance, if \code{CL_lines} = 95, then 62 | \code{percentage_out} can only be either 5 (keeping data inside the 95 CL) or 63 | 0 (to avoid exclusion of extreme values in M). 64 | 65 | Excluding a certain percentage of extreme environmental values prevents the 66 | algorithm from considering extremely rare environmental values in the 67 | accessible area for the species (M). Being too rare, these values may have 68 | never been explored by the species; therefore, including them in the process 69 | of preparation of the table of characters (bin table) is risky. 70 | 71 | The argument \code{n_bins} helps to define how many characters (bins) will be 72 | considered for the range of values in each variable. This is, a value of 20 73 | determines that a range of temperature (5-25) will be split approximately 74 | every 1 degree. The argument \code{bin_size} has been deprecated. 75 | } 76 | \examples{ 77 | # simple list of ranges 78 | ranges <- list(temp = data.frame(Species = c("sp1", "sp2", "sp3"), 79 | Species_lower = c(120, 56, 59.75), 80 | Species_upper = c(265, 333, 333), 81 | M_lower = c(93, 39, 56), 82 | M_upper = c(302, 333, 333), 83 | M_95_lowerCL = c(158, 91, 143), 84 | M_95_upperCL = c(292, 290, 326)), 85 | prec = data.frame(Species = c("sp1", "sp2", "sp3"), 86 | Species_lower = c(597, 3, 3), 87 | Species_upper = c(3492, 2673, 6171), 88 | M_lower = c(228, 3, 3), 89 | M_upper = c(6369, 7290, 6606), 90 | M_95_lowerCL = c(228, 3, 3), 91 | M_95_upperCL = c(3114, 2376, 2568))) 92 | 93 | # bin preparation 94 | bins <- bin_tables(ranges, percentage_out = 5, n_bins = 20) 95 | 96 | # see arguments save and output_directory to write results in local directory 97 | } 98 | -------------------------------------------------------------------------------- /man/nichevol_labels.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plotting_helpers.R 3 | \name{nichevol_labels} 4 | \alias{nichevol_labels} 5 | \title{Labels to represent changes of niche characteristics between ancestors and descendants} 6 | \usage{ 7 | nichevol_labels(tree, whole_rec_table, ancestor_line = FALSE, 8 | present = "1", absent = "0", unknown = "?", 9 | present_col = "#252525", unknown_col = "#d9d9d9", 10 | no_change_col = "#b2df8a", retraction_col = "#984ea3", 11 | expansion_col = "#4daf4a", width = 1, height = 1) 12 | } 13 | \arguments{ 14 | \item{tree}{an object of class "phylo".} 15 | 16 | \item{whole_rec_table}{matrix of reconstructed bins for nodes and species 17 | derived from a process of maximum parsimony or maximum likelihood reconstruction. 18 | See functions \code{\link{bin_par_rec}} or \code{\link{bin_ml_rec}}.} 19 | 20 | \item{ancestor_line}{controls whether ancestor line is plotted. 21 | Default = FALSE.} 22 | 23 | \item{present}{(character) code indicating environmental bins in which the 24 | species is present. Default = "1".} 25 | 26 | \item{absent}{(character) code indicating environmental bins in which the 27 | species is absent. Default = "0".} 28 | 29 | \item{unknown}{(character) code indicating environmental bins in which the 30 | species presence is unknown (uncertain). Default = "?".} 31 | 32 | \item{present_col}{color for line representing environments where the species 33 | is present. Default = "#252525".} 34 | 35 | \item{unknown_col}{color for line representing environments where the species 36 | presence is unknown (uncertain). Default = "#d9d9d9".} 37 | 38 | \item{no_change_col}{color for area of the bar representing environments where 39 | no change has been detected. Default = "#b2df8a".} 40 | 41 | \item{retraction_col}{color for area of the bar representing environments where 42 | niche retraction has been detected. Default = "#984ea3".} 43 | 44 | \item{expansion_col}{color for area of the bar representing environments where 45 | niche expansion has been detected. Default = "#4daf4a".} 46 | 47 | \item{width}{value defining the width of bars representing changes in niches; 48 | default = 1.} 49 | 50 | \item{height}{value defining the height of bars representing changes in niches; 51 | default = 1.} 52 | } 53 | \description{ 54 | nichevol_labels helps in adding bar-type labels that represent how 55 | species' niches changed from ancestors to descendants. 56 | } 57 | \details{ 58 | For the moment, only plots of type "phylogram" with "rightwards" or "leftwards" 59 | directions, created with the function \code{\link[ape]{plot.phylo}} from the 60 | package \code{ape} are supported. 61 | 62 | Evolution of ecological niches is represented in one environmental dimension, 63 | with vertical bars indicating if the niche of the descendant has expanded, 64 | retracted, or has not changed compared to its ancestor's niche. Lower values of 65 | environmental variables are represented in the lower part of the bar, and the 66 | opposite part of the bar represents higher values. 67 | 68 | Changes in niches (evolution) are defined as follows: 69 | \itemize{ 70 | \item if (ancestor == present & descendant == absent) {change <- "retraction"} 71 | \item if (ancestor == present & descendant == present) {change <- "no_change"} 72 | \item if (ancestor == present & descendant == unknown) {change <- "no_change"} 73 | \item if (ancestor == absent & descendant == present) {change <- "expansion"} 74 | \item if (ancestor == absent & descendant == absent) {change <- "no_change"} 75 | \item if (ancestor == absent & descendant == unknown) {change <- "no_change"} 76 | \item if (ancestor == unknown & descendant == absent) {change <- "no_change"} 77 | \item if (ancestor == unknown & descendant == present) {change <- "no_change"} 78 | \item if (ancestor == unknown & descendant == unknown) {change <- "no_change"} 79 | } 80 | 81 | If \code{ancestor_line} is TRUE, the ancestor line will be plotted on the bar 82 | representing niche evolution. The line will represent where, in the range of 83 | environmental conditions, the ancestor was present, and where its presence is 84 | uncertain (unknown). 85 | } 86 | \examples{ 87 | # a simple tree 88 | data("tree5", package = "nichevol") 89 | 90 | # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 91 | dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 92 | "242" = rep("1", length(tree5$tip.label)), 93 | "243" = c("1", "1", "0", "0", "0"), 94 | "244" = c("1", "1", "0", "0", "0"), 95 | "245" = c("1", "?", "0", "0", "0")) 96 | rownames(dataTable) <- tree5$tip.label 97 | 98 | # list with two objects (tree and character table) 99 | treeWdata <- geiger::treedata(tree5, dataTable) 100 | 101 | # Maximum parsimony reconstruction 102 | rec_tab <- smooth_rec(bin_par_rec(treeWdata)) 103 | 104 | # plotting and adding labels 105 | ape::plot.phylo(tree5, label.offset = 0.04) 106 | nichevol_labels(tree5, rec_tab, height = 0.6) 107 | } 108 | -------------------------------------------------------------------------------- /man/bin_table.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bin_table.R 3 | \name{bin_table} 4 | \alias{bin_table} 5 | \title{Bin table of environmental conditions in M and for occurrences} 6 | \usage{ 7 | bin_table(Ms, occurrences, species, longitude, latitude, variable, 8 | percentage_out = 5, n_bins = 20, bin_size, verbose = TRUE) 9 | } 10 | \arguments{ 11 | \item{Ms}{a list of SpatVector objects representing the accessible area 12 | (M) for all species to be analyzed. The order of species represented by each 13 | object here must coincide with the one in \code{occurrences}. See details.} 14 | 15 | \item{occurrences}{a list of data.frames of occurrence records for all species. 16 | The order of species represented by each data.frame must coincide with the one 17 | in \code{Ms}. See details.} 18 | 19 | \item{species}{(character) name of the column in occurrence data.frames that 20 | contains the name of the species.} 21 | 22 | \item{longitude}{(character) name of the column in occurrence files containing 23 | values of longitude.} 24 | 25 | \item{latitude}{(character) name of the column in occurrence files containing 26 | values of latitude.} 27 | 28 | \item{variable}{a single SpatRaster layer representing an environmental 29 | variable of interest. See details.} 30 | 31 | \item{percentage_out}{(numeric) percentage of extreme environmental data in M 32 | to be excluded in bin creation for further analyses. See details. Default = 5.} 33 | 34 | \item{n_bins}{(numeric) number of bins to be created from the range of 35 | environmental values considered when creating each character in bin tables. 36 | Default = 20. See details.} 37 | 38 | \item{bin_size}{(numeric) argument deprecated, use n_bins instead.} 39 | 40 | \item{verbose}{(logical) whether messages should be printed. Default = TRUE.} 41 | } 42 | \value{ 43 | A list containing a table of characters to represent ecological niches of the 44 | species of interest. 45 | 46 | Potential values for characters are: 47 | \itemize{ 48 | \item "1" = the species is present in those environmental conditions. 49 | \item "0" = the species is not present in those environmental conditions. This is, 50 | those environmental conditions inside the accessible area (M) are more extreme 51 | than the ones used for the species. 52 | \item "?" = there is no certainty about the species presence in those environmental 53 | conditions. This happens in environmental combinations more extreme than the 54 | ones found in the accessible area (M), when environmental conditions in 55 | species records are as extreme as the most extreme ones in M. 56 | } 57 | } 58 | \description{ 59 | bin_table helps in creating a bin table of environmental 60 | conditions in accessible areas (M) and for species occurrence records 61 | (i.e., table of characters). 62 | } 63 | \details{ 64 | Coordinates in \code{occurrences}, SpatVector objects in \code{Ms}, and 65 | SpatRaster in \code{variable} must coincide in the geographic projection in 66 | which they are represented. WGS84 with no planar projection is recommended. 67 | 68 | Accessible area (M) is understood as the geographic area that has been 69 | accessible for a species for relevant periods of time. Defining M is usually 70 | a hard task, but also a very important one, because it allows identifying 71 | uncertainties about the ability of a species to maintain populations in 72 | certain environmental conditions. For further details on this topic, see 73 | Barve et al. (2011) \url{doi:10.1016/j.ecolmodel.2011.02.011} 74 | and Machado-Stredel et al. (2021) \url{doi:10.21425/F5FBG48814}. 75 | 76 | The percentage to be defined in \code{percentage_out} excludes a percentage 77 | of extreme environmental values to prevent from considering extremely rare 78 | environmental values in the accessible area for the species (M). Being too 79 | rare, these values may have never been explored by the species; therefore, 80 | including them in the process of preparation of the table of characters 81 | (bin table) is risky. 82 | 83 | The argument \code{n_bins} helps to define how many characters (bins) will be 84 | considered for the range of values in each variable. This is, a value of 20 85 | determines that a range of temperature (5-25) will be split approximately 86 | every 1 degree. The argument \code{bin_size} has been deprecated. 87 | } 88 | \examples{ 89 | # example data 90 | ## list of species records 91 | data("occ_list", package = "nichevol") 92 | 93 | ## list of species accessible areas 94 | m_files <- list.files(system.file("extdata", package = "nichevol"), 95 | pattern = "m\\\\d.gpkg", full.names = TRUE) 96 | 97 | m_list <- lapply(m_files, terra::vect) 98 | 99 | ## raster variable 100 | temp <- terra::rast(system.file("extdata", "temp.tif", package = "nichevol")) 101 | 102 | 103 | # preparing bins 104 | char_table <- bin_table(Ms = m_list, occurrences = occ_list, species = "species", 105 | longitude = "x", latitude = "y", variable = temp, 106 | percentage_out = 5, n_bins = 20) 107 | } 108 | -------------------------------------------------------------------------------- /man/nichevol_bars.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/niche_diffbars.R 3 | \name{nichevol_bars} 4 | \alias{nichevol_bars} 5 | \title{PNG bar figures for representing niche evolution} 6 | \usage{ 7 | nichevol_bars(tree, whole_rec_table, ancestor_line = FALSE, 8 | present = "1", absent = "0", unknown = "?", 9 | present_col = "#252525", unknown_col = "#d9d9d9", 10 | no_change_col = "#b2df8a", retraction_col = "#984ea3", 11 | expansion_col = "#4daf4a", width = 50, height = 5, 12 | res = 300, output_directory, overwrite = FALSE) 13 | } 14 | \arguments{ 15 | \item{tree}{an object of class "phylo".} 16 | 17 | \item{whole_rec_table}{matrix of reconstructed bins for nodes and species 18 | derived from a process of maximum parsimony reconstruction.} 19 | 20 | \item{ancestor_line}{controls whether ancestor line is plotted. 21 | Default = FALSE.} 22 | 23 | \item{present}{(character) code indicating environmental bins in which the 24 | species is present. Default = "1".} 25 | 26 | \item{absent}{(character) code indicating environmental bins in which the 27 | species is absent. Default = "0".} 28 | 29 | \item{unknown}{(character) code indicating environmental bins in which the 30 | species presence is unknown (uncertain). Default = "?".} 31 | 32 | \item{present_col}{color for line representing environments where the species 33 | is present. Default = "#252525".} 34 | 35 | \item{unknown_col}{color for line representing environments where the species 36 | presence is unknown (uncertain). Default = "#d9d9d9".} 37 | 38 | \item{no_change_col}{color for area of the bar representing environments where 39 | no change has been detected. Default = "#b2df8a".} 40 | 41 | \item{retraction_col}{color for area of the bar representing environments where 42 | niche retraction has been detected. Default = "#984ea3".} 43 | 44 | \item{expansion_col}{color for area of the bar representing environments where 45 | niche expansion has been detected. Default = "#4daf4a".} 46 | 47 | \item{width}{(numeric) width of the device in mm to be passed to the 48 | \code{\link[grDevices]{png}} function. Default = 50.} 49 | 50 | \item{height}{(numeric) height of the device in mm to be passed to the 51 | \code{\link[grDevices]{png}} function. Default = 5.} 52 | 53 | \item{res}{(numeric) nominal resolution in ppi to be passed to the 54 | \code{\link[grDevices]{png}} function. Default = 300.} 55 | 56 | \item{output_directory}{(character) name of the folder in which results will 57 | be written. The directory will be created as part of the process.} 58 | 59 | \item{overwrite}{(logical) whether or not to overwrite existing results in 60 | \code{output_directory}. Default = FALSE.} 61 | } 62 | \value{ 63 | A folder named as in \code{output_directory} containing all bar figures 64 | produced, as well as a legend to describe what is plotted. 65 | } 66 | \description{ 67 | nichevol_bars produces bar plots that represent how 68 | species' niches (considering one environmental variable at a time) have evolved. 69 | Bars are exported as png figures to an output directory for posterior use. 70 | } 71 | \details{ 72 | Evolution of ecological niches is represented in one environmental dimension 73 | with horizontal bars indicating if the niche of the descendant has expanded, 74 | retracted, or has not changed compared to its ancestor. Lower values of 75 | environmental variables are represented in the left part of the bar, higher 76 | values at the right. 77 | 78 | Changes in niches (evolution) are defined as follows: 79 | \itemize{ 80 | \item if (ancestor == present & descendant == absent) {change <- "retraction"} 81 | \item if (ancestor == present & descendant == present) {change <- "no_change"} 82 | \item if (ancestor == present & descendant == unknown) {change <- "no_change"} 83 | \item if (ancestor == absent & descendant == present) {change <- "expansion"} 84 | \item if (ancestor == absent & descendant == absent) {change <- "no_change"} 85 | \item if (ancestor == absent & descendant == unknown) {change <- "no_change"} 86 | \item if (ancestor == unknown & descendant == absent) {change <- "no_change"} 87 | \item if (ancestor == unknown & descendant == present) {change <- "no_change"} 88 | \item if (ancestor == unknown & descendant == unknown) {change <- "no_change"} 89 | } 90 | 91 | If \code{ancestor_line} is TRUE, the ancestor line will be plotted on the bar 92 | representing niche evolution. The line will represent where, in the range of 93 | environmental conditions, the ancestor was present, and where its presence is 94 | uncertain (unknown). 95 | } 96 | \examples{ 97 | # a simple tree 98 | data("tree5", package = "nichevol") 99 | 100 | # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 101 | dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 102 | "242" = rep("1", length(tree5$tip.label)), 103 | "243" = c("1", "1", "0", "0", "0"), 104 | "244" = c("1", "1", "0", "0", "0"), 105 | "245" = c("1", "?", "0", "0", "0")) 106 | rownames(dataTable) <- tree5$tip.label 107 | 108 | # list with two objects (tree and character table) 109 | treeWdata <- geiger::treedata(tree5, dataTable) 110 | 111 | # Maximum parsimony reconstruction 112 | rec_tab <- smooth_rec(bin_par_rec(treeWdata)) 113 | 114 | # the running (before running, define a working directory) 115 | nichevol_bars(tree5, rec_tab, output_directory = file.path(tempdir(), "evolbars")) 116 | } 117 | -------------------------------------------------------------------------------- /R/hist_evalues.R: -------------------------------------------------------------------------------- 1 | #' Histograms of environmental conditions in M and for occurrences (one species) 2 | #' 3 | #' @description hist_evalues helps in creating histograms to explore environmental 4 | #' conditions in M, lines for the confidence limits of values in M, and the 5 | #' location of values in occurrence records, for one species at the time. 6 | #' 7 | #' @param M a SpatVector object representing the accessible area (M) 8 | #' for one species. See details. 9 | #' @param occurrences a data.frame of occurrence records for one species. See 10 | #' details. 11 | #' @param species (character) name of the column in \code{occurrences} that 12 | #' contains the name of the species. 13 | #' @param longitude (character) name of the column in \code{occurrences} containing 14 | #' values of longitude. 15 | #' @param latitude (character) name of the column in \code{occurrences} containing 16 | #' values of latitude. 17 | #' @param variable a single SpatRaster layer representing an environmental 18 | #' variable of interest. See details. 19 | #' @param CL_lines (numeric) confidence limits of environmental values in M to 20 | #' be plotted as lines in the histograms. See details. Default = c(95, 99). 21 | #' @param col colors for lines representing confidence limits. If NULL, colors 22 | #' are selected from a gray palette. Default = NULL. 23 | #' 24 | #' @details 25 | #' Coordinates in \code{occurrences}, SpatVector object in \code{M}, and 26 | #' SpatRaster in \code{variable} must coincide in the geographic projection in 27 | #' which they are represented. WGS84 with no planar projection is recommended. 28 | #' 29 | #' The accessible area (M) is understood as the geographic area that has been 30 | #' accessible to a species over relevant periods of time. Defining M is usually 31 | #' a hard task, but also a very important one because it allows identifying 32 | #' uncertainties about the ability of a species to maintain populations under 33 | #' certain environmental conditions. For further details on this topic, see 34 | #' Barve et al. (2011) 35 | #' and Machado-Stredel et al. (2021) . 36 | #' 37 | #' @importFrom grDevices gray.colors 38 | #' @importFrom graphics abline hist points 39 | #' @importFrom stats na.omit median 40 | #' @importFrom terra extract crop 41 | #' 42 | #' @export 43 | #' 44 | #' @usage 45 | #' hist_evalues(M, occurrences, species, longitude, latitude, variable, 46 | #' CL_lines = c(95, 99), col = NULL) 47 | #' 48 | #' @examples 49 | #' # example data 50 | #' ## list of species records 51 | #' data("occ_list", package = "nichevol") 52 | #' 53 | #' ## list of species accessible areas 54 | #' m_files <- list.files(system.file("extdata", package = "nichevol"), 55 | #' pattern = "m\\d.gpkg", full.names = TRUE) 56 | #' 57 | #' m_list <- lapply(m_files, terra::vect) 58 | #' 59 | #' ## raster variable 60 | #' temp <- terra::rast(system.file("extdata", "temp.tif", package = "nichevol")) 61 | #' 62 | #' # running stats 63 | #' hist_evalues(M = m_list[[1]], occurrences = occ_list[[1]], species = "species", 64 | #' longitude = "x", latitude = "y", variable = temp, 65 | #' CL_lines = c(95, 99), col = c("blue", "red")) 66 | 67 | hist_evalues <- function(M, occurrences, species, longitude, latitude, variable, 68 | CL_lines = c(95, 99), col = NULL) { 69 | # checking for potential errors 70 | if (missing(M)) {stop("Argument 'M' is missing.")} 71 | if (missing(occurrences)) {stop("Argument 'occurrences' is missing.")} 72 | if (missing(species)) {stop("Argument 'species' is missing.")} 73 | if (missing(longitude)) {stop("Argument 'longitude' is missing.")} 74 | if (missing(latitude)) {stop("Argument 'latitude' is missing.")} 75 | if (missing(variable)) {stop("Argument 'variable' is missing.")} 76 | if (is.null(col)) { 77 | col <- sort(gray.colors(lcll + 1), decreasing = TRUE)[1:lcll] 78 | } 79 | col1 <- rep(col, each = 2) 80 | 81 | # par settings 82 | opar <- par(no.readonly = TRUE) 83 | on.exit(par(opar)) 84 | 85 | # preparing data for plotting 86 | ## species name 87 | spname <- as.character(occurrences[1, species]) 88 | 89 | ## confidence limits length 90 | lcll <- length(CL_lines) 91 | 92 | ## get values of variables in M 93 | mvar <- terra::crop(variable, M, mask = TRUE) 94 | mval <- na.omit(mvar[][, 1]) 95 | 96 | ## distance of each absolute value to median value 97 | medians <- median(mval) 98 | df_layer <- abs(mval - medians) 99 | names(df_layer) <- mval 100 | 101 | occval <- na.omit(terra::extract(mvar, 102 | as.matrix(occurrences[, c(longitude, 103 | latitude)])))[, 1] 104 | occ_dfs <- abs(occval - medians) 105 | names(occ_dfs) <- occval 106 | 107 | y_values <- c(max(table(mval)), max(table(df_layer))) 108 | 109 | ## ranges of real values 110 | M_limit <- lapply(1:lcll, function(k) { 111 | limit <- floor((CL_lines[k]) * length(df_layer) / 100) 112 | df_layera <- sort(df_layer)[1:limit] 113 | 114 | range(as.numeric(names(df_layera))) 115 | }) 116 | 117 | M_ranges <- range(mval) 118 | M_limits <- do.call(c, M_limit) 119 | sp_ranges <- range(occval) 120 | 121 | ## for legend 122 | sym_legend <- c("", "", "Occurrences", paste0(CL_lines, "% CI")) 123 | lin <- c(NA, NA, NA, rep(1, length(CL_lines))) 124 | poi <- c(NA, NA, 1, rep(NA, length(CL_lines))) 125 | colss <- c(NA, NA, "darkgreen", col) 126 | 127 | # plotting 128 | par(mfrow = c(1, 2), cex = 0.8, mar = (c(4.5, 4, 3.5, 1) + 0.1)) 129 | ## actual values 130 | hist(as.numeric(names(df_layer)), 131 | main = gsub("_", " ", spname), xlab = "Variable values") 132 | points(as.numeric(names(occ_dfs)), 133 | rep(y_values[1], length(occ_dfs)), col = "darkgreen", 134 | pch = 1) 135 | abline(v = M_limits, col = col1) 136 | 137 | ## median deviation 138 | hist(df_layer, main = gsub("_", " ", spname), 139 | xlab = "Median deviation") 140 | points(occ_dfs, rep(y_values[2], length(occ_dfs)), 141 | col = "darkgreen", pch = 1) 142 | limit <- floor(CL_lines * length(df_layer) / 100) 143 | abline(v = sort(df_layer)[limit], col = col) 144 | 145 | ## legend 146 | legend("topright", legend = sym_legend, lty = lin, pch = poi, col = colss, 147 | cex = 0.9, box.col = "white", bg = "white", inset = 0) 148 | } 149 | -------------------------------------------------------------------------------- /man/histograms_env.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/histograms_env.R 3 | \name{histograms_env} 4 | \alias{histograms_env} 5 | \title{Histograms of environmental conditions in M and for occurrences} 6 | \usage{ 7 | histograms_env(M_folder, M_format, occ_folder, longitude, latitude, 8 | var_folder, var_format, CL_lines = c(95, 99), col = NULL, 9 | round = FALSE, round_names = NULL, multiplication_factor = 1, 10 | save_ranges = FALSE, output_directory, overwrite = FALSE, 11 | verbose = TRUE) 12 | } 13 | \arguments{ 14 | \item{M_folder}{(character) name of the folder containing files representing 15 | the accessible area (M) for all species to be analyzed. See details.} 16 | 17 | \item{M_format}{format of files representing the accessible area (M) for the 18 | species. Names of M files must match the ones for occurrence files in 19 | \code{occ_folder}. Format options are: "shp", "gpkg", or any of the options 20 | supported by \code{\link[terra]{rast}} (e.g., "tif" or "asc").} 21 | 22 | \item{occ_folder}{(character) name of the folder containing csv files of 23 | occurrence data for all species. Names of csv files must match the ones of M 24 | files in \code{M_folder}.} 25 | 26 | \item{longitude}{(character) name of the column in occurrence files containing 27 | values of longitude.} 28 | 29 | \item{latitude}{(character) name of the column in occurrence files containing 30 | values of latitude.} 31 | 32 | \item{var_folder}{(character) name of the folder containing layers to 33 | represent environmental variables.} 34 | 35 | \item{var_format}{format of layers to represent environmental variables. 36 | Format options are all the ones supported by \code{\link[terra]{rast}} 37 | (e.g., "tif" or "asc").} 38 | 39 | \item{CL_lines}{(numeric) confidence limits of environmental values in M to 40 | be plotted as lines in the histograms. See details. Default = c(95, 99).} 41 | 42 | \item{col}{colors for lines representing confidence limits. If NULL, colors 43 | are selected from a gray palette. Default = NULL.} 44 | 45 | \item{round}{(logical) whether or not to round values of one or more 46 | variables after multiplying them times the value in \code{multiplication_factor}. 47 | Default = FALSE. See details.} 48 | 49 | \item{round_names}{(character) names of the variables to be rounded. 50 | Default = NULL. If \code{round} = TRUE, names must be defined.} 51 | 52 | \item{multiplication_factor}{(numeric) value to be used to multiply the 53 | variables defined in \code{round_names}. Default = 1.} 54 | 55 | \item{save_ranges}{(logical) whether or not to save the values identified as 56 | ranges considering the whole set of values and confidence limits defined in 57 | \code{CL_lines}. Default = FALSE.} 58 | 59 | \item{output_directory}{(character) name of the folder in which results will 60 | be written.} 61 | 62 | \item{overwrite}{(logical) whether or not to overwrite existing results in 63 | \code{output_directory}. Default = FALSE.} 64 | 65 | \item{verbose}{(logical) whether messages should be printed. Default = TRUE.} 66 | } 67 | \value{ 68 | A list of data.frames containing intervals of environmental values in species 69 | occurrences and accessible areas (M), as well as values corresponding to the 70 | confidence limits defined in \code{CL_lines}. A folder named as 71 | in \code{output_directory} containing all resulting PDF files (one per 72 | variable) with histograms for all species. Files (csv) of ranges found during 73 | the analyses will be also written in \code{output_directory} if 74 | \code{save_ranges} is set as TRUE. 75 | } 76 | \description{ 77 | histograms_env creates PDF files with histogram plots of 78 | environmental conditions in M, lines for the confidence limits of values in 79 | M, and the location of values in occurrence records. This is done using data 80 | read directly from a local directory, and can be applied to various species 81 | and multiple variables. 82 | } 83 | \details{ 84 | Coordinates in csv files in \code{occ_folder}, SpatVector-like files in 85 | \code{M_folder}, and raster layers in \code{var_folder} must coincide in the 86 | geographic projection in which they are represented. WGS84 with no planar 87 | projection is recommended. 88 | 89 | Accessible area (M) is understood as the geographic area that has been 90 | accessible for a species for relevant periods of time. Defining M is usually 91 | a hard task, but also a very important one, because it allows identifying 92 | uncertainties about the ability of a species to maintain populations under 93 | certain environmental conditions. For further details on this topic, see 94 | Barve et al. (2011) \url{doi:10.1016/j.ecolmodel.2011.02.011} 95 | and Machado-Stredel et al. (2021) \url{doi:10.21425/F5FBG48814}. 96 | 97 | Rounding variables may be useful when multiple variables are considered and 98 | the values of some or all of them are too small (e.g., when using principal 99 | components). To round specific variables arguments \code{round}, 100 | \code{round_names}, and \code{multiplication_factor}, must be used accordingly. 101 | } 102 | \examples{ 103 | # preparing data and directories for examples 104 | ## directories 105 | tempdir <- file.path(tempdir(), "nevol_test") 106 | dir.create(tempdir) 107 | 108 | cvariables <- paste0(tempdir, "/variables") 109 | dir.create(cvariables) 110 | 111 | records <- paste0(tempdir, "/records") 112 | dir.create(records) 113 | 114 | m_areas <- paste0(tempdir, "/M_areas") 115 | dir.create(m_areas) 116 | 117 | histdir <- paste0(tempdir, "/Hists") 118 | 119 | ## data 120 | data("occ_list", package = "nichevol") 121 | 122 | temp <- system.file("extdata", "temp.tif", package = "nichevol") 123 | 124 | m_files <- list.files(system.file("extdata", package = "nichevol"), 125 | pattern = "m\\\\d.gpkg", full.names = TRUE) 126 | 127 | ## writing data in temporal directories 128 | spnames <- sapply(occ_list, function (x) as.character(x[1, 1])) 129 | ocnames <- paste0(records, "/", spnames, ".csv") 130 | 131 | occs <- lapply(1:length(spnames), function (x) { 132 | write.csv(occ_list[[x]], ocnames[x], row.names = FALSE) 133 | }) 134 | 135 | to_replace <- paste0(system.file("extdata", package = "nichevol"), "/") 136 | 137 | otemp <- gsub(to_replace, "", temp) 138 | file.copy(from = temp, to = paste0(cvariables, "/", otemp)) 139 | 140 | file.copy(from = m_files, to = paste0(m_areas, "/", spnames, ".gpkg")) 141 | 142 | # running analysis to produce plots 143 | hists <- histograms_env(M_folder = m_areas, M_format = "gpkg", 144 | occ_folder = records, longitude = "x", 145 | latitude = "y", var_folder = cvariables, 146 | var_format = "tif", output_directory = histdir) 147 | } 148 | -------------------------------------------------------------------------------- /man/stats_evalues.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stats_evalues.R 3 | \name{stats_evalues} 4 | \alias{stats_evalues} 5 | \title{Statistics of environmental conditions in M and for occurrences (multiple variables)} 6 | \usage{ 7 | stats_evalues(stats = c("median", "range"), M_folder, M_format, occ_folder, 8 | longitude, latitude, var_folder, var_format, round = FALSE, 9 | round_names, multiplication_factor = 1, percentage_out = 0, 10 | save = FALSE, output_directory, overwrite = FALSE, 11 | verbose = TRUE) 12 | } 13 | \arguments{ 14 | \item{stats}{(character) name or vector of names of functions to be applied 15 | to get basic statistics of environmental values.} 16 | 17 | \item{M_folder}{(character) name of the folder containing files representing 18 | the accessible area (M) for each species to be analyzed. See details.} 19 | 20 | \item{M_format}{format of files representing the accessible area (M) for the 21 | species. Names of M files must match the ones for occurrence files in 22 | \code{occ_folder}. Format options are: "shp", "gpkg", or any of the options 23 | supported by \code{\link[terra]{rast}} (e.g., "tif" or "asc").} 24 | 25 | \item{occ_folder}{(character) name of the folder containing csv files of 26 | occurrence data for all species. Names of csv files must match the ones of M 27 | files in \code{M_folder}.} 28 | 29 | \item{longitude}{(character) name of the column in occurrence files containing 30 | values of longitude.} 31 | 32 | \item{latitude}{(character) name of the column in occurrence files containing 33 | values of latitude.} 34 | 35 | \item{var_folder}{(character) name of the folder containing layers to 36 | represent environmental variables.} 37 | 38 | \item{var_format}{format of layers to represent environmental variables. 39 | Format options are all the ones supported by \code{\link[terra]{rast}} 40 | (e.g., "tif" or "asc").} 41 | 42 | \item{round}{(logical) whether or not to round the values of one or more 43 | variables after multiplying them times the value in \code{multiplication_factor}. 44 | Default = FALSE. See details.} 45 | 46 | \item{round_names}{(character) names of the variables to be rounded. 47 | Default = NULL. If \code{round} = TRUE, names must be defined.} 48 | 49 | \item{multiplication_factor}{(numeric) value to be used to multiply the 50 | variables defined in \code{round_names}. Default = 1.} 51 | 52 | \item{percentage_out}{(numeric) percentage of extreme environmental data in M 53 | to be excluded in bin creation for further analyses. See details. Default = 0.} 54 | 55 | \item{save}{(logical) whether or not to save the results in working directory. 56 | Default = FALSE.} 57 | 58 | \item{output_directory}{(character) name of the folder in which results will 59 | be written.} 60 | 61 | \item{overwrite}{(logical) whether or not to overwrite existing results in 62 | \code{output_directory}. Default = FALSE.} 63 | 64 | \item{verbose}{(logical) whether messages should be printed. Default = TRUE.} 65 | } 66 | \value{ 67 | A list named as the variables present in \code{var_folder}, containing all 68 | tables with statistics of environmental values in M and in species records. 69 | A folder named as in \code{output_directory} containing all resultant csv 70 | files with the tables of statistics will be created if \code{save} is set as 71 | TRUE. 72 | } 73 | \description{ 74 | stats_evalues helps in creating csv files with statistics 75 | of environmental conditions in accessible areas (M) and species occurrence 76 | records. This is done using data read directly from a local directory, and 77 | can be applied to various species and multiple variables. 78 | } 79 | \details{ 80 | Coordinates in csv files in \code{occ_folder}, SpatVector-like files in 81 | \code{M_folder}, and raster layers in \code{var_folder} must coincide in the 82 | geographic projection in which they are represented. WGS84 with no planar 83 | projection is recommended. 84 | 85 | Accessible area (M) is understood as the geographic area that has been 86 | accessible for a species for relevant periods of time. Defining M is usually 87 | a hard task, but also a very important one, because it allows identifying 88 | uncertainties about the ability of a species to maintain populations in 89 | certain environmental conditions. For further details on this topic, see 90 | Barve et al. (2011) \url{doi:10.1016/j.ecolmodel.2011.02.011} 91 | and Machado-Stredel et al. (2021) \url{doi:10.21425/F5FBG48814}. 92 | 93 | Rounding variables may be useful when multiple variables are considered and 94 | the values of some or all of them are too small (e.g., when using principal 95 | components). To round specific variables arguments \code{round}, 96 | \code{round_names}, and \code{multiplication_factor}, must be used accordingly. 97 | 98 | The percentage to be defined in \code{percentage_out} excludes a percentage 99 | of extreme environmental values to prevent the algorithm from considering 100 | extremely rare environmental values in the accessible area for the species (M). 101 | Being too rare, these values may have never been explored by the species; 102 | therefore, including them in the process of preparation of the table of 103 | characters (bin table) is risky. 104 | } 105 | \examples{ 106 | # preparing data and directories for examples 107 | ## directories 108 | tempdir <- file.path(tempdir(), "nevol_test") 109 | dir.create(tempdir) 110 | 111 | cvariables <- paste0(tempdir, "/variables") 112 | dir.create(cvariables) 113 | 114 | records <- paste0(tempdir, "/records") 115 | dir.create(records) 116 | 117 | m_areas <- paste0(tempdir, "/M_areas") 118 | dir.create(m_areas) 119 | 120 | ## data 121 | data("occ_list", package = "nichevol") 122 | 123 | temp <- system.file("extdata", "temp.tif", package = "nichevol") 124 | 125 | m_files <- list.files(system.file("extdata", package = "nichevol"), 126 | pattern = "m\\\\d.gpkg", full.names = TRUE) 127 | 128 | ## writing data in temporal directories 129 | spnames <- sapply(occ_list, function (x) as.character(x[1, 1])) 130 | ocnames <- paste0(records, "/", spnames, ".csv") 131 | 132 | occs <- lapply(1:length(spnames), function (x) { 133 | write.csv(occ_list[[x]], ocnames[x], row.names = FALSE) 134 | }) 135 | 136 | to_replace <- paste0(system.file("extdata", package = "nichevol"), "/") 137 | 138 | otemp <- gsub(to_replace, "", temp) 139 | file.copy(from = temp, to = paste0(cvariables, "/", otemp)) 140 | 141 | file.copy(from = m_files, to = paste0(m_areas, "/", spnames, ".gpkg")) 142 | stats <- stats_evalues(stats = c("median", "range"), M_folder = m_areas, 143 | M_format = "gpkg", occ_folder = records, 144 | longitude = "x", latitude = "y", 145 | var_folder = cvariables, var_format = "tif", 146 | percentage_out = 5) 147 | } 148 | -------------------------------------------------------------------------------- /R/bin_tables.R: -------------------------------------------------------------------------------- 1 | #' Bin tables of environmental conditions in M and for occurrences from objects 2 | #' 3 | #' @description bin_tables helps in creating bin tables of environmental 4 | #' conditions in accessible areas (M) and species occurrence records 5 | #' (i.e., table of characters). This is done using results from previous 6 | #' analyses, and can be applied to various species and multiple variables. 7 | #' 8 | #' @param ranges list of ranges of environmental values in M and in species 9 | #' occurrences derived from using the function \code{\link{histograms_env}}. 10 | #' @param percentage_out (numeric) percentage of extreme environmental data in M 11 | #' to be excluded in bin creation for further analyses. See details. Default = 5. 12 | #' @param n_bins (numeric) number of bins to be created from the range of 13 | #' environmental values considered when creating each character in bin tables. 14 | #' Default = 20. See details. 15 | #' @param bin_size (numeric) argument deprecated, use n_bins instead. 16 | #' @param save (logical) whether or not to save the results in working directory. 17 | #' Default = FALSE. 18 | #' @param output_directory (character) name of the folder in which results will be 19 | #' written. 20 | #' @param overwrite (logical) whether or not to overwrite existing results 21 | #' in \code{output_directory}. Default = FALSE. 22 | #' @param verbose (logical) whether messages should be printed. Default = TRUE. 23 | #' 24 | #' @details 25 | #' The percentage to be defined in \code{percentage_out} must correspond with 26 | #' one of the confidence limits defined in \code{\link{histograms_env}} 27 | #' (argument \code{CL_lines}). For instance, if \code{CL_lines} = 95, then 28 | #' \code{percentage_out} can only be either 5 (keeping data inside the 95 CL) or 29 | #' 0 (to avoid exclusion of extreme values in M). 30 | #' 31 | #' Excluding a certain percentage of extreme environmental values prevents the 32 | #' algorithm from considering extremely rare environmental values in the 33 | #' accessible area for the species (M). Being too rare, these values may have 34 | #' never been explored by the species; therefore, including them in the process 35 | #' of preparation of the table of characters (bin table) is risky. 36 | #' 37 | #' The argument \code{n_bins} helps to define how many characters (bins) will be 38 | #' considered for the range of values in each variable. This is, a value of 20 39 | #' determines that a range of temperature (5-25) will be split approximately 40 | #' every 1 degree. The argument \code{bin_size} has been deprecated. 41 | #' 42 | #' @return 43 | #' A list named as in \code{ranges} containing the table(s) of characters. 44 | #' A folder named as in \code{output_directory} containing all resulting csv 45 | #' files with the tables of characters will be created if \code{save} is set as 46 | #' TRUE. 47 | #' 48 | #' Potential values for characters are: 49 | #' - "1" = the species is present in those environmental conditions. 50 | #' - "0" = the species is not present in those environmental conditions. This is, 51 | #' those environmental conditions inside the accessible area (M) are more extreme 52 | #' than the ones used for the species. 53 | #' - "?" = there is no certainty about the species presence in those environmental 54 | #' conditions. This happens if environmental combinations are more extreme than 55 | #' the ones found in the accessible area (M), when environmental conditions in 56 | #' species records are as extreme as the most extreme ones in M. 57 | #' 58 | #' @importFrom utils write.csv 59 | #' 60 | #' @export 61 | #' 62 | #' @usage 63 | #' bin_tables(ranges, percentage_out = 5, n_bins = 20, bin_size, save = FALSE, 64 | #' output_directory, overwrite = FALSE, verbose = TRUE) 65 | #' 66 | #' @examples 67 | #' # simple list of ranges 68 | #' ranges <- list(temp = data.frame(Species = c("sp1", "sp2", "sp3"), 69 | #' Species_lower = c(120, 56, 59.75), 70 | #' Species_upper = c(265, 333, 333), 71 | #' M_lower = c(93, 39, 56), 72 | #' M_upper = c(302, 333, 333), 73 | #' M_95_lowerCL = c(158, 91, 143), 74 | #' M_95_upperCL = c(292, 290, 326)), 75 | #' prec = data.frame(Species = c("sp1", "sp2", "sp3"), 76 | #' Species_lower = c(597, 3, 3), 77 | #' Species_upper = c(3492, 2673, 6171), 78 | #' M_lower = c(228, 3, 3), 79 | #' M_upper = c(6369, 7290, 6606), 80 | #' M_95_lowerCL = c(228, 3, 3), 81 | #' M_95_upperCL = c(3114, 2376, 2568))) 82 | #' 83 | #' # bin preparation 84 | #' bins <- bin_tables(ranges, percentage_out = 5, n_bins = 20) 85 | #' 86 | #' # see arguments save and output_directory to write results in local directory 87 | 88 | bin_tables <- function(ranges, percentage_out = 5, n_bins = 20, bin_size, 89 | save = FALSE, output_directory, overwrite = FALSE, 90 | verbose = TRUE) { 91 | # checking for potential errors 92 | if (missing(ranges)) {stop("Argument 'ranges' is missing.")} 93 | if (!missing(bin_size)) { 94 | warning("Argument 'bin_size' is deprecated, using 'n_bins'.") 95 | } 96 | if (save == TRUE) { 97 | if (missing(output_directory)) { 98 | stop("Argument 'output_directory' is missing.") 99 | } else { 100 | if (overwrite == FALSE & dir.exists(output_directory)) { 101 | stop("'output_directory' already exists, to replace it use 'overwrite' = TRUE.") 102 | } 103 | if (overwrite == TRUE & dir.exists(output_directory)) { 104 | unlink(x = output_directory, recursive = TRUE, force = TRUE) 105 | } 106 | } 107 | } 108 | 109 | if (verbose == TRUE) { 110 | message("\nPreparing bin tables using ranges:") 111 | } 112 | 113 | # directory for results 114 | if (save == TRUE) {dir.create(output_directory)} 115 | 116 | bin_tabs <- lapply(1:length(ranges), function(i) { 117 | # preparing ranges 118 | spnames <- ranges[[1]][, 1] 119 | cl <- paste0("M_", 100 - percentage_out, c("_lowerCL", "_upperCL")) 120 | sp_r <- paste0("Species_", c("lower", "upper")) 121 | 122 | overall_range <- range(c(ranges[[i]][, c(sp_r, cl)])) 123 | M_range <- ranges[[i]][, cl] 124 | sp_range <- ranges[[i]][, 2:3] 125 | 126 | # bin tables 127 | bin_size <- diff(overall_range) / n_bins 128 | 129 | bin_table <- bin_env(overall_range, M_range, sp_range, bin_size) 130 | rownames(bin_table) <- gsub("_", " ", spnames) 131 | 132 | # write table 133 | if (save == TRUE) { 134 | write.csv(bin_table, 135 | paste0(output_directory, "/", names(ranges)[i], "_bin_table.csv"), 136 | row.names = TRUE) 137 | } 138 | 139 | if (verbose == TRUE) { 140 | message(i, " of ", length(ranges), " variables processed") 141 | } 142 | 143 | return(bin_table) 144 | }) 145 | 146 | names(bin_tabs) <- names(ranges) 147 | return(bin_tabs) 148 | } 149 | -------------------------------------------------------------------------------- /R/niche_bars.R: -------------------------------------------------------------------------------- 1 | #' PNG bar figures to represent ecological niches of distinct taxa 2 | #' 3 | #' @description niche_bars produces bar plots that represent species 4 | #' ecological niches in one environmental variable. Bars are exported as png 5 | #' figures to an output directory for posterior use. 6 | #' 7 | #' @param tree an object of class "phylo". 8 | #' @param whole_rec_table matrix of environmental bins for all tips and nodes 9 | #' derived from functions \code{\link{bin_par_rec}} or \code{\link{bin_ml_rec}}. 10 | #' @param present (character) code indicating environmental bins in which the 11 | #' species is present. Default = "1". 12 | #' @param unknown (character) code indicating environmental bins in which the 13 | #' species presence is unknown (uncertain). Default = "?". 14 | #' @param present_col color for area of the bar representing environments where 15 | #' the species is present. Default = "#e41a1c". 16 | #' @param unknown_col color for area of the bar representing environments where 17 | #' the species presence is unknown (uncertain). Default = "#969696". 18 | #' @param absent_col color for area of the bar representing environments where 19 | #' no change has been detected. Default = "#377eb8". 20 | #' @param width (numeric) width of the device in mm to be passed to the 21 | #' \code{\link[grDevices]{png}} function. Default = 50. 22 | #' @param height (numeric) height of the device in mm to be passed to the 23 | #' \code{\link[grDevices]{png}} function. Default = 5. 24 | #' @param res (numeric) nominal resolution in ppi to be passed to the 25 | #' \code{\link[grDevices]{png}} function. Default = 300. 26 | #' @param output_directory (character) name of the folder in which results will 27 | #' be written. The directory will be created as part of the process. 28 | #' @param overwrite (logical) whether or not to overwrite existing results in 29 | #' \code{output_directory}. Default = FALSE. 30 | #' 31 | #' @details 32 | #' Ecological niches are represented in one environmental dimension with vertical 33 | #' bars that indicate if the species is present, absent, or if its presence is 34 | #' uncertain in the range of environmental conditions. Lower values of 35 | #' environmental variables are represented in the left part of the bar, and the 36 | #' opposite part of the bar represents higher values. 37 | #' 38 | #' @return 39 | #' A folder named as in \code{output_directory} containing all bar figures 40 | #' produced, as well as a legend to describe what is plotted. 41 | #' 42 | #' @importFrom graphics par plot polygon legend 43 | #' @importFrom grDevices dev.off png 44 | #' 45 | #' @export 46 | #' 47 | #' @usage 48 | #' niche_bars(tree, whole_rec_table, present = "1", unknown = "?", 49 | #' present_col = "#e41a1c", unknown_col = "#969696", 50 | #' absent_col = "#377eb8", width = 50, height = 5, res = 300, 51 | #' output_directory, overwrite = FALSE) 52 | #' 53 | #' @examples 54 | #' # a simple tree 55 | #' data("tree5", package = "nichevol") 56 | #' 57 | #' # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 58 | #' dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 59 | #' "242" = rep("1", length(tree5$tip.label)), 60 | #' "243" = c("1", "1", "0", "0", "0"), 61 | #' "244" = c("1", "1", "0", "0", "0"), 62 | #' "245" = c("1", "?", "0", "0", "0")) 63 | #' rownames(dataTable) <- tree5$tip.label 64 | #' 65 | #' # list with two objects (tree and character table) 66 | #' treeWdata <- geiger::treedata(tree5, dataTable) 67 | #' 68 | #' # Maximum parsimony reconstruction 69 | #' rec_tab <- smooth_rec(bin_par_rec(treeWdata)) 70 | #' 71 | #' # the running (before running, define a working directory) 72 | #' niche_bars(tree5, rec_tab, output_directory = file.path(tempdir(), "nichebars")) 73 | 74 | 75 | niche_bars <- function(tree, whole_rec_table, present = "1", unknown = "?", 76 | present_col = "#e41a1c", unknown_col = "#969696", 77 | absent_col = "#377eb8", width = 50, height = 5, res = 300, 78 | output_directory, overwrite = FALSE) { 79 | 80 | # testing for potential errors 81 | if (missing(tree)) {stop("Argument 'tree' is needed to perform the analyses.")} 82 | if (missing(whole_rec_table)) {stop("Argument 'whole_rec_table' needs to be defined.")} 83 | if ("LogLik" %in% rownames(whole_rec_table)) { 84 | whole_rec_table <- whole_rec_table[1:(nrow(whole_rec_table) - 3), ] 85 | } 86 | if (missing(output_directory)) { 87 | stop("Argument 'output_directory' is missing.") 88 | } else { 89 | if (overwrite == FALSE & dir.exists(output_directory)) { 90 | stop("'output_directory' already exists, to replace it use 'overwrite' = TRUE.") 91 | } 92 | if (overwrite == TRUE & dir.exists(output_directory)) { 93 | unlink(x = output_directory, recursive = TRUE, force = TRUE) 94 | } 95 | } 96 | 97 | # par settings 98 | opar <- par(no.readonly = TRUE) 99 | on.exit(par(opar)) 100 | 101 | # reorganizing character table 102 | tlab <- tree$tip.label 103 | nrt <- nrow(whole_rec_table) 104 | rns <- c(tlab, rownames(whole_rec_table)[(length(tlab) + 1):nrt]) 105 | whole_rec_table <- rbind(whole_rec_table[tlab, ], 106 | whole_rec_table[(length(tlab) + 1):nrt, ]) 107 | rownames(whole_rec_table) <- rns 108 | 109 | # organizing data 110 | nnames <- rownames(whole_rec_table); nnames <- nnames[!nnames %in% tlab] 111 | spnames <- c(tlab, nnames) 112 | bnames <- c(tlab, paste0("Node", nnames)) 113 | 114 | tpol <- ncol(whole_rec_table) 115 | wpol <- 1 / tpol 116 | 117 | h_vertices <- seq(0, 1, wpol) 118 | v_vertices <- rep(c(0, 0.05), each = 2) 119 | 120 | dir.create(output_directory) 121 | 122 | barss <- sapply(1:nrow(whole_rec_table), function(j) { 123 | bar_name <- paste0(output_directory, "/", bnames[j], 124 | "_bar.png") 125 | 126 | png(filename = bar_name, width = width, height = height, units = "mm", 127 | bg = "transparent", res = res) 128 | par(mar = rep(0, 4)) 129 | plot(x = c(0, 1), y = c(0, 0.05), col = "transparent", axes = FALSE) 130 | 131 | polys <- sapply(1:(length(h_vertices) - 1), function(x) { 132 | if (as.character(whole_rec_table[j, x]) == unknown) { 133 | pcolor <- unknown_col 134 | } else { 135 | pcolor <- ifelse(as.character(whole_rec_table[j, x]) == present, 136 | present_col, absent_col) 137 | } 138 | 139 | xs <- c(h_vertices[x], h_vertices[x + 1], h_vertices[x + 1], h_vertices[x]) 140 | 141 | polygon(x = xs, y = v_vertices, col = pcolor, border = NA) 142 | }) 143 | dev.off() 144 | }) 145 | 146 | # legend 147 | png(filename = paste0(output_directory, "/0_Legend.png"), width = 50, 148 | height = 30, units = "mm", bg = "transparent", res = res) 149 | par(mar = rep(0, 4), cex = 1.2) 150 | plot(x = c(0, 0.5), y = c(0, 0.5), col = "transparent", axes = FALSE) 151 | legend("center", legend = c("Uncertain", "Present", "Not present"), 152 | bty = "n", pch = 22, pt.cex = 2.2, col = "transparent", 153 | pt.bg = c(unknown_col, present_col, absent_col)) 154 | invisible(dev.off()) 155 | } 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /R/stats_eval.R: -------------------------------------------------------------------------------- 1 | #' Statistics of environmental conditions in M and for occurrences (one variable) 2 | #' 3 | #' @description stats_eval helps in creating tables of descriptive statistics 4 | #' of environmental conditions in accessible areas (M) and occurrence 5 | #' records for one environmental variable at a time. 6 | #' 7 | #' @param stats (character) name or vector of names of functions to be applied 8 | #' to get basic statistics of environmental values. 9 | #' @param Ms a list of SpatVector objects representing the accessible area 10 | #' (M) for each species to be analyzed. The order of species represented by each 11 | #' object here must coincide with the one in \code{occurrences}. See details. 12 | #' @param occurrences a list of data.frames of occurrence records for all species. 13 | #' The order of species represented by each data.frame must coincide with the one 14 | #' in \code{Ms}. See details. 15 | #' @param species (character) name of the column in occurrence data.frames that 16 | #' contains the name of the species. 17 | #' @param longitude (character) name of the column in occurrence files containing 18 | #' values of longitude. 19 | #' @param latitude (character) name of the column in occurrence files containing 20 | #' values of latitude. 21 | #' @param variable a single SpatRaster layer of an environmental variable of 22 | #' interest. See details. 23 | #' @param percentage_out (numeric) percentage of extreme environmental data in M 24 | #' to be excluded in bin creation for further analyses. See details. Default = 0. 25 | #' @param verbose (logical) whether messages should be printed. Default = TRUE. 26 | #' 27 | #' @details 28 | #' Coordinates in \code{occurrences}, SpatVector objects in \code{Ms}, and 29 | #' SpatRaster in \code{variable} must coincide in the geographic projection in 30 | #' which they are represented. WGS84 with no planar projection is recommended. 31 | #' 32 | #' Accessible area (M) is understood as the geographic area that has been 33 | #' accessible for a species for relevant periods of time. Defining M is usually 34 | #' a hard task, but also a very important one, because it allows identifying 35 | #' uncertainties about the ability of a species to maintain populations in 36 | #' certain environmental conditions. For further details on this topic, see 37 | #' Barve et al. (2011) 38 | #' and Machado-Stredel et al. (2021) . 39 | #' 40 | #' The percentage to be defined in \code{percentage_out} excludes a percentage 41 | #' of extreme environmental values to prevent from considering extremely rare 42 | #' environmental values in the accessible area for the species (M). Being too 43 | #' rare, these values may have never been explored by the species; therefore, 44 | #' including them in the process of preparation of the table of characters 45 | #' (bin table) is risky. 46 | #' 47 | #' @return 48 | #' A list containing tables with statistics of the values in \code{variable}, 49 | #' for the species M and occurrences. 50 | #' 51 | #' @importFrom stats na.omit median 52 | #' @importFrom terra extract crop 53 | #' 54 | #' @export 55 | #' 56 | #' @usage 57 | #' stats_eval(stats = c("median", "range"), Ms, occurrences, species, 58 | #' longitude, latitude, variable, percentage_out = 0, verbose = TRUE) 59 | #' 60 | #' @examples 61 | #' # example data 62 | #' ## list of species records 63 | #' data("occ_list", package = "nichevol") 64 | #' 65 | #' ## list of species accessible areas 66 | #' m_files <- list.files(system.file("extdata", package = "nichevol"), 67 | #' pattern = "m\\d.gpkg", full.names = TRUE) 68 | #' 69 | #' m_list <- lapply(m_files, terra::vect) 70 | #' 71 | #' ## raster variable 72 | #' temp <- terra::rast(system.file("extdata", "temp.tif", package = "nichevol")) 73 | #' 74 | #' # running stats 75 | #' stat <- stats_eval(stats = c("mean", "sd", "median", "range", "quantile"), 76 | #' Ms = m_list, occurrences = occ_list, species = "species", 77 | #' longitude = "x", latitude = "y", variable = temp, 78 | #' percentage_out = 0) 79 | 80 | stats_eval <- function(stats = c("median", "range"), Ms, occurrences, species, 81 | longitude, latitude, variable, percentage_out = 0, 82 | verbose = TRUE) { 83 | # checking for potential errors 84 | if (missing(Ms)) {stop("Argument 'Ms' is missing.")} 85 | if (missing(occurrences)) {stop("Argument 'occurrences' is missing.")} 86 | if (missing(species)) {stop("Argument 'species' is missing.")} 87 | if (missing(longitude)) {stop("Argument 'longitude' is missing.")} 88 | if (missing(latitude)) {stop("Argument 'latitude' is missing.")} 89 | if (missing(variable)) {stop("Argument 'variable' is missing.")} 90 | if (!is.list(Ms)) {stop("Argument 'Ms' must be a list.")} 91 | if (!is.list(occurrences)) {stop("Argument 'occurrences' must be a list.")} 92 | if (length(Ms) != length(occurrences)) { 93 | stop("'Ms' and 'occurrences' must have the same length and order of species listed must be the same.") 94 | } 95 | 96 | if (verbose == TRUE) { 97 | message("\nPreparing statistics from environmental layer and species data:") 98 | } 99 | 100 | sp_stats <- lapply(1:length(occurrences), function(j) { 101 | ## preparing e values 102 | mvar <- terra::crop(variable, Ms[[j]], mask = TRUE) 103 | mval <- na.omit(mvar[][, 1]) 104 | if (percentage_out > 0) { 105 | medians <- median(mval) 106 | df_layer <- abs(mval - medians) 107 | names(df_layer) <- mval 108 | limit <- floor((100 - percentage_out) * length(df_layer)/100) 109 | df_layer <- sort(df_layer)[1:limit] 110 | mval <- as.numeric(names(df_layer)) 111 | } 112 | 113 | occval <- na.omit(terra::extract(mvar, 114 | as.matrix(occurrences[[j]][, c(longitude, 115 | latitude)])))[, 1] 116 | 117 | ## obtaining statistics 118 | if (length(stats) > 1) { 119 | m_stats <- lapply(1:length(stats), function(k) { 120 | eval(parse(text = paste0(stats[k], "(mval)"))) 121 | }) 122 | o_stats <- lapply(1:length(stats), function(k) { 123 | eval(parse(text = paste0(stats[k], "(occval)"))) 124 | }) 125 | 126 | } else { 127 | m_stats <- eval(parse(text = paste0(stats, "(mval)"))) 128 | o_stats <- eval(parse(text = paste0(stats, "(occval)"))) 129 | } 130 | names(m_stats) <- stats 131 | names(o_stats) <- stats 132 | 133 | spn <- as.character(occurrences[[j]][1, species]) 134 | 135 | if (verbose == TRUE) { 136 | message("\t", j, " of ", length(occurrences), " species finished") 137 | } 138 | return(list(sp = spn, M = unlist(m_stats), Occurrences = unlist(o_stats))) 139 | }) 140 | 141 | # preparing tables with results 142 | spnames <- gsub("_", " ", unlist(lapply(sp_stats, function(x) {x[[1]]}))) 143 | m_table <- data.frame(Species = spnames, 144 | do.call(rbind, lapply(sp_stats, function(x) {x[[2]]}))) 145 | o_table <- data.frame(Species = spnames, 146 | do.call(rbind, lapply(sp_stats, function(x) {x[[3]]}))) 147 | 148 | return(list(M_stats = m_table, Occurrence_stats = o_table)) 149 | } 150 | -------------------------------------------------------------------------------- /man/bin_tables0.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bin_tables0.R 3 | \name{bin_tables0} 4 | \alias{bin_tables0} 5 | \title{Bin tables of environmental conditions in M and for occurrences from data} 6 | \usage{ 7 | bin_tables0(M_folder, M_format, occ_folder, longitude, 8 | latitude, var_folder, var_format, round = FALSE, 9 | round_names, multiplication_factor = 1, 10 | percentage_out = 5, n_bins = 20, bin_size, save = FALSE, 11 | output_directory, overwrite = FALSE, verbose = TRUE) 12 | } 13 | \arguments{ 14 | \item{M_folder}{(character) name of the folder containing files representing 15 | the accessible area (M) for all species to be analyzed. See details.} 16 | 17 | \item{M_format}{format of files representing the accessible area (M) for the 18 | species. Names of M files must match the ones for occurrence files in 19 | \code{occ_folder}. Format options are: "shp", "gpkg", or any of the options 20 | supported by \code{\link[terra]{rast}} (e.g., "tif" or "asc").} 21 | 22 | \item{occ_folder}{(character) name of the folder containing csv files of 23 | occurrence data for all species. Names of csv files must match the ones of M 24 | files in \code{M_folder}.} 25 | 26 | \item{longitude}{(character) name of the column in occurrence files containing 27 | values of longitude.} 28 | 29 | \item{latitude}{(character) name of the column in occurrence files containing 30 | values of latitude.} 31 | 32 | \item{var_folder}{(character) name of the folder containing layers to 33 | represent environmental variables.} 34 | 35 | \item{var_format}{format of layers to represent environmental variables. 36 | Format options are all the ones supported by \code{\link[terra]{rast}} 37 | (e.g., "tif" or "asc").} 38 | 39 | \item{round}{(logical) whether or not to round the values of one or more 40 | variables after multiplying them times the value in \code{multiplication_factor}. 41 | Default = FALSE. See details.} 42 | 43 | \item{round_names}{(character) names of the variables to be rounded. 44 | Default = NULL. If \code{round} = TRUE, names must be defined.} 45 | 46 | \item{multiplication_factor}{(numeric) value to be used to multiply the 47 | variables defined in \code{round_names}. Default = 1.} 48 | 49 | \item{percentage_out}{(numeric) percentage of extreme environmental data in M 50 | to be excluded in bin creation for further analyses. See details. Default = 5.} 51 | 52 | \item{n_bins}{(numeric) number of bins to be created from the range of 53 | environmental values considered when creating each character in bin tables. 54 | Default = 20. See details.} 55 | 56 | \item{bin_size}{(numeric) argument deprecated, use n_bins instead.} 57 | 58 | \item{save}{(logical) whether or not to save the results in working directory. 59 | Default = FALSE.} 60 | 61 | \item{output_directory}{(character) name of the folder in which results will be 62 | written.} 63 | 64 | \item{overwrite}{(logical) whether or not to overwrite existing results in 65 | \code{output_directory}. Default = FALSE.} 66 | 67 | \item{verbose}{(logical) whether messages should be printed. Default = TRUE.} 68 | } 69 | \value{ 70 | A list named as the variables present in \code{var_folder}, containing all 71 | tables of characters. A folder named as in \code{output_directory} containing 72 | all resultant csv files with the tables of characters will be created if 73 | \code{save} is set as TRUE. 74 | 75 | Potential values for characters are: 76 | \itemize{ 77 | \item "1" = the species is present in those environmental conditions. 78 | \item "0" = the species is not present in those environmental conditions. This is, 79 | those environmental conditions inside the accessible area (M) are more extreme 80 | than the ones used for the species. 81 | \item "?" = there is no certainty about the species presence in those environmental 82 | conditions. This happens in environmental combinations more extreme than the 83 | ones found in the accessible area (M), when environmental conditions in 84 | species records are as extreme as the most extreme ones in M. 85 | } 86 | } 87 | \description{ 88 | bin_tables0 helps in creating bin tables of environmental 89 | conditions in accessible areas (M) and species occurrence records 90 | (i.e., table of characters). This is done using data read directly from a 91 | local directory, and can be applied to various species and multiple variables. 92 | } 93 | \details{ 94 | Coordinates in csv files in \code{occ_folder}, SpatVector-like files in 95 | \code{M_folder}, and raster layers in \code{var_folder} must coincide in the 96 | geographic projection in which they are represented. WGS84 with no planar 97 | projection is recommended. 98 | 99 | Accessible area (M) is understood as the geographic area that has been 100 | accessible for a species for relevant periods of time. Defining M is usually 101 | a hard task, but also a very important one, because it allows identifying 102 | uncertainties about the ability of a species to maintain populations in 103 | certain environmental conditions. For further details on this topic, see 104 | Barve et al. (2011) \url{doi:10.1016/j.ecolmodel.2011.02.011} 105 | and Machado-Stredel et al. (2021) \url{doi:10.21425/F5FBG48814}. 106 | 107 | Rounding variables may be useful when multiple variables are considered and 108 | the values of some or all of them are too small (e.g., when using principal 109 | components). To round specific variables arguments \code{round}, 110 | \code{round_names}, and \code{multiplication_factor}, must be used accordingly. 111 | 112 | The percentage to be defined in \code{percentage_out} excludes a percentage 113 | of extreme environmental values to prevent from considering extremely rare 114 | environmental values in the accessible area for the species (M). Being too 115 | rare, these values may have never been explored by the species; therefore, 116 | including them in the process of preparation of the table of characters 117 | (bin table) is risky. 118 | 119 | The argument \code{n_bins} helps to define how many characters (bins) will be 120 | considered for the range of values in each variable. This is, a value of 20 121 | determines that a range of temperature (5-25) will be split approximately 122 | every 1 degree. The argument \code{bin_size} has been deprecated. 123 | } 124 | \examples{ 125 | # preparing data and directories for example 126 | ## directories 127 | tempdir <- file.path(tempdir(), "nevol_test") 128 | dir.create(tempdir) 129 | 130 | cvariables <- paste0(tempdir, "/variables") 131 | dir.create(cvariables) 132 | 133 | records <- paste0(tempdir, "/records") 134 | dir.create(records) 135 | 136 | m_areas <- paste0(tempdir, "/M_areas") 137 | dir.create(m_areas) 138 | 139 | ## data 140 | data("occ_list", package = "nichevol") 141 | 142 | temp <- system.file("extdata", "temp.tif", package = "nichevol") 143 | 144 | m_files <- list.files(system.file("extdata", package = "nichevol"), 145 | pattern = "m\\\\d.gpkg", full.names = TRUE) 146 | 147 | ## writing data in temporal directories 148 | spnames <- sapply(occ_list, function (x) as.character(x[1, 1])) 149 | ocnames <- paste0(records, "/", spnames, ".csv") 150 | 151 | occs <- lapply(1:length(spnames), function (x) { 152 | write.csv(occ_list[[x]], ocnames[x], row.names = FALSE) 153 | }) 154 | 155 | to_replace <- paste0(system.file("extdata", package = "nichevol"), "/") 156 | 157 | otemp <- gsub(to_replace, "", temp) 158 | file.copy(from = temp, to = paste0(cvariables, "/", otemp)) 159 | 160 | file.copy(from = m_files, to = paste0(m_areas, "/", spnames, ".gpkg")) 161 | 162 | # preparing tables 163 | tabs <- bin_tables0(M_folder = m_areas, M_format = "gpkg", occ_folder = records, 164 | longitude = "x", latitude = "y", var_folder = cvariables, 165 | var_format = "tif") 166 | } 167 | -------------------------------------------------------------------------------- /R/bin_table.R: -------------------------------------------------------------------------------- 1 | #' Bin table of environmental conditions in M and for occurrences 2 | #' 3 | #' @description bin_table helps in creating a bin table of environmental 4 | #' conditions in accessible areas (M) and for species occurrence records 5 | #' (i.e., table of characters). 6 | #' 7 | #' @param Ms a list of SpatVector objects representing the accessible area 8 | #' (M) for all species to be analyzed. The order of species represented by each 9 | #' object here must coincide with the one in \code{occurrences}. See details. 10 | #' @param occurrences a list of data.frames of occurrence records for all species. 11 | #' The order of species represented by each data.frame must coincide with the one 12 | #' in \code{Ms}. See details. 13 | #' @param species (character) name of the column in occurrence data.frames that 14 | #' contains the name of the species. 15 | #' @param longitude (character) name of the column in occurrence files containing 16 | #' values of longitude. 17 | #' @param latitude (character) name of the column in occurrence files containing 18 | #' values of latitude. 19 | #' @param variable a single SpatRaster layer representing an environmental 20 | #' variable of interest. See details. 21 | #' @param percentage_out (numeric) percentage of extreme environmental data in M 22 | #' to be excluded in bin creation for further analyses. See details. Default = 5. 23 | #' @param n_bins (numeric) number of bins to be created from the range of 24 | #' environmental values considered when creating each character in bin tables. 25 | #' Default = 20. See details. 26 | #' @param bin_size (numeric) argument deprecated, use n_bins instead. 27 | #' @param verbose (logical) whether messages should be printed. Default = TRUE. 28 | #' 29 | #' @details 30 | #' Coordinates in \code{occurrences}, SpatVector objects in \code{Ms}, and 31 | #' SpatRaster in \code{variable} must coincide in the geographic projection in 32 | #' which they are represented. WGS84 with no planar projection is recommended. 33 | #' 34 | #' Accessible area (M) is understood as the geographic area that has been 35 | #' accessible for a species for relevant periods of time. Defining M is usually 36 | #' a hard task, but also a very important one, because it allows identifying 37 | #' uncertainties about the ability of a species to maintain populations in 38 | #' certain environmental conditions. For further details on this topic, see 39 | #' Barve et al. (2011) 40 | #' and Machado-Stredel et al. (2021) . 41 | #' 42 | #' The percentage to be defined in \code{percentage_out} excludes a percentage 43 | #' of extreme environmental values to prevent from considering extremely rare 44 | #' environmental values in the accessible area for the species (M). Being too 45 | #' rare, these values may have never been explored by the species; therefore, 46 | #' including them in the process of preparation of the table of characters 47 | #' (bin table) is risky. 48 | #' 49 | #' The argument \code{n_bins} helps to define how many characters (bins) will be 50 | #' considered for the range of values in each variable. This is, a value of 20 51 | #' determines that a range of temperature (5-25) will be split approximately 52 | #' every 1 degree. The argument \code{bin_size} has been deprecated. 53 | #' 54 | #' @return 55 | #' A list containing a table of characters to represent ecological niches of the 56 | #' species of interest. 57 | #' 58 | #' Potential values for characters are: 59 | #' - "1" = the species is present in those environmental conditions. 60 | #' - "0" = the species is not present in those environmental conditions. This is, 61 | #' those environmental conditions inside the accessible area (M) are more extreme 62 | #' than the ones used for the species. 63 | #' - "?" = there is no certainty about the species presence in those environmental 64 | #' conditions. This happens in environmental combinations more extreme than the 65 | #' ones found in the accessible area (M), when environmental conditions in 66 | #' species records are as extreme as the most extreme ones in M. 67 | #' 68 | #' @importFrom stats na.omit median 69 | #' @importFrom terra extract crop 70 | #' 71 | #' @export 72 | #' 73 | #' @usage 74 | #' bin_table(Ms, occurrences, species, longitude, latitude, variable, 75 | #' percentage_out = 5, n_bins = 20, bin_size, verbose = TRUE) 76 | #' 77 | #' @examples 78 | #' # example data 79 | #' ## list of species records 80 | #' data("occ_list", package = "nichevol") 81 | #' 82 | #' ## list of species accessible areas 83 | #' m_files <- list.files(system.file("extdata", package = "nichevol"), 84 | #' pattern = "m\\d.gpkg", full.names = TRUE) 85 | #' 86 | #' m_list <- lapply(m_files, terra::vect) 87 | #' 88 | #' ## raster variable 89 | #' temp <- terra::rast(system.file("extdata", "temp.tif", package = "nichevol")) 90 | #' 91 | #' 92 | #' # preparing bins 93 | #' char_table <- bin_table(Ms = m_list, occurrences = occ_list, species = "species", 94 | #' longitude = "x", latitude = "y", variable = temp, 95 | #' percentage_out = 5, n_bins = 20) 96 | 97 | bin_table <- function(Ms, occurrences, species, longitude, latitude, variable, 98 | percentage_out = 5, n_bins = 20, bin_size, verbose = TRUE) { 99 | # checking for potential errors 100 | if (missing(Ms)) {stop("Argument 'Ms' is missing.")} 101 | if (missing(occurrences)) {stop("Argument 'occurrences' is missing.")} 102 | if (missing(species)) {stop("Argument 'species' is missing.")} 103 | if (missing(longitude)) {stop("Argument 'longitude' is missing.")} 104 | if (missing(latitude)) {stop("Argument 'latitude' is missing.")} 105 | if (missing(variable)) {stop("Argument 'variable' is missing.")} 106 | if (!is.list(Ms)) {stop("Argument 'Ms' must be a list.")} 107 | if (!is.list(occurrences)) {stop("Argument 'occurrences' must be a list.")} 108 | if (!missing(bin_size)) { 109 | warning("Argument 'bin_size' is deprecated, using 'n_bins'.") 110 | } 111 | if (length(Ms) != length(occurrences)) { 112 | stop("'Ms' and 'occurrences' must have the same length and order of species listed must be the same.") 113 | } 114 | 115 | M_range <- list() 116 | sp_range <- list() 117 | spnames <- vector() 118 | 119 | if (verbose == TRUE) { 120 | message("\n Preparing range values:") 121 | } 122 | 123 | for (j in 1:length(occurrences)) { 124 | # processing 125 | ## get values of variable in M 126 | mvar <- terra::crop(variable, Ms[[j]], mask = TRUE) 127 | mval <- na.omit(mvar[][, 1]) 128 | 129 | ## distance of each absolute value to median value 130 | medians <- median(mval) 131 | df_layer <- abs(mval - medians) 132 | names(df_layer) <- mval 133 | 134 | ## limit 135 | limit <- floor((100 - percentage_out) * length(df_layer) / 100) 136 | df_layer <- sort(df_layer)[1:limit] 137 | 138 | M_range[[j]] <- range(as.numeric(names(df_layer))) 139 | 140 | ## occurrences 141 | occval <- na.omit(terra::extract(mvar, 142 | as.matrix(occurrences[[j]][, c(longitude, 143 | latitude)])))[, 1] 144 | sp_range[[j]] <- range(occval) 145 | spnames[j] <- as.character(occurrences[[j]][1, species]) 146 | 147 | if (verbose == TRUE) { 148 | message("\t", j, " of ", length(occurrences), " species finished") 149 | } 150 | } 151 | 152 | # overall range 153 | M_range <- round(do.call(rbind, M_range), 2) 154 | sp_range <- round(do.call(rbind, sp_range), 2) 155 | overall_range <- range(c(c(M_range), c(sp_range))) 156 | 157 | # bin tables 158 | if (verbose == TRUE) { 159 | message("\n Preparing bin tables using ranges:") 160 | } 161 | 162 | bin_size <- diff(overall_range) / n_bins 163 | 164 | bin_table <- bin_env(overall_range, M_range, sp_range, bin_size) 165 | rownames(bin_table) <- gsub("_", " ", spnames) 166 | 167 | return(bin_table) 168 | } 169 | -------------------------------------------------------------------------------- /R/niche_diffbars.R: -------------------------------------------------------------------------------- 1 | #' PNG bar figures for representing niche evolution 2 | #' 3 | #' @description nichevol_bars produces bar plots that represent how 4 | #' species' niches (considering one environmental variable at a time) have evolved. 5 | #' Bars are exported as png figures to an output directory for posterior use. 6 | #' 7 | #' @param tree an object of class "phylo". 8 | #' @param whole_rec_table matrix of reconstructed bins for nodes and species 9 | #' derived from a process of maximum parsimony reconstruction. 10 | #' @param ancestor_line controls whether ancestor line is plotted. 11 | #' Default = FALSE. 12 | #' @param present (character) code indicating environmental bins in which the 13 | #' species is present. Default = "1". 14 | #' @param absent (character) code indicating environmental bins in which the 15 | #' species is absent. Default = "0". 16 | #' @param unknown (character) code indicating environmental bins in which the 17 | #' species presence is unknown (uncertain). Default = "?". 18 | #' @param present_col color for line representing environments where the species 19 | #' is present. Default = "#252525". 20 | #' @param unknown_col color for line representing environments where the species 21 | #' presence is unknown (uncertain). Default = "#d9d9d9". 22 | #' @param no_change_col color for area of the bar representing environments where 23 | #' no change has been detected. Default = "#b2df8a". 24 | #' @param retraction_col color for area of the bar representing environments where 25 | #' niche retraction has been detected. Default = "#984ea3". 26 | #' @param expansion_col color for area of the bar representing environments where 27 | #' niche expansion has been detected. Default = "#4daf4a". 28 | #' @param width (numeric) width of the device in mm to be passed to the 29 | #' \code{\link[grDevices]{png}} function. Default = 50. 30 | #' @param height (numeric) height of the device in mm to be passed to the 31 | #' \code{\link[grDevices]{png}} function. Default = 5. 32 | #' @param res (numeric) nominal resolution in ppi to be passed to the 33 | #' \code{\link[grDevices]{png}} function. Default = 300. 34 | #' @param output_directory (character) name of the folder in which results will 35 | #' be written. The directory will be created as part of the process. 36 | #' @param overwrite (logical) whether or not to overwrite existing results in 37 | #' \code{output_directory}. Default = FALSE. 38 | #' 39 | #' @details 40 | #' Evolution of ecological niches is represented in one environmental dimension 41 | #' with horizontal bars indicating if the niche of the descendant has expanded, 42 | #' retracted, or has not changed compared to its ancestor. Lower values of 43 | #' environmental variables are represented in the left part of the bar, higher 44 | #' values at the right. 45 | #' 46 | #' Changes in niches (evolution) are defined as follows: 47 | #' - if (ancestor == present & descendant == absent) {change <- "retraction"} 48 | #' - if (ancestor == present & descendant == present) {change <- "no_change"} 49 | #' - if (ancestor == present & descendant == unknown) {change <- "no_change"} 50 | #' - if (ancestor == absent & descendant == present) {change <- "expansion"} 51 | #' - if (ancestor == absent & descendant == absent) {change <- "no_change"} 52 | #' - if (ancestor == absent & descendant == unknown) {change <- "no_change"} 53 | #' - if (ancestor == unknown & descendant == absent) {change <- "no_change"} 54 | #' - if (ancestor == unknown & descendant == present) {change <- "no_change"} 55 | #' - if (ancestor == unknown & descendant == unknown) {change <- "no_change"} 56 | #' 57 | #' If \code{ancestor_line} is TRUE, the ancestor line will be plotted on the bar 58 | #' representing niche evolution. The line will represent where, in the range of 59 | #' environmental conditions, the ancestor was present, and where its presence is 60 | #' uncertain (unknown). 61 | #' 62 | #' @return 63 | #' A folder named as in \code{output_directory} containing all bar figures 64 | #' produced, as well as a legend to describe what is plotted. 65 | #' 66 | #' @importFrom utils combn 67 | #' @importFrom graphics par plot polygon legend lines 68 | #' @importFrom grDevices dev.off png 69 | #' 70 | #' @export 71 | #' 72 | #' @usage 73 | #' nichevol_bars(tree, whole_rec_table, ancestor_line = FALSE, 74 | #' present = "1", absent = "0", unknown = "?", 75 | #' present_col = "#252525", unknown_col = "#d9d9d9", 76 | #' no_change_col = "#b2df8a", retraction_col = "#984ea3", 77 | #' expansion_col = "#4daf4a", width = 50, height = 5, 78 | #' res = 300, output_directory, overwrite = FALSE) 79 | #' 80 | #' @examples 81 | #' # a simple tree 82 | #' data("tree5", package = "nichevol") 83 | #' 84 | #' # a matrix of niche charactes (1 = present, 0 = absent, ? = unknown) 85 | #' dataTable <- cbind("241" = rep("1", length(tree5$tip.label)), 86 | #' "242" = rep("1", length(tree5$tip.label)), 87 | #' "243" = c("1", "1", "0", "0", "0"), 88 | #' "244" = c("1", "1", "0", "0", "0"), 89 | #' "245" = c("1", "?", "0", "0", "0")) 90 | #' rownames(dataTable) <- tree5$tip.label 91 | #' 92 | #' # list with two objects (tree and character table) 93 | #' treeWdata <- geiger::treedata(tree5, dataTable) 94 | #' 95 | #' # Maximum parsimony reconstruction 96 | #' rec_tab <- smooth_rec(bin_par_rec(treeWdata)) 97 | #' 98 | #' # the running (before running, define a working directory) 99 | #' nichevol_bars(tree5, rec_tab, output_directory = file.path(tempdir(), "evolbars")) 100 | 101 | nichevol_bars <- function(tree, whole_rec_table, ancestor_line = FALSE, 102 | present = "1", absent = "0", unknown = "?", 103 | present_col = "#252525", unknown_col = "#d9d9d9", 104 | no_change_col = "#b2df8a", retraction_col = "#984ea3", 105 | expansion_col = "#4daf4a", width = 50, height = 5, 106 | res = 300, output_directory, overwrite = FALSE) { 107 | 108 | # testing for potential errors 109 | if (missing(tree)) {stop("Argument 'tree' is needed to perform the analyses.")} 110 | if (missing(whole_rec_table)) {stop("Argument 'whole_rec_table' needs to be defined.")} 111 | if ("LogLik" %in% rownames(whole_rec_table)) { 112 | whole_rec_table <- whole_rec_table[1:(nrow(whole_rec_table) - 3), ] 113 | } 114 | if (missing(output_directory)) { 115 | stop("Argument 'output_directory' is missing.") 116 | } else { 117 | if (overwrite == FALSE & dir.exists(output_directory)) { 118 | stop("'output_directory' already exists, to replace it use 'overwrite' = TRUE.") 119 | } 120 | if (overwrite == TRUE & dir.exists(output_directory)) { 121 | unlink(x = output_directory, recursive = TRUE, force = TRUE) 122 | } 123 | } 124 | 125 | # par settings 126 | opar <- par(no.readonly = TRUE) 127 | on.exit(par(opar)) 128 | 129 | # reorganizing character table 130 | tlab <- tree$tip.label 131 | nrt <- nrow(whole_rec_table) 132 | rns <- c(tlab, rownames(whole_rec_table)[(length(tlab) + 1):nrt]) 133 | whole_rec_table <- rbind(whole_rec_table[tlab, ], 134 | whole_rec_table[(length(tlab) + 1):nrt, ]) 135 | rownames(whole_rec_table) <- rns 136 | 137 | edges <- tree$edge 138 | 139 | # preparing plotting parameters 140 | spp <- rownames(whole_rec_table) 141 | 142 | tpol <- ncol(whole_rec_table) 143 | wpol <- 1 / tpol 144 | 145 | h_vertices <- seq(0, 1, wpol) 146 | v_vertices <- rep(c(0, 0.05), each = 2) 147 | y_line <- rep(mean(c(0, 0.05)), 2) 148 | 149 | # combinations for comparisons 150 | all_comb <- cbind(spp[edges[, 1]], spp[edges[, 2]]) 151 | all_nam <- paste("From_node", all_comb[, 1], "to", all_comb[, 2], sep = "_") 152 | 153 | # plotting data 154 | dir.create(output_directory) # folder 155 | 156 | # comparisons and plots 157 | comp_list <- lapply(1:nrow(all_comb), function(x){ 158 | comp <- sapply(1:ncol(whole_rec_table), function(z) { 159 | from <- whole_rec_table[all_comb[x, 1], z] 160 | to <- whole_rec_table[all_comb[x, 2], z] 161 | if (from == present & to == absent) {comp <- "loss"} 162 | if (from == present & to == present) {comp <- "nc"} 163 | if (from == present & to == unknown) {comp <- "nc"} 164 | if (from == absent & to == present) {comp <- "gain"} 165 | if (from == absent & to == absent) {comp <- "nc"} 166 | if (from == absent & to == unknown) {comp <- "nc"} 167 | if (from == unknown & to == absent) {comp <- "nc"} 168 | if (from == unknown & to == present) {comp <- "nc"} 169 | if (from == unknown & to == unknown) {comp <- "nc"} 170 | return(comp) 171 | }) 172 | 173 | # infor for lines 174 | linesp <- whole_rec_table[all_comb[x, 1], ] 175 | 176 | # bar creation 177 | bar_name <- paste0(output_directory, "/", all_nam[x], "_bar.png") 178 | 179 | png(filename = bar_name, width = width, height = height, units = "mm", 180 | bg = "transparent", res = res) 181 | par(mar = rep(0, 4)) 182 | plot(x = c(0, 1), y = c(0, 0.05), col = "transparent", axes = FALSE) 183 | 184 | poly_lines <- sapply(1:(length(h_vertices) - 1), function(y) { 185 | # polygons 186 | if (comp[y] == "nc") { 187 | pcolor <- no_change_col 188 | } else { 189 | pcolor <- ifelse(comp[y] == "gain", expansion_col, retraction_col) 190 | } 191 | 192 | xs <- c(h_vertices[y], h_vertices[y + 1], h_vertices[y + 1], h_vertices[y]) 193 | polygon(x = xs, y = v_vertices, col = pcolor, border = NA) 194 | 195 | # lines 196 | if (ancestor_line == TRUE) { 197 | if (linesp[y] == unknown) { 198 | pcolor <- unknown_col 199 | } else { 200 | pcolor <- ifelse(linesp[y] == present, present_col, "transparent") 201 | } 202 | 203 | xs <- c(h_vertices[y], h_vertices[y + 1]) 204 | lines(x = xs, y = y_line, col = pcolor, lty = 1, lwd = 1.7) 205 | } 206 | }) 207 | dev.off() 208 | 209 | }) 210 | 211 | # legend 212 | png(filename = paste0(output_directory, "/0_Legend.png"), width = 50, height = 50, 213 | units = "mm", bg = "transparent", res = res) 214 | par(mar = rep(0, 4), cex = 1.2) 215 | plot(x = c(0, 0.5), y = c(0, 0.5), col = "transparent", axes = FALSE) 216 | 217 | if (ancestor_line == TRUE) { 218 | legend("center", 219 | legend = c("Uncertain", "Present", "No change", "Retraction", "Expansion"), 220 | lty = c(1, NA, NA, NA, NA), lwd = 2, 221 | col = c("transparent", NA, NA, NA, NA), bty = "n") 222 | 223 | legend("center", legend = c(" ", "", "", "", ""), bty = "n", 224 | pch = 22, pt.bg = c(NA, NA, no_change_col, retraction_col, expansion_col), 225 | pt.cex = 2.2, lty = 1, col = "transparent") 226 | 227 | legend("center", legend = c(" ", "", "", "", ""), 228 | bty = "n", lty = c(1, 1, NA, NA, NA), lwd = 2, 229 | col = c(unknown_col, present_col, NA, NA, NA)) 230 | } else { 231 | legend("center", legend = c("No change", "Retraction", "Expansion"), 232 | pch = 22, pt.bg = c(no_change_col, retraction_col, expansion_col), 233 | col = "transparent", pt.cex = 2.2, bty = "n") 234 | } 235 | 236 | invisible(dev.off()) 237 | } 238 | -------------------------------------------------------------------------------- /R/stats_evalues.R: -------------------------------------------------------------------------------- 1 | #' Statistics of environmental conditions in M and for occurrences (multiple variables) 2 | #' 3 | #' @description stats_evalues helps in creating csv files with statistics 4 | #' of environmental conditions in accessible areas (M) and species occurrence 5 | #' records. This is done using data read directly from a local directory, and 6 | #' can be applied to various species and multiple variables. 7 | #' 8 | #' @param stats (character) name or vector of names of functions to be applied 9 | #' to get basic statistics of environmental values. 10 | #' @param M_folder (character) name of the folder containing files representing 11 | #' the accessible area (M) for each species to be analyzed. See details. 12 | #' @param M_format format of files representing the accessible area (M) for the 13 | #' species. Names of M files must match the ones for occurrence files in 14 | #' \code{occ_folder}. Format options are: "shp", "gpkg", or any of the options 15 | #' supported by \code{\link[terra]{rast}} (e.g., "tif" or "asc"). 16 | #' @param occ_folder (character) name of the folder containing csv files of 17 | #' occurrence data for all species. Names of csv files must match the ones of M 18 | #' files in \code{M_folder}. 19 | #' @param longitude (character) name of the column in occurrence files containing 20 | #' values of longitude. 21 | #' @param latitude (character) name of the column in occurrence files containing 22 | #' values of latitude. 23 | #' @param var_folder (character) name of the folder containing layers to 24 | #' represent environmental variables. 25 | #' @param var_format format of layers to represent environmental variables. 26 | #' Format options are all the ones supported by \code{\link[terra]{rast}} 27 | #' (e.g., "tif" or "asc"). 28 | #' @param round (logical) whether or not to round the values of one or more 29 | #' variables after multiplying them times the value in \code{multiplication_factor}. 30 | #' Default = FALSE. See details. 31 | #' @param round_names (character) names of the variables to be rounded. 32 | #' Default = NULL. If \code{round} = TRUE, names must be defined. 33 | #' @param multiplication_factor (numeric) value to be used to multiply the 34 | #' variables defined in \code{round_names}. Default = 1. 35 | #' @param percentage_out (numeric) percentage of extreme environmental data in M 36 | #' to be excluded in bin creation for further analyses. See details. Default = 0. 37 | #' @param save (logical) whether or not to save the results in working directory. 38 | #' Default = FALSE. 39 | #' @param output_directory (character) name of the folder in which results will 40 | #' be written. 41 | #' @param overwrite (logical) whether or not to overwrite existing results in 42 | #' \code{output_directory}. Default = FALSE. 43 | #' @param verbose (logical) whether messages should be printed. Default = TRUE. 44 | #' 45 | #' @details 46 | #' Coordinates in csv files in \code{occ_folder}, SpatVector-like files in 47 | #' \code{M_folder}, and raster layers in \code{var_folder} must coincide in the 48 | #' geographic projection in which they are represented. WGS84 with no planar 49 | #' projection is recommended. 50 | #' 51 | #' Accessible area (M) is understood as the geographic area that has been 52 | #' accessible for a species for relevant periods of time. Defining M is usually 53 | #' a hard task, but also a very important one, because it allows identifying 54 | #' uncertainties about the ability of a species to maintain populations in 55 | #' certain environmental conditions. For further details on this topic, see 56 | #' Barve et al. (2011) 57 | #' and Machado-Stredel et al. (2021) . 58 | #' 59 | #' Rounding variables may be useful when multiple variables are considered and 60 | #' the values of some or all of them are too small (e.g., when using principal 61 | #' components). To round specific variables arguments \code{round}, 62 | #' \code{round_names}, and \code{multiplication_factor}, must be used accordingly. 63 | #' 64 | #' The percentage to be defined in \code{percentage_out} excludes a percentage 65 | #' of extreme environmental values to prevent the algorithm from considering 66 | #' extremely rare environmental values in the accessible area for the species (M). 67 | #' Being too rare, these values may have never been explored by the species; 68 | #' therefore, including them in the process of preparation of the table of 69 | #' characters (bin table) is risky. 70 | #' 71 | #' @return 72 | #' A list named as the variables present in \code{var_folder}, containing all 73 | #' tables with statistics of environmental values in M and in species records. 74 | #' A folder named as in \code{output_directory} containing all resultant csv 75 | #' files with the tables of statistics will be created if \code{save} is set as 76 | #' TRUE. 77 | #' 78 | #' @importFrom stats na.omit median 79 | #' @importFrom utils write.csv read.csv 80 | #' @importFrom terra extract crop nlyr rast vect 81 | #' 82 | #' @export 83 | #' 84 | #' @usage 85 | #' stats_evalues(stats = c("median", "range"), M_folder, M_format, occ_folder, 86 | #' longitude, latitude, var_folder, var_format, round = FALSE, 87 | #' round_names, multiplication_factor = 1, percentage_out = 0, 88 | #' save = FALSE, output_directory, overwrite = FALSE, 89 | #' verbose = TRUE) 90 | #' 91 | #' @examples 92 | #' # preparing data and directories for examples 93 | #' ## directories 94 | #' tempdir <- file.path(tempdir(), "nevol_test") 95 | #' dir.create(tempdir) 96 | #' 97 | #' cvariables <- paste0(tempdir, "/variables") 98 | #' dir.create(cvariables) 99 | #' 100 | #' records <- paste0(tempdir, "/records") 101 | #' dir.create(records) 102 | #' 103 | #' m_areas <- paste0(tempdir, "/M_areas") 104 | #' dir.create(m_areas) 105 | #' 106 | #' ## data 107 | #' data("occ_list", package = "nichevol") 108 | #' 109 | #' temp <- system.file("extdata", "temp.tif", package = "nichevol") 110 | #' 111 | #' m_files <- list.files(system.file("extdata", package = "nichevol"), 112 | #' pattern = "m\\d.gpkg", full.names = TRUE) 113 | #' 114 | #' ## writing data in temporal directories 115 | #' spnames <- sapply(occ_list, function (x) as.character(x[1, 1])) 116 | #' ocnames <- paste0(records, "/", spnames, ".csv") 117 | #' 118 | #' occs <- lapply(1:length(spnames), function (x) { 119 | #' write.csv(occ_list[[x]], ocnames[x], row.names = FALSE) 120 | #' }) 121 | #' 122 | #' to_replace <- paste0(system.file("extdata", package = "nichevol"), "/") 123 | #' 124 | #' otemp <- gsub(to_replace, "", temp) 125 | #' file.copy(from = temp, to = paste0(cvariables, "/", otemp)) 126 | #' 127 | #' file.copy(from = m_files, to = paste0(m_areas, "/", spnames, ".gpkg")) 128 | #' stats <- stats_evalues(stats = c("median", "range"), M_folder = m_areas, 129 | #' M_format = "gpkg", occ_folder = records, 130 | #' longitude = "x", latitude = "y", 131 | #' var_folder = cvariables, var_format = "tif", 132 | #' percentage_out = 5) 133 | 134 | stats_evalues <- function(stats = c("median", "range"), M_folder, M_format, 135 | occ_folder, longitude, latitude, var_folder, 136 | var_format, round = FALSE, round_names, 137 | multiplication_factor = 1, percentage_out = 0, 138 | save = FALSE, output_directory, overwrite = FALSE, 139 | verbose = TRUE) { 140 | # checking for potential errors 141 | if (missing(M_folder)) {stop("Argument 'M_folder' is missing.")} 142 | if (missing(M_format)) {stop("Argument 'M_format' is missing.")} 143 | if (missing(occ_folder)) {stop("Argument 'occ_folder' is missing.")} 144 | if (missing(longitude)) {stop("Argument 'longitude' is missing.")} 145 | if (missing(latitude)) {stop("Argument 'latitude' is missing.")} 146 | if (missing(var_folder)) {stop("Argument 'var_folder' is missing.")} 147 | if (missing(var_format)) {stop("Argument 'var_format' is missing.")} 148 | if (save == TRUE) { 149 | if (missing(output_directory)) { 150 | stop("Argument 'output_directory' is missing.") 151 | } else { 152 | if (overwrite == FALSE & dir.exists(output_directory)) { 153 | stop("'output_directory' already exists, to replace it use 'overwrite' = TRUE.") 154 | } 155 | if (overwrite == TRUE & dir.exists(output_directory)) { 156 | unlink(x = output_directory, recursive = TRUE, force = TRUE) 157 | } 158 | } 159 | } 160 | 161 | # formats and data to start 162 | if (verbose == TRUE) { 163 | message("\nPreparing data, please wait...\n") 164 | } 165 | 166 | ## records 167 | occlist <- list.files(path = occ_folder, pattern = ".csv$", full.names = TRUE) 168 | 169 | ## M areas 170 | M_patt <- paste0(M_format, "$") 171 | mlist <- list.files(path = M_folder, pattern = M_patt, full.names = TRUE) 172 | 173 | ## species names 174 | subs <- paste0(".", M_format) 175 | spnames <- gsub(subs, "", list.files(path = M_folder, pattern = M_patt)) 176 | 177 | ## variables 178 | v_patt <- paste0(var_format, "$") 179 | variables <- terra::rast(list.files(path = var_folder, pattern = v_patt, 180 | full.names = TRUE)) 181 | 182 | var_names <- names(variables) 183 | if (round == TRUE) { 184 | rounds <- round(variables[[round_names]] * multiplication_factor) 185 | noround <- var_names[!var_names %in% round_names] 186 | variables <- c(variables[[noround]], rounds) 187 | } 188 | 189 | # directory for results 190 | if (save == TRUE) {dir.create(output_directory)} 191 | if (verbose == TRUE) { 192 | message("Preparing statistics from environmental layers and species data:") 193 | } 194 | 195 | n_vars <- terra::nlyr(variables) 196 | 197 | var_stats <- lapply(1:n_vars, function(i) { 198 | sp_stats <- lapply(1:length(occlist), function(j) { 199 | ## M 200 | if (M_format %in% c("shp", "gpkg")) { 201 | M <- terra::vect(mlist[j]) 202 | } else { 203 | M <- terra::rast(mlist[j]) 204 | } 205 | 206 | ## occurrences 207 | occ <- read.csv(occlist[j]) 208 | 209 | # processing 210 | ## get values of variables in M 211 | mvar <- terra::crop(variables[[i]], M, mask = TRUE) 212 | mval <- na.omit(mvar[][, 1]) 213 | 214 | if (percentage_out > 0) { 215 | medians <- median(mval) 216 | df_layer <- abs(mval - medians) 217 | names(df_layer) <- mval 218 | limit <- floor((100 - percentage_out) * length(df_layer) / 100) 219 | df_layer <- sort(df_layer)[1:limit] 220 | mval <- as.numeric(names(df_layer)) 221 | } 222 | 223 | ## occurrences 224 | occval <- na.omit(terra::extract(mvar, as.matrix(occ[, c(longitude, 225 | latitude)]))[, 1]) 226 | 227 | ## obtaining statistics 228 | if (length(stats) > 1) { 229 | m_stats <- lapply(1:length(stats), function(k) { 230 | eval(parse(text = paste0(stats[k], "(mval)"))) 231 | }) 232 | o_stats <- lapply(1:length(stats), function(k) { 233 | eval(parse(text = paste0(stats[k], "(occval)"))) 234 | }) 235 | 236 | } else { 237 | m_stats <- eval(parse(text = paste0(stats, "(mval)"))) 238 | o_stats <- eval(parse(text = paste0(stats, "(occval)"))) 239 | } 240 | names(m_stats) <- stats 241 | names(o_stats) <- stats 242 | 243 | message("\t", j, " of ", length(occlist), " species finished") 244 | return(list(M = unlist(m_stats), Occurrences = unlist(o_stats))) 245 | }) 246 | 247 | # preparing tables with results 248 | spnames <- gsub("_", " ", spnames) 249 | m_table <- data.frame(Species = spnames, 250 | do.call(rbind, lapply(sp_stats, function(x) {x[[1]]}))) 251 | o_table <- data.frame(Species = spnames, 252 | do.call(rbind, lapply(sp_stats, function(x) {x[[2]]}))) 253 | 254 | # write table 255 | if (save == TRUE) { 256 | write.csv(m_table, 257 | paste0(output_directory, "/", var_names[i], "_M_stats.csv"), 258 | row.names = FALSE) 259 | write.csv(o_table, 260 | paste0(output_directory, "/", var_names[i], "_Occurrence_stats.csv"), 261 | row.names = FALSE) 262 | } 263 | 264 | if (verbose == TRUE) { 265 | message(i, " of ", n_vars, " variables processed") 266 | } 267 | 268 | return(list(M_stats = m_table, Occurrence_stats = o_table)) 269 | }) 270 | 271 | # returning final results 272 | names(var_stats) <- var_names 273 | return(var_stats) 274 | } 275 | -------------------------------------------------------------------------------- /R/bin_tables0.R: -------------------------------------------------------------------------------- 1 | #' Bin tables of environmental conditions in M and for occurrences from data 2 | #' 3 | #' @description bin_tables0 helps in creating bin tables of environmental 4 | #' conditions in accessible areas (M) and species occurrence records 5 | #' (i.e., table of characters). This is done using data read directly from a 6 | #' local directory, and can be applied to various species and multiple variables. 7 | #' 8 | #' @param M_folder (character) name of the folder containing files representing 9 | #' the accessible area (M) for all species to be analyzed. See details. 10 | #' @param M_format format of files representing the accessible area (M) for the 11 | #' species. Names of M files must match the ones for occurrence files in 12 | #' \code{occ_folder}. Format options are: "shp", "gpkg", or any of the options 13 | #' supported by \code{\link[terra]{rast}} (e.g., "tif" or "asc"). 14 | #' @param occ_folder (character) name of the folder containing csv files of 15 | #' occurrence data for all species. Names of csv files must match the ones of M 16 | #' files in \code{M_folder}. 17 | #' @param longitude (character) name of the column in occurrence files containing 18 | #' values of longitude. 19 | #' @param latitude (character) name of the column in occurrence files containing 20 | #' values of latitude. 21 | #' @param var_folder (character) name of the folder containing layers to 22 | #' represent environmental variables. 23 | #' @param var_format format of layers to represent environmental variables. 24 | #' Format options are all the ones supported by \code{\link[terra]{rast}} 25 | #' (e.g., "tif" or "asc"). 26 | #' @param round (logical) whether or not to round the values of one or more 27 | #' variables after multiplying them times the value in \code{multiplication_factor}. 28 | #' Default = FALSE. See details. 29 | #' @param round_names (character) names of the variables to be rounded. 30 | #' Default = NULL. If \code{round} = TRUE, names must be defined. 31 | #' @param multiplication_factor (numeric) value to be used to multiply the 32 | #' variables defined in \code{round_names}. Default = 1. 33 | #' @param percentage_out (numeric) percentage of extreme environmental data in M 34 | #' to be excluded in bin creation for further analyses. See details. Default = 5. 35 | #' @param n_bins (numeric) number of bins to be created from the range of 36 | #' environmental values considered when creating each character in bin tables. 37 | #' Default = 20. See details. 38 | #' @param bin_size (numeric) argument deprecated, use n_bins instead. 39 | #' @param save (logical) whether or not to save the results in working directory. 40 | #' Default = FALSE. 41 | #' @param output_directory (character) name of the folder in which results will be 42 | #' written. 43 | #' @param overwrite (logical) whether or not to overwrite existing results in 44 | #' \code{output_directory}. Default = FALSE. 45 | #' @param verbose (logical) whether messages should be printed. Default = TRUE. 46 | #' 47 | #' @details 48 | #' Coordinates in csv files in \code{occ_folder}, SpatVector-like files in 49 | #' \code{M_folder}, and raster layers in \code{var_folder} must coincide in the 50 | #' geographic projection in which they are represented. WGS84 with no planar 51 | #' projection is recommended. 52 | #' 53 | #' Accessible area (M) is understood as the geographic area that has been 54 | #' accessible for a species for relevant periods of time. Defining M is usually 55 | #' a hard task, but also a very important one, because it allows identifying 56 | #' uncertainties about the ability of a species to maintain populations in 57 | #' certain environmental conditions. For further details on this topic, see 58 | #' Barve et al. (2011) 59 | #' and Machado-Stredel et al. (2021) . 60 | #' 61 | #' Rounding variables may be useful when multiple variables are considered and 62 | #' the values of some or all of them are too small (e.g., when using principal 63 | #' components). To round specific variables arguments \code{round}, 64 | #' \code{round_names}, and \code{multiplication_factor}, must be used accordingly. 65 | #' 66 | #' The percentage to be defined in \code{percentage_out} excludes a percentage 67 | #' of extreme environmental values to prevent from considering extremely rare 68 | #' environmental values in the accessible area for the species (M). Being too 69 | #' rare, these values may have never been explored by the species; therefore, 70 | #' including them in the process of preparation of the table of characters 71 | #' (bin table) is risky. 72 | #' 73 | #' The argument \code{n_bins} helps to define how many characters (bins) will be 74 | #' considered for the range of values in each variable. This is, a value of 20 75 | #' determines that a range of temperature (5-25) will be split approximately 76 | #' every 1 degree. The argument \code{bin_size} has been deprecated. 77 | #' 78 | #' @return 79 | #' A list named as the variables present in \code{var_folder}, containing all 80 | #' tables of characters. A folder named as in \code{output_directory} containing 81 | #' all resultant csv files with the tables of characters will be created if 82 | #' \code{save} is set as TRUE. 83 | #' 84 | #' Potential values for characters are: 85 | #' - "1" = the species is present in those environmental conditions. 86 | #' - "0" = the species is not present in those environmental conditions. This is, 87 | #' those environmental conditions inside the accessible area (M) are more extreme 88 | #' than the ones used for the species. 89 | #' - "?" = there is no certainty about the species presence in those environmental 90 | #' conditions. This happens in environmental combinations more extreme than the 91 | #' ones found in the accessible area (M), when environmental conditions in 92 | #' species records are as extreme as the most extreme ones in M. 93 | #' 94 | #' @importFrom utils write.csv read.csv 95 | #' @importFrom stats na.omit median 96 | #' @importFrom terra extract crop nlyr rast vect 97 | #' 98 | #' @export 99 | #' 100 | #' @usage 101 | #' bin_tables0(M_folder, M_format, occ_folder, longitude, 102 | #' latitude, var_folder, var_format, round = FALSE, 103 | #' round_names, multiplication_factor = 1, 104 | #' percentage_out = 5, n_bins = 20, bin_size, save = FALSE, 105 | #' output_directory, overwrite = FALSE, verbose = TRUE) 106 | #' 107 | #' @examples 108 | #' # preparing data and directories for example 109 | #' ## directories 110 | #' tempdir <- file.path(tempdir(), "nevol_test") 111 | #' dir.create(tempdir) 112 | #' 113 | #' cvariables <- paste0(tempdir, "/variables") 114 | #' dir.create(cvariables) 115 | #' 116 | #' records <- paste0(tempdir, "/records") 117 | #' dir.create(records) 118 | #' 119 | #' m_areas <- paste0(tempdir, "/M_areas") 120 | #' dir.create(m_areas) 121 | #' 122 | #' ## data 123 | #' data("occ_list", package = "nichevol") 124 | #' 125 | #' temp <- system.file("extdata", "temp.tif", package = "nichevol") 126 | #' 127 | #' m_files <- list.files(system.file("extdata", package = "nichevol"), 128 | #' pattern = "m\\d.gpkg", full.names = TRUE) 129 | #' 130 | #' ## writing data in temporal directories 131 | #' spnames <- sapply(occ_list, function (x) as.character(x[1, 1])) 132 | #' ocnames <- paste0(records, "/", spnames, ".csv") 133 | #' 134 | #' occs <- lapply(1:length(spnames), function (x) { 135 | #' write.csv(occ_list[[x]], ocnames[x], row.names = FALSE) 136 | #' }) 137 | #' 138 | #' to_replace <- paste0(system.file("extdata", package = "nichevol"), "/") 139 | #' 140 | #' otemp <- gsub(to_replace, "", temp) 141 | #' file.copy(from = temp, to = paste0(cvariables, "/", otemp)) 142 | #' 143 | #' file.copy(from = m_files, to = paste0(m_areas, "/", spnames, ".gpkg")) 144 | #' 145 | #' # preparing tables 146 | #' tabs <- bin_tables0(M_folder = m_areas, M_format = "gpkg", occ_folder = records, 147 | #' longitude = "x", latitude = "y", var_folder = cvariables, 148 | #' var_format = "tif") 149 | 150 | 151 | bin_tables0 <- function(M_folder, M_format, occ_folder, longitude, 152 | latitude, var_folder, var_format, 153 | round = FALSE, round_names, multiplication_factor = 1, 154 | percentage_out = 5, n_bins = 20, bin_size, save = FALSE, 155 | output_directory, overwrite = FALSE, verbose = TRUE) { 156 | # checking for potential errors 157 | if (missing(M_folder)) {stop("Argument 'M_folder' is missing.")} 158 | if (missing(M_format)) {stop("Argument 'M_format' is missing.")} 159 | if (missing(occ_folder)) {stop("Argument 'occ_folder' is missing.")} 160 | if (missing(longitude)) {stop("Argument 'longitude' is missing.")} 161 | if (missing(latitude)) {stop("Argument 'latitude' is missing.")} 162 | if (missing(var_folder)) {stop("Argument 'var_folder' is missing.")} 163 | if (missing(var_format)) {stop("Argument 'var_format' is missing.")} 164 | if (!missing(bin_size)) { 165 | warning("Argument 'bin_size' is deprecated, using 'n_bins'.") 166 | } 167 | if (save == TRUE) { 168 | if (missing(output_directory)) { 169 | stop("Argument 'output_directory' is missing.") 170 | } else { 171 | if (overwrite == FALSE & dir.exists(output_directory)) { 172 | stop("'output_directory' already exists, to replace it use overwrite = TRUE.") 173 | } 174 | if (overwrite == TRUE & dir.exists(output_directory)) { 175 | unlink(x = output_directory, recursive = TRUE, force = TRUE) 176 | } 177 | } 178 | } 179 | 180 | # formats and data to start 181 | if (verbose == TRUE) { 182 | message("\nPreparing data, please wait...\n") 183 | } 184 | 185 | ## records 186 | occlist <- list.files(path = occ_folder, pattern = ".csv$", full.names = TRUE) 187 | 188 | ## M areas 189 | M_patt <- paste0(M_format, "$") 190 | mlist <- list.files(path = M_folder, pattern = M_patt, full.names = TRUE) 191 | 192 | ## species names 193 | subs <- paste0(".", M_format) 194 | spnames <- gsub(subs, "", list.files(path = M_folder, pattern = M_patt)) 195 | 196 | ## variables 197 | v_patt <- paste0(var_format, "$") 198 | variables <- terra::rast(list.files(path = var_folder, pattern = v_patt, 199 | full.names = TRUE)) 200 | 201 | ### rounding variables 202 | if (round == TRUE) { 203 | rounds <- round(variables[[round_names]] * multiplication_factor) 204 | var_names <- names(variables) 205 | noround <- var_names[!var_names %in% round_names] 206 | variables <- c(variables[[noround]], rounds) 207 | } 208 | 209 | # directory for results 210 | if (save == TRUE) {dir.create(output_directory)} 211 | if (verbose == TRUE) { 212 | message("Preparing range values and bin tables from environmental layers and species data:") 213 | } 214 | 215 | nvars <- terra::nlyr(variables) 216 | 217 | bin_tabs <- lapply(1:nvars, function(i) { 218 | # data 219 | M_range <- list() 220 | sp_range <- list() 221 | 222 | if (verbose == TRUE) { 223 | message("\n Preparing range values:") 224 | } 225 | 226 | for (j in 1:length(occlist)) { 227 | ## M 228 | if (M_format %in% c("shp", "gpkg")) { 229 | M <- terra::vect(mlist[j]) 230 | } else { 231 | M <- terra::rast(mlist[j]) 232 | } 233 | 234 | ## occurrences 235 | occ <- read.csv(occlist[j]) 236 | 237 | # processing 238 | ## get values of variables in M 239 | mvar <- terra::crop(variables[[i]], M, mask = TRUE) 240 | mval <- na.omit(mvar[][, 1]) 241 | 242 | ## distance of each absolute value to median value 243 | medians <- median(mval) 244 | df_layer <- abs(mval - medians) 245 | names(df_layer) <- mval 246 | 247 | ## limit 248 | limit <- floor((100 - percentage_out) * length(df_layer) / 100) 249 | df_layer <- sort(df_layer)[1:limit] 250 | 251 | M_range[[j]] <- range(as.numeric(names(df_layer))) 252 | 253 | ## occurrences 254 | occval <- na.omit(terra::extract(mvar, as.matrix(occ[, c(longitude, 255 | latitude)])))[, 1] 256 | sp_range[[j]] <- range(occval) 257 | 258 | if (verbose == TRUE) { 259 | message("\t", j, " of ", length(occlist), " species finished") 260 | } 261 | } 262 | 263 | # overall range 264 | M_range <- round(do.call(rbind, M_range), 2) 265 | sp_range <- round(do.call(rbind, sp_range), 2) 266 | overall_range <- range(c(c(M_range), c(sp_range))) 267 | 268 | # bin tables 269 | if (verbose == TRUE) { 270 | message("\n Preparing character tables using ranges:") 271 | } 272 | 273 | bin_size <- diff(overall_range) / n_bins 274 | 275 | bin_table <- bin_env(overall_range, M_range, sp_range, bin_size) 276 | rownames(bin_table) <- gsub("_", " ", spnames) 277 | 278 | # write table 279 | if (save == TRUE) { 280 | write.csv(bin_table, 281 | paste0(output_directory, "/", names(variables)[i], "_bin_table.csv"), 282 | row.names = TRUE) 283 | } 284 | 285 | if (verbose == TRUE) { 286 | message(i, " of ", nvars, " variables processed") 287 | } 288 | return(bin_table) 289 | }) 290 | 291 | names(bin_tabs) <- names(variables) 292 | return(bin_tabs) 293 | } 294 | -------------------------------------------------------------------------------- /R/histograms_env.R: -------------------------------------------------------------------------------- 1 | #' Histograms of environmental conditions in M and for occurrences 2 | #' 3 | #' @description histograms_env creates PDF files with histogram plots of 4 | #' environmental conditions in M, lines for the confidence limits of values in 5 | #' M, and the location of values in occurrence records. This is done using data 6 | #' read directly from a local directory, and can be applied to various species 7 | #' and multiple variables. 8 | #' 9 | #' @param M_folder (character) name of the folder containing files representing 10 | #' the accessible area (M) for all species to be analyzed. See details. 11 | #' @param M_format format of files representing the accessible area (M) for the 12 | #' species. Names of M files must match the ones for occurrence files in 13 | #' \code{occ_folder}. Format options are: "shp", "gpkg", or any of the options 14 | #' supported by \code{\link[terra]{rast}} (e.g., "tif" or "asc"). 15 | #' @param occ_folder (character) name of the folder containing csv files of 16 | #' occurrence data for all species. Names of csv files must match the ones of M 17 | #' files in \code{M_folder}. 18 | #' @param longitude (character) name of the column in occurrence files containing 19 | #' values of longitude. 20 | #' @param latitude (character) name of the column in occurrence files containing 21 | #' values of latitude. 22 | #' @param var_folder (character) name of the folder containing layers to 23 | #' represent environmental variables. 24 | #' @param var_format format of layers to represent environmental variables. 25 | #' Format options are all the ones supported by \code{\link[terra]{rast}} 26 | #' (e.g., "tif" or "asc"). 27 | #' @param CL_lines (numeric) confidence limits of environmental values in M to 28 | #' be plotted as lines in the histograms. See details. Default = c(95, 99). 29 | #' @param col colors for lines representing confidence limits. If NULL, colors 30 | #' are selected from a gray palette. Default = NULL. 31 | #' @param round (logical) whether or not to round values of one or more 32 | #' variables after multiplying them times the value in \code{multiplication_factor}. 33 | #' Default = FALSE. See details. 34 | #' @param round_names (character) names of the variables to be rounded. 35 | #' Default = NULL. If \code{round} = TRUE, names must be defined. 36 | #' @param multiplication_factor (numeric) value to be used to multiply the 37 | #' variables defined in \code{round_names}. Default = 1. 38 | #' @param save_ranges (logical) whether or not to save the values identified as 39 | #' ranges considering the whole set of values and confidence limits defined in 40 | #' \code{CL_lines}. Default = FALSE. 41 | #' @param output_directory (character) name of the folder in which results will 42 | #' be written. 43 | #' @param overwrite (logical) whether or not to overwrite existing results in 44 | #' \code{output_directory}. Default = FALSE. 45 | #' @param verbose (logical) whether messages should be printed. Default = TRUE. 46 | #' 47 | #' @details 48 | #' Coordinates in csv files in \code{occ_folder}, SpatVector-like files in 49 | #' \code{M_folder}, and raster layers in \code{var_folder} must coincide in the 50 | #' geographic projection in which they are represented. WGS84 with no planar 51 | #' projection is recommended. 52 | #' 53 | #' Accessible area (M) is understood as the geographic area that has been 54 | #' accessible for a species for relevant periods of time. Defining M is usually 55 | #' a hard task, but also a very important one, because it allows identifying 56 | #' uncertainties about the ability of a species to maintain populations under 57 | #' certain environmental conditions. For further details on this topic, see 58 | #' Barve et al. (2011) 59 | #' and Machado-Stredel et al. (2021) . 60 | #' 61 | #' Rounding variables may be useful when multiple variables are considered and 62 | #' the values of some or all of them are too small (e.g., when using principal 63 | #' components). To round specific variables arguments \code{round}, 64 | #' \code{round_names}, and \code{multiplication_factor}, must be used accordingly. 65 | #' 66 | #' @return 67 | #' A list of data.frames containing intervals of environmental values in species 68 | #' occurrences and accessible areas (M), as well as values corresponding to the 69 | #' confidence limits defined in \code{CL_lines}. A folder named as 70 | #' in \code{output_directory} containing all resulting PDF files (one per 71 | #' variable) with histograms for all species. Files (csv) of ranges found during 72 | #' the analyses will be also written in \code{output_directory} if 73 | #' \code{save_ranges} is set as TRUE. 74 | #' 75 | #' @importFrom grDevices gray.colors 76 | #' @importFrom utils write.csv read.csv 77 | #' @importFrom stats na.omit median 78 | #' @importFrom terra extract crop nlyr rast vect 79 | #' 80 | #' @export 81 | #' 82 | #' @usage 83 | #' histograms_env(M_folder, M_format, occ_folder, longitude, latitude, 84 | #' var_folder, var_format, CL_lines = c(95, 99), col = NULL, 85 | #' round = FALSE, round_names = NULL, multiplication_factor = 1, 86 | #' save_ranges = FALSE, output_directory, overwrite = FALSE, 87 | #' verbose = TRUE) 88 | #' 89 | #' @examples 90 | #' # preparing data and directories for examples 91 | #' ## directories 92 | #' tempdir <- file.path(tempdir(), "nevol_test") 93 | #' dir.create(tempdir) 94 | #' 95 | #' cvariables <- paste0(tempdir, "/variables") 96 | #' dir.create(cvariables) 97 | #' 98 | #' records <- paste0(tempdir, "/records") 99 | #' dir.create(records) 100 | #' 101 | #' m_areas <- paste0(tempdir, "/M_areas") 102 | #' dir.create(m_areas) 103 | #' 104 | #' histdir <- paste0(tempdir, "/Hists") 105 | #' 106 | #' ## data 107 | #' data("occ_list", package = "nichevol") 108 | #' 109 | #' temp <- system.file("extdata", "temp.tif", package = "nichevol") 110 | #' 111 | #' m_files <- list.files(system.file("extdata", package = "nichevol"), 112 | #' pattern = "m\\d.gpkg", full.names = TRUE) 113 | #' 114 | #' ## writing data in temporal directories 115 | #' spnames <- sapply(occ_list, function (x) as.character(x[1, 1])) 116 | #' ocnames <- paste0(records, "/", spnames, ".csv") 117 | #' 118 | #' occs <- lapply(1:length(spnames), function (x) { 119 | #' write.csv(occ_list[[x]], ocnames[x], row.names = FALSE) 120 | #' }) 121 | #' 122 | #' to_replace <- paste0(system.file("extdata", package = "nichevol"), "/") 123 | #' 124 | #' otemp <- gsub(to_replace, "", temp) 125 | #' file.copy(from = temp, to = paste0(cvariables, "/", otemp)) 126 | #' 127 | #' file.copy(from = m_files, to = paste0(m_areas, "/", spnames, ".gpkg")) 128 | #' 129 | #' # running analysis to produce plots 130 | #' hists <- histograms_env(M_folder = m_areas, M_format = "gpkg", 131 | #' occ_folder = records, longitude = "x", 132 | #' latitude = "y", var_folder = cvariables, 133 | #' var_format = "tif", output_directory = histdir) 134 | 135 | histograms_env <- function(M_folder, M_format, occ_folder, longitude, 136 | latitude, var_folder, var_format, 137 | CL_lines = c(95, 99), col = NULL, round = FALSE, 138 | round_names = NULL, multiplication_factor = 1, 139 | save_ranges = FALSE, output_directory, 140 | overwrite = FALSE, verbose = TRUE) { 141 | # checking for potential errors 142 | if (missing(M_folder)) {stop("Argument 'M_folder' is missing.")} 143 | if (missing(M_format)) {stop("Argument 'M_format' is missing.")} 144 | if (missing(occ_folder)) {stop("Argument 'occ_folder' is missing.")} 145 | if (missing(longitude)) {stop("Argument 'longitude' is missing.")} 146 | if (missing(latitude)) {stop("Argument 'latitude' is missing.")} 147 | if (missing(var_folder)) {stop("Argument 'var_folder' is missing.")} 148 | if (missing(var_format)) {stop("Argument 'var_format' is missing.")} 149 | if (missing(output_directory)) { 150 | stop("Argument 'output_directory' is missing.") 151 | } else { 152 | if (overwrite == FALSE & dir.exists(output_directory)) { 153 | stop("'output_directory' already exists, to replace it use 'overwrite' = TRUE.") 154 | } 155 | if (overwrite == TRUE & dir.exists(output_directory)) { 156 | unlink(x = output_directory, recursive = TRUE, force = TRUE) 157 | } 158 | } 159 | 160 | lcll <- length(CL_lines) 161 | if (is.null(col)) { 162 | col <- sort(gray.colors(lcll + 1), decreasing = TRUE)[1:lcll] 163 | } 164 | if (round == TRUE & is.null(round_names)) { 165 | stop("Argument 'round_names' cannot be NULL if round = TRUE.") 166 | } 167 | 168 | # formats and data to start 169 | if (verbose == TRUE) { 170 | message("\nPreparing data, please wait...\n") 171 | } 172 | 173 | ## records 174 | occlist <- list.files(path = occ_folder, pattern = ".csv$", full.names = TRUE) 175 | 176 | ## M areas 177 | M_patt <- paste0(M_format, "$") 178 | mlist <- list.files(path = M_folder, pattern = M_patt, full.names = TRUE) 179 | 180 | ## species names 181 | subs <- paste0(".", M_format) 182 | spnames <- gsub(subs, "", list.files(path = M_folder, pattern = M_patt)) 183 | 184 | ## variables 185 | v_patt <- paste0(var_format, "$") 186 | variables <- terra::rast(list.files(path = var_folder, pattern = v_patt, 187 | full.names = TRUE)) 188 | 189 | ### rounding variables 190 | if (round == TRUE) { 191 | rounds <- round(variables[[round_names]] * multiplication_factor) 192 | var_names <- names(variables) 193 | noround <- var_names[!var_names %in% round_names] 194 | variables <- c(variables[[noround]], rounds) 195 | } 196 | 197 | # directory for results 198 | dir.create(output_directory) 199 | 200 | nvars <- terra::nlyr(variables) 201 | 202 | if (verbose == TRUE) { 203 | message("Preparing environmental values and histograms from layers and species data:") 204 | } 205 | 206 | ranges <- lapply(1:nvars, function(i) { 207 | # data 208 | df_layer <- list() 209 | occ_dfs <- list() 210 | 211 | M_ranges <- list() 212 | M_limits <- list() 213 | sp_ranges <- list() 214 | y_values <- list() 215 | 216 | if (verbose == TRUE) { 217 | message("\n Preparing environmental values:") 218 | } 219 | 220 | for (j in 1:length(occlist)) { 221 | ## M 222 | if (M_format %in% c("shp", "gpkg")) { 223 | M <- terra::vect(mlist[j]) 224 | } else { 225 | M <- terra::rast(mlist[j]) 226 | } 227 | 228 | ## occurrences 229 | occ <- read.csv(occlist[j]) 230 | 231 | # processing 232 | ## get values of variables in M 233 | mvar <- terra::crop(variables[[i]], M, mask = TRUE) 234 | mval <- na.omit(mvar[][, 1]) 235 | 236 | ## distance of each absolute value to median value 237 | medians <- median(mval) 238 | df_layer[[j]] <- abs(mval - medians) 239 | names(df_layer[[j]]) <- mval 240 | 241 | occval <- na.omit(terra::extract(mvar, 242 | as.matrix(occ[, c(longitude, latitude)])))[, 1] 243 | occ_dfs[[j]] <- abs(occval - medians) 244 | names(occ_dfs[[j]]) <- occval 245 | 246 | y_values[[j]] <- c(max(table(mval)), max(table(df_layer[[j]]))) 247 | 248 | ## ranges of real values 249 | M_limit <- lapply(1:lcll, function(k) { 250 | limit <- floor((CL_lines[k]) * length(df_layer[[j]]) / 100) 251 | df_layera <- sort(df_layer[[j]])[1:limit] 252 | 253 | range(as.numeric(names(df_layera))) 254 | }) 255 | 256 | M_ranges[[j]] <- range(mval) 257 | M_limits[[j]] <- do.call(c, M_limit) 258 | sp_ranges[[j]] <- range(occval) 259 | 260 | if (verbose == TRUE) { 261 | message("\t", j, " of ", length(occlist), " species finished") 262 | } 263 | } 264 | 265 | ## ranges final values for variables 266 | limits <- do.call(rbind, M_limits) 267 | ranges <- data.frame(gsub("_", " ", spnames), do.call(rbind, sp_ranges), 268 | do.call(rbind, M_ranges), limits) 269 | colnames(ranges) <- c("Species", "Species_lower", "Species_upper", 270 | "M_lower", "M_upper", paste0("M_", 271 | rep(CL_lines, each = 2), 272 | c("_lowerCL", "_upperCL"))) 273 | 274 | if (save_ranges == TRUE) { 275 | write.csv(ranges, file = paste0(output_directory, "/Ranges_", 276 | names(variables)[i], ".csv"), 277 | row.names = FALSE) 278 | } 279 | 280 | ## frecuency of each value in M 281 | if (verbose == TRUE) { 282 | message("\n Preparing histogram plots using environmental values...") 283 | } 284 | pdf_histograms(env_data = df_layer, occ_data = occ_dfs, y_values = y_values, 285 | sp_names = spnames, variable_name = names(variables)[i], 286 | CL_lines = CL_lines, limits = limits, col = col, 287 | output_directory = output_directory) 288 | 289 | message(i, " of ", nvars, " variables processed") 290 | return(ranges) 291 | }) 292 | 293 | if (save_ranges == TRUE) { 294 | if (verbose == TRUE) { 295 | message("\ncsv files with the environmental ranges were saved in ", 296 | output_directory, "\n") 297 | } 298 | } 299 | 300 | names(ranges) <- names(variables) 301 | 302 | return(ranges) 303 | } 304 | --------------------------------------------------------------------------------