diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..157f48a Binary files /dev/null and b/.DS_Store differ diff --git a/.Rbuildignore b/.Rbuildignore index d595a43..98b1802 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -12,4 +12,3 @@ ^LICENSE\.md$ ^doc$ ^Meta$ -^CODE_OF_CONDUCT\.md$ diff --git a/.github/CODE_OF_CONDUCT.MD b/.github/CODE_OF_CONDUCT.MD deleted file mode 100644 index 7b2c995..0000000 --- a/.github/CODE_OF_CONDUCT.MD +++ /dev/null @@ -1,124 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, caste, color, religion, or sexual -identity and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall - community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or advances of - any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email address, - without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at roseth@posteo.com. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series of -actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or permanent -ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within the -community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), -version 2.1, available at -. - -Community Impact Guidelines were inspired by -[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/inclusion). - -For answers to common questions about this code of conduct, see the FAQ at -. Translations are available at . diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index bd24e45..0000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,49 +0,0 @@ -# Contributing to ASTR - -This guide outlines how to propose a change to ASTR. - -## Fixing typos - -You can fix typos, spelling mistakes, or grammatical errors in the documentation directly using the GitHub web interface, as long as the changes are made in the _source_ file. -This generally means you'll need to edit [roxygen2 comments](https://roxygen2.r-lib.org/articles/roxygen2.html) in an `.R`, not a `.Rd` file. -You can find the `.R` file that generates the `.Rd` by reading the comment in the first line. - -## Bigger changes - -If you want to make a bigger change, it's a good idea to first file an issue and make sure someone from the team agrees that it’s needed. -If you’ve found a bug, please file an issue that illustrates the bug with a minimal -[reprex](https://www.tidyverse.org/help/#reprex) (this will also help you write a unit test, if needed). - -### Pull request process - -* Fork the package and clone onto your computer. If you haven't done this before, we recommend using `usethis::create_from_github("archaeothommy/ASTR", fork = TRUE)`. - -* Install all development dependencies with `devtools::install_dev_deps()`, and then make sure the package passes R CMD check by running `devtools::check()`. - If R CMD check doesn't pass cleanly, it's a good idea to ask for help before continuing. - -* Create a Git branch for your pull request (PR). We recommend using `usethis::pr_init("brief-description-of-change")`. - -* Make your changes, commit to git, and then create a PR by running `usethis::pr_push()`, and following the prompts in your browser. - The title of your PR should briefly describe the change. - The body of your PR should contain `Fixes #issue-number`. - -* For user-facing changes, add a bullet to the top of `NEWS.md` (i.e. just below the first header). Follow the style described in . - -### Code style - -* New code should follow the tidyverse [style guide](https://style.tidyverse.org) with some minor modifications. - You can use the [styler](https://CRAN.R-project.org/package=styler) package to apply these styles. You should use the [lintr](https://CRAN.R-project.org/package=lintr) package to check that your code adheres to the code style. - Please don't restyle code that has nothing to do with your PR. - -* We use [roxygen2](https://cran.r-project.org/package=roxygen2), with [Markdown syntax](https://cran.r-project.org/web/packages/roxygen2/vignettes/rd-formatting.html), for documentation. - -* We use [testthat](https://cran.r-project.org/package=testthat) for unit tests. - Contributions with test cases included are easier to accept. - -## Code of Conduct - -Please note that ASTR is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By contributing to this project you agree to abide by its terms. - -## Acknowledgement - -This contributor guide was is adopted from the [contributor guide of readr](https://github.com/tidyverse/readr/blob/main/.github/CONTRIBUTING.md). diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index aeae016..2a95163 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -30,7 +30,7 @@ jobs: R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 5fdd01f..e87d167 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -15,7 +15,7 @@ jobs: env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-r@v2 with: diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 2b29c92..bfc9f4d 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -23,7 +23,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 diff --git a/.github/workflows/pr-commands.yaml b/.github/workflows/pr-commands.yaml index 7b9913e..2edd93f 100644 --- a/.github/workflows/pr-commands.yaml +++ b/.github/workflows/pr-commands.yaml @@ -18,7 +18,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: r-lib/actions/pr-fetch@v2 with: @@ -57,7 +57,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: r-lib/actions/pr-fetch@v2 with: diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 57023a5..0ab748d 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -16,7 +16,7 @@ jobs: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-r@v2 with: @@ -56,7 +56,7 @@ jobs: - name: Upload test results if: failure() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v4 with: name: coverage-test-failures path: ${{ runner.temp }}/package diff --git a/.gitignore b/.gitignore index d20bf51..130a84f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,3 @@ docs inst/doc /doc/ /Meta/ - diff --git a/.lintr b/.lintr index 16edc84..4390955 100644 --- a/.lintr +++ b/.lintr @@ -3,6 +3,5 @@ linters: linters_with_defaults( commented_code_linter = NULL, absolute_path_linter(lax = TRUE), return_linter = NULL, - object_name_linter = NULL, - pipe_consistency_linter(pipe = "%>%") + object_name_linter = NULL ) diff --git a/DESCRIPTION b/DESCRIPTION index b582709..3b9cf79 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,39 +1,33 @@ Package: ASTR -Title: Archaeometric Standards and Tools in R +Title: What the Package Does (One Line, Title Case) Version: 0.0.0.9000 -URL: https://archaeothommy.github.io/ASTR/, https://github.com/archaeothommy/ASTR -BugReports: https://github.com/archaeothommy/ASTR/issues +URL: https://example.com Authors@R: c( - person("Thomas", "Rose", comment = c(ORCID = "0000-0002-8186-3566"), role = c("cre", "aut"), email = "roseth@posteo.com"), - person("Mathias Ayine", "Abagna", role = "aut"), - person("Andrea", "Acevedo Mejia", comment = c(ORCID = "0009-0002-7441-1737"), role = "aut"), - person("Gilberto", "Artioli", comment = c(ORCID = "0000-0002-8693-7392"), role = "aut"), - person("María Florencia", "Becerra", comment = c(ORCID = "0000-0001-6302-7452"), role = "aut"), - person("Adam Kevin", "Benfer", comment = c(ORCID = "0009-0004-1253-1068"), role = "aut"), - person("Lisa", "Bellemère", role = "aut"), - person("Thomas Edward", "Birch", comment = c(ORCID = "0000-0002-4568-9767"), role = "aut"), - person("Karan", "Desai", comment = c(ORCID = "0009-0008-8224-8435"), role = "aut"), - person("Paolo", "d'Imporzano", role = "aut"), - person("Tzilla", "Eshel", comment = c(ORCID = "0000-0003-0976-0877"), role = "aut"), - person("Valerio", "Gentile", comment = c(ORCID = "0000-0003-4402-2730"), role = "aut"), - person("Sabine", "Klein", comment = c(ORCID = "0000-0002-3939-4428"), role = "aut"), - person("Catherine", "Klesner", comment = c(ORCID = "0000-0002-2264-9383"), role = "aut"), - person("Kathryn", "Murphy", comment = c(ORCID = "0000-0002-5906-7299"), role = "aut"), - person("Ben", "Marwick", comment = c(ORCID = "0000-0001-7879-4531"), role = "aut"), - person("Stephen", "Merkel", comment = c(ORCID = "0000-0001-8730-6923"), role = "aut"), - person("Marco Daniele", "Pelizzari", role = "aut"), - person("Alexandra", "Rodler", comment = c(ORCID = "0000-0002-4087-7160"), role = "aut"), - person("Benjamin", "Sabatini", comment = c(ORCID = "0000-0002-4199-0253"), role = "aut"), - person("Clemens", "Schmid", comment = c(ORCID = "0000-0003-3448-5715"), role = "aut"), - person("Berber", "van der Meulen-van der Veen", comment = c(ORCID = "0000-0001-5297-0269"), role = "aut"), - person("Chen", "Wang", comment = c(ORCID = "0009-0007-1851-2388"), role = "aut"), - person("Katrin Julia", "Westner", comment = c(ORCID = "0000-0001-5529-1165"), role = "aut"), - person("Deutsche Forschungsgemeinschaft", comment = c(ROR = "018mejw64"), role = c("fnd")), - person("Lorentz Center", comment = c(ROR = "00d503m77"), role = c("fnd")) + person("Rose", "Thomas", comment = c(ORCID = "0000-0002-8186-3566"), role = c("cre", "aut"), email = "roseth@posteo.com"), + person("Acevedo Mejia", "Andrea", comment = c(ORCID = "0009-0002-7441-1737"), role = "aut"), + person("Artioli", "Gilberto", comment = c(ORCID = "0000-0002-8693-7392"), role = "aut"), + person("Becerra", "María Florencia", comment = c(ORCID = "0000-0001-6302-7452"), role = "aut"), + person("Benfer", "Adam Kevin", comment = c(ORCID = "0009-0004-1253-1068"), role = "aut"), + person("Bellemère", "Lisa", role = "aut"), + person("Birch", "Thomas Edward", comment = c(ORCID = "0000-0002-4568-9767"), role = "aut"), + person("Desai", "Karan", comment = c(ORCID = "0009-0008-8224-8435"), role = "aut"), + person("d'Imporzano", "Paolo", role = "aut"), + person("Eshel", "Tzilla", comment = c(ORCID = "0000-0003-0976-0877"), role = "aut"), + person("Gentile", "Valerio", comment = c(ORCID = "0000-0003-4402-2730"), role = "aut"), + person("Klein", "Sabine", comment = c(ORCID = "0000-0002-3939-4428"), role = "aut"), + person("Klesner", "Catherine", comment = c(ORCID = "0000-0002-2264-9383"), role = "aut"), + person("Murphy", "Kathryn", comment = c(ORCID = "0000-0002-5906-7299"), role = "aut"), + person("Marwick", "Ben", comment = c(ORCID = "0000-0001-7879-4531"), role = "aut"), + person("Merkel", "Stephen", comment = c(ORCID = "0000-0001-8730-6923"), role = "aut"), + person("Pelizzari", "Marco Daniele", role = "aut"), + person("Rodler", "Alexandra", comment = c(ORCID = "0000-0002-4087-7160"), role = "aut"), + person("Sabatini", "Benjamin", comment = c(ORCID = "0000-0002-4199-0253"), role = "aut"), + person("Schmid", "Clemens", comment = c(ORCID = "0000-0003-3448-5715"), role = "aut"), + person("van der Meulen-van der Veen", "Berber", comment = c(ORCID = "0000-0001-5297-0269"), role = "aut"), + person("Wang", "Chen", comment = c(ORCID = "0009-0007-1851-2388"), role = "aut"), + person("Westner", "Katrin Julia", comment = c(ORCID = "0000-0001-5529-1165"), role = "aut") ) -Description: ASTR defines and implements a community reporting standard for archaeometric datasets. - It also provides easy-to-use functions for common plots, statistical analyses, data processing - and transformation workflows in archaeometry. +Description: What the package does (one paragraph). License: MIT + file LICENSE Encoding: UTF-8 Roxygen: list(markdown = TRUE) @@ -46,7 +40,7 @@ Suggests: vdiffr Imports: checkmate, - dplyr (>= 1.2.0), + dplyr, geometry, magrittr, purrr, @@ -57,7 +51,7 @@ Imports: tibble, tidyselect, units, - vctrs, + robCompositions, ggplot2, ks, units, diff --git a/NAMESPACE b/NAMESPACE index 79cf8be..4a94c86 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,55 +1,37 @@ # Generated by roxygen2: do not edit by hand -S3method(dplyr::dplyr_col_modify,ASTR) -S3method(dplyr::dplyr_reconstruct,ASTR) -S3method(dplyr::dplyr_row_slice,ASTR) -S3method(format,ASTR) -S3method(get_analytical_columns,ASTR) -S3method(get_concentration_columns,ASTR) -S3method(get_contextual_columns,ASTR) -S3method(get_element_columns,ASTR) -S3method(get_isotope_columns,ASTR) -S3method(get_ratio_columns,ASTR) -S3method(get_unit_columns,ASTR) -S3method(print,ASTR) -S3method(remove_units,ASTR) -S3method(validate,ASTR) +S3method(dplyr::dplyr_col_modify,archchem) +S3method(dplyr::dplyr_reconstruct,archchem) +S3method(dplyr::dplyr_row_slice,archchem) +S3method(format,archchem) +S3method(get_analytical_columns,archchem) +S3method(get_concentration_columns,archchem) +S3method(get_contextual_columns,archchem) +S3method(get_element_columns,archchem) +S3method(get_isotope_columns,archchem) +S3method(get_ratio_columns,archchem) +S3method(print,archchem) +S3method(remove_units,archchem) +S3method(validate,archchem) S3method(validate,default) export(albarede_juteau_1984) -export(as_ASTR) -export(at_to_wt) -export(copper_alloy_bb) -export(copper_alloy_pollard) +export(as_archchem) export(copper_group_bray) export(cumming_richards_1975) -export(element_to_oxide) export(geom_kde2d) -export(geom_sk_labels) -export(geom_sk_lines) export(get_analytical_columns) export(get_concentration_columns) export(get_contextual_columns) export(get_element_columns) export(get_isotope_columns) export(get_ratio_columns) -export(get_unit_columns) -export(oxide_to_element) export(pb_iso_age_model) export(pointcloud_distribution) -export(read_ASTR) +export(read_archchem) export(remove_units) export(stacey_kramers_1975) export(unify_concentration_unit) export(validate) -export(wt_to_at) -import(ggplot2) -importFrom(dplyr,bind_rows) -importFrom(dplyr,c_across) -importFrom(dplyr,filter) -importFrom(dplyr,mutate) -importFrom(dplyr,rowwise) -importFrom(dplyr,select) -importFrom(dplyr,ungroup) importFrom(geometry,convhulln) importFrom(geometry,inhulln) importFrom(ggplot2,GeomPoint) @@ -63,8 +45,6 @@ importFrom(ks,contourLevels) importFrom(ks,kde) importFrom(magrittr,"%>%") importFrom(rdist,cdist) -importFrom(rlang,":=") importFrom(rlang,.data) importFrom(stats,aggregate) importFrom(stats,as.formula) -importFrom(tidyselect,starts_with) diff --git a/NEWS.md b/NEWS.md index f279ee8..c964005 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,3 @@ # ASTR (development version) -* Implementation of ASTR schema. -* Support and conversions for geochemical non-SI units: *at%*, *wt%* (elements and oxides) +* Initial CRAN submission. diff --git a/R/ASTR_PbIso_AgeModels.R b/R/ASTR_PbIso_AgeModels.R index c965829..227227d 100644 --- a/R/ASTR_PbIso_AgeModels.R +++ b/R/ASTR_PbIso_AgeModels.R @@ -5,25 +5,33 @@ #' *References*). [pb_iso_age_model()] provides a wrapper for them and allows #' to calculate all age models simultaneously. #' +#' The implemented age models are: +#' * Stacey & Kramers (1975): [stacey_kramers_1975()] +#' * Cumming & Richards (1975): [cumming_richards_1975()] +#' * Albarède & Juteau (1984): [albarede_juteau_1984()] +#' +#' The used model is indicated in the column names of the output by the initials +#' of the author's last names and the publication year (e. g.`SK75` for Stacey +#' & Kramers 1975). +#' #' See the references for the respective publications of the age models. The #' function for the age model of Albarède & Juteau (1984) is based on the -#' MATLAB-script of F. Albarède (version 2020-11-06). The age model published in -#' Albarède et al. (2012) should not be used according to F. Albarède and is +#' MATLAB-script of F. Albarède (version 2020-11-06). The age model published +#' in Albarède et al. (2012) should not be used according to F. Albarède and is #' therefore not implemented. Instead, he recommends to use the age model #' published in Albarède & Juteau (1984). #' -#' The ratio of 208Pb/204Pb is not necessary for [cumming_richards_1975]. The -#' function takes it as argument only to be consistent with the input of the +#' The ratio of 208Pb/204Pb is not necessary for [cumming_richards_1975]. +#' The function takes it as argument only to be consistent with the input of the #' other age model functions. If provided, it will be ignored. #' -#' @param df The data frame from which the age model parameters should be -#' calculated. +#' @param df The data frame from which the age model should be calculated. #' @param ratio_206_204 Name of the column with the 206Pb/204Pb ratio as -#' character string. Default is `206Pb/204Pb`. +#' character string. Default is `206Pb/204Pb`. #' @param ratio_207_204 Name of the column with the 207Pb/204Pb ratio as -#' character string. Default is `207Pb/204Pb`. +#' character string. Default is `207Pb/204Pb`. #' @param ratio_208_204 Name of the column with the 208Pb/204Pb ratio as -#' character string. Default is `208Pb/204Pb`. +#' character string. Default is `208Pb/204Pb`. #' @param model Character string with the abbreviation of the model to #' calculate: #' * `SK75` for Stacey & Kramers (1975) @@ -31,37 +39,29 @@ #' * `AJ84` for Albarède & Juteau (1984) #' * `all` for all models at once #' -#' @return If `df` is an [ASTR object][ASTR], the output is an object of the -#' same type including the ID column, the contextual columns, the lead isotope -#' ratios used for calculation of the age model parameters, and the calculated -#' age model parameters. In all other cases, the data frame provided as input -#' with columns added for the calculated age model parameters. -#' -#' The used age model is indicated in the column names of the output by the -#' abbreviations for the models given above. They represent the initials of -#' the author's last names and the publication year (e. g. `SK75` for Stacey & -#' Kramers 1975). +#' @return The data frame provided as input with columns added for the model +#' age, mu, and kappa value(s) of the respective age models. The used model is +#' indicated in the column names of the output by the abbreviations given above. #' #' @export #' #' @references Albarède, F. and Juteau, M. (1984) Unscrambling the lead model -#' ages. Geochimica et Cosmochimica Acta 48(1), pp. 207-212. -#' . +#' ages. Geochimica et Cosmochimica Acta 48(1), pp. 207–212. +#' . #' -#' Albarède, F., Desaulty, A.-M. and Blichert-Toft, J. (2012) A geological -#' perspective on the use of Pb isotopes in Archaeometry. Archaeometry 54, pp. -#' 853–867. . +#' Albarède, F., Desaulty, A.-M. and Blichert-Toft, J. (2012) A geological +#' perspective on the use of Pb isotopes in Archaeometry. Archaeometry 54, pp. +#' 853–867. . #' -#' Cumming, G.L. and Richards, J.R. (1975) Ore lead isotope ratios in a -#' continuously changing earth. Earth and Planetary Science Letters 28(2), pp. -#' 155–171. . +#' Cumming, G.L. and Richards, J.R. (1975) Ore lead isotope ratios in a +#' continuously changing earth. Earth and Planetary Science Letters 28(2), pp. +#' 155–171. . #' -#' Stacey, J.S. and Kramers, J.D. (1975) Approximation of terrestrial lead -#' isotope evolution by a two-stage model. Earth and Planetary Science Letters -#' 26(2), pp. 207–221. . +#' Stacey, J.S. and Kramers, J.D. (1975) Approximation of terrestrial lead +#' isotope evolution by a two-stage model. Earth and Planetary Science Letters +#' 26(2), pp. 207–221. % round(3) - if (inherits(df, "ASTR")) { - df_out <- cbind(get_contextual_columns(df), df[c(ratio_206_204, ratio_207_204, ratio_208_204)], result) - df_out <- suppressWarnings( - as_ASTR( - df_out, - context = c(colnames(get_contextual_columns(df))[-1], colnames(result)) - ) - ) - } else { - df_out <- cbind(df, result) - } + result <- cbind(df, result) - return(df_out) + result } @@ -238,19 +214,9 @@ cumming_richards_1975 <- function(df, result <- data.frame("model_age_CR75" = model_age * 10^-6, "mu_CR75" = mu, "kappa_CR75" = kappa) %>% round(3) - if (inherits(df, "ASTR")) { - df_out <- cbind(get_contextual_columns(df), df[c(ratio_206_204, ratio_207_204, ratio_208_204)], result) - df_out <- suppressWarnings( - as_ASTR( - df_out, - context = c(colnames(get_contextual_columns(df))[-1], colnames(result)) - ) - ) - } else { - df_out <- cbind(df, result) - } + result <- cbind(df, result) - return(df_out) + result } #' @rdname age_models @@ -305,17 +271,7 @@ albarede_juteau_1984 <- function(df, result <- data.frame("model_age_AJ84" = roots[1, ] * 10^-6, "mu_AJ84" = roots[2, ], "kappa_AJ84" = kappa) %>% round(3) - if (inherits(df, "ASTR")) { - df_out <- cbind(get_contextual_columns(df), df[c(ratio_206_204, ratio_207_204, ratio_208_204)], result) - df_out <- suppressWarnings( - as_ASTR( - df_out, - context = c(colnames(get_contextual_columns(df))[-1], colnames(result)) - ) - ) - } else { - df_out <- cbind(df, result) - } + result <- cbind(df, result) - return(df_out) + result } diff --git a/R/ASTR_colname_parser.R b/R/ASTR_colname_parser.R deleted file mode 100644 index 0c9a1c6..0000000 --- a/R/ASTR_colname_parser.R +++ /dev/null @@ -1,392 +0,0 @@ -#### column type constructor mechanism #### - -# define the correct constructor function for an ASTR column -# based on some clever parsing of the column name -# SI-unit column types are defined with the units package -# https://cran.r-project.org/web/packages/units/index.html -# (so the udunits library) - -# 1. evaluate column names -parse_colnames <- function(x, context, drop_columns) { - column_table <- purrr::imap_dfr( - colnames(x), - function(colname, idx) { - # use while for hacky switch statement - while (TRUE) { - # ID column - if (colname == "ID") { - return( - tibble::tibble( - drop = FALSE, - idx, - colname, - consider_bdl = FALSE, - type = "as input", - unit = "none", - class = list("ASTR_id"), - ) - ) - break - } - # contextual columns - if (idx %in% context || colname %in% context) { - return( - tibble::tibble( - drop = FALSE, - idx, - colname, - consider_bdl = FALSE, - type = "guess", - unit = "none", - class = list("ASTR_context") - ) - ) - break - } - # error columns - if (is_err_percent(colname)) { # check for percent err must be first - return( - tibble::tibble( - drop = FALSE, - idx, - colname, - consider_bdl = TRUE, - type = "numeric", - unit = "%", - class = list("ASTR_error"), - ) - ) - break - } - if (is_err_abs(colname)) { - return( - tibble::tibble( - drop = FALSE, - idx, - colname, - consider_bdl = TRUE, - type = "numeric", - unit = "from main field", - class = list("ASTR_error") - ) - ) - break - } - # ratios - if (is_isotope_ratio(colname)) { - return( - tibble::tibble( - drop = FALSE, - idx, - colname, - consider_bdl = FALSE, - type = "numeric", - unit = "none", - class = list(c("ASTR_isotope", "ASTR_ratio")), - ) - ) - break - } - if (is_isotope_delta_epsilon(colname)) { - return( - tibble::tibble( - drop = FALSE, - idx, - colname, - consider_bdl = FALSE, - type = "numeric", - unit = "none", - class = list(c("ASTR_isotope", "ASTR_ratio")) - ) - ) - break - } - if (is_elemental_ratio(colname)) { - return( - tibble::tibble( - drop = FALSE, - idx, - colname, - consider_bdl = FALSE, - type = "numeric", - unit = "none", - class = list(c("ASTR_element", "ASTR_ratio")) - ) - ) - break - } - # concentrations - if (is_concentration(colname)) { - unit_from_name <- extract_unit_string(colname) - # handle relative units and special cases - unit_from_name <- dplyr::recode_values( - unit_from_name, - c("at%", "atP") ~ "atP", - c("wt%", "wtP", - "w/w%", "m/m%", "%w/w", "%m/m", - "(w/w)%", "(m/m)%", "%(w/w)", "%(m/m)", - "pph", "pph(m/m)", "pph(w/w)" - ) ~ "wtP", - c("%w/v", "%m/v", "%(w/v)", "%(m/v)", - "w/v%", "m/v%", "(w/v)%", "(m/v)%", - "pph(m/v)" - ) ~ "0.01 g/L", - c("%v/v", "v/v%", "%(v/v)", "(v/v)%", "pph(v/v)") ~ "0.01 L/L", - c("ppm(w/w)", "ppm(m/m)", "ppm") ~ "mg/kg", - c("ppm(m/v)") ~ "mg/L", - c("ppm(v/v)") ~ "ml/L", - c("ppb(m/m)", "ppb(w/w)", "ppb") ~ "ng/g", - c("ppb(m/v)", "ppb(w/v)") ~ "ng/mL", - c("ppb(v/v)") ~ "nl/mL", - c("ppt(m/m)", "ppt(w/w)", "ppt") ~ "ng/kg", - c("ppt(m/v)", "ppt(w/v)") ~ "ng/L", - c("ppt(v/v)") ~ "nl/L", - c("ppq(m/m)", "ppq(w/w)", "ppq") ~ "pg/kg", - c("ppq(m/v)", "ppq(w/v)") ~ "pg/L", - c("ppq(v/v)") ~ "pl/L", - c("cps") ~ "count/s", - default = unit_from_name - ) - return( - tibble::tibble( - drop = FALSE, - idx, - colname, - consider_bdl = TRUE, - type = "numeric", - unit = unit_from_name, - class = list("ASTR_concentration"), - ) - ) - break - } - # handle everything not recognized by the parser: - m <- paste0( - "Column name \"", - colname, - "\" could not be parsed. ", - "Either analytical columns do not conform to ASTR conventions or ", - "contextual columns are not specified as such." - ) - warning(m) - if (drop_columns) { - return( - tibble::tibble( - drop = TRUE, - idx, - colname, - unit = "none" - ) - ) - } else { - stop(m) - } - } - } - ) - # get units for columns that depend on a main column, - # so overwrite unit "from main field" with the unit of - # said main field - is_dependent <- column_table$unit == "from main field" - dependent_cols <- column_table[is_dependent, ] - dependent_bases <- remove_suffix(dependent_cols$colname) - independent_cols <- column_table[!is_dependent, ] - independent_bases <- remove_suffix(independent_cols$colname) - for (i in seq_along(dependent_bases)) { - j <- which(dependent_bases[i] == independent_bases) - if (length(j) != 1) { - stop("Column ", dependent_cols$colname[i], " cannot be uniquely matched to a non-error column.") - } else { - column_table[is_dependent, ]$unit[i] <- independent_cols$unit[j] - } - } - return(column_table) -} - -# 2. build constructor functions -build_constructors <- function( - column_table, - bdl, bdl_strategy, - guess_context_type, na -) { - purrr::pmap( - column_table, function(drop, idx, colname, consider_bdl, type, unit, class) { - # delete fields that should be dropped (NULL-constructor) - if (drop) { - return( - function(x) { - NULL - } - ) - } - # assemble normal constructor function based on column properties - return( - function(x) { - # bdl - if (consider_bdl) { - x <- apply_bdl_strategy(x, colname, bdl, bdl_strategy) - } - # type - if (type == "numeric") { - x <- as_numeric_info(x, colname) - } else if (type == "guess" && guess_context_type && is.character(x)) { - x <- readr::parse_guess(x, na = na) - } - # unit - if (unit != "none" && unit != "from main field") { - x <- units::set_units(x, value = unit, mode = "standard") - } - # class - x <- add_ASTR_class(x, class) - return(x) - } - ) - } - ) -} - -add_ASTR_class <- function(x, class) { - attr(x, "ASTR_class") <- class - return(x) -} - -as_numeric_info <- function(x, colname) { - withCallingHandlers( - y <- as.numeric(x), - warning = function(w) { - message <- conditionMessage(w) - warning( - paste0( - "Issue when transforming column \"", colname, "\" to numeric values: " - ), - message, - call. = FALSE - ) - tryInvokeRestart("muffleWarning") - } - ) - return(y) -} - -# colname only an argument in case we want to implement more specific handling -# eventually -apply_bdl_strategy <- function(x, colname, bdl, bdl_strategy) { - bdl_values <- which(grepl(paste(bdl, collapse = "|"), x, perl = FALSE)) - x[bdl_values] <- bdl_strategy() - return(x) -} - -#### regex validators #### - -is_err_percent <- function(colname) { - grepl(err_percent(), colname, perl = TRUE) -} -is_err_abs <- function(colname) { - grepl(err_abs(), colname, perl = TRUE) -} -is_isotope_ratio <- function(colname) { - grepl(isotope_ratio(), colname, perl = TRUE) -} -is_isotope_delta_epsilon <- function(colname) { - grepl(isotope_delta_epsilon(), colname, perl = TRUE) -} -is_elemental_ratio <- function(colname) { - grepl(elemental_ratio(), colname, perl = TRUE) -} -is_concentration <- function(colname) { - grepl(concentration(), colname, perl = TRUE) -} -extract_unit_string <- function(colname) { - pos <- regexpr("(?<=_).*", colname, perl = TRUE) - regmatches(colname, pos) -} -extract_delta_epsilon_string <- function(colname) { - substr(colname, 1, 1) -} - -#### regex patterns #### - -# collate vectors to string with | to indicate OR in regex -isotopes_list <- function() { - paste0(isotopes_data, collapse = "|") -} -elements_list <- function() { - paste0(elements_data, collapse = "|") -} -oxides_list <- function() { - all_oxide_like_states <- c(oxides_data, special_oxide_states) - paste0(all_oxide_like_states, collapse = "|") -} -ox_elem_list <- function() paste0(oxides_list(), "|", elements_list()) -ox_elem_iso_list <- function() paste0(ox_elem_list(), "|", isotopes_list()) - -# special_type_list <- function() { -# paste0(c( -# "wt%", "at%", "w/w%" -# #"ppm", "ppb", "ppt", "%", , -# #"\u2030" # for the per-mille symbol -# ), collapse = "|") -# } - -# define regex pattern for isotope ratio: -# any isotope followed by a / and another isotope, e.g. 206Pb/204Pb -isotope_ratio <- function() { - paste0("(", isotopes_list(), ")/(", isotopes_list(), ")") -} - -# define regex pattern for delta and epsilon notation: -# letter d OR e followed by any isotope -isotope_delta_epsilon <- function() { - paste0( - "(", paste0(c("d", "e"), collapse = "|"), - ")(", isotopes_list(), ")" - ) -} - -# error states -err_percent <- function() { - paste0(c( - err_2sd_percent(), err_sd_percent() - ), collapse = "|") -} -err_2sd_percent <- function() "\\_err2SD%" -err_sd_percent <- function() "\\_errSD%" - -err_abs <- function() { - paste0(c( - err_2sd(), err_sd(), - err_2se(), err_se() - ), collapse = "|") -} -err_2sd <- function() "\\_err2SD" -err_sd <- function() "\\_errSD" -err_2se <- function() "\\_err2SE" -err_se <- function() "\\_errSE" - -# define regex pattern for element ratios: -# any combination of two elements or oxides connected by + , - or / that may or -# may not be enclosed in parentheses followed by a / and any combination of two -# elements or oxides connected by +, -, or / that may or may not be enclosed in -# parentheses, e.g. Sb/As, SiO2/Feo, (Al2O3+SiO2)/(K2O-Na20), (Feo/Mno)/(SiO2) -elemental_ratio <- function() { - paste0( - "\\(?(", ox_elem_list(), ")([\\+-/](", - ox_elem_list(), "))?\\)?/\\(?(", - ox_elem_list(), ")([\\+-/](", - ox_elem_list(), "))?\\)?" - ) -} - -# define regex pattern for concentrations: -# any combination of one or more elements, isotopes, or oxides connected by -# + or - and followed by an underscore that may or may be enclosed in -# parentheses, e.g. Sb_, Feo+SiO2_, (Al2O3+SiO2)_ -# The underscore enforces that concentrations always have a unit and prevents -# partial matching in elemental ratios -concentration <- function() { - paste0( - "^\\(?(", - ox_elem_iso_list(), ")(?!/)((\\+|-)(", - ox_elem_iso_list(), "))*\\)?_" - ) -} diff --git a/R/ASTR_column_select.R b/R/ASTR_column_select.R deleted file mode 100644 index f9aac12..0000000 --- a/R/ASTR_column_select.R +++ /dev/null @@ -1,112 +0,0 @@ -# functions to select sets of columns for ASTR tables - -is_ASTR_class <- function(x, classes) { - any(attr(x, "ASTR_class") %in% classes) -} - -get_cols_with_ac_class <- function(x, classes) { - dplyr::select(x, tidyselect::where( - function(y) { - is_ASTR_class(y, classes) - } - )) -} - -get_cols_without_ac_class <- function(x, classes) { - dplyr::select(x, tidyselect::where( - function(y) { - !is_ASTR_class(y, classes) - } - )) -} - -#' @rdname ASTR -#' @export -get_contextual_columns <- function(x, ...) { - UseMethod("get_contextual_columns") -} -#' @export -get_contextual_columns.ASTR <- function(x, ...) { - get_cols_with_ac_class(x, c("ASTR_id", "ASTR_context")) -} - -#' @rdname ASTR -#' @export -get_analytical_columns <- function(x, ...) { - UseMethod("get_analytical_columns") -} -#' @export -get_analytical_columns.ASTR <- function(x, ...) { - get_cols_without_ac_class(x, "ASTR_context") -} - -#' @rdname ASTR -#' @export -get_isotope_columns <- function(x, ...) { - UseMethod("get_isotope_columns") -} -#' @export -get_isotope_columns.ASTR <- function(x, ...) { - get_cols_with_ac_class(x, c("ASTR_id", "ASTR_isotope")) -} - -#' @rdname ASTR -#' @export -get_element_columns <- function(x, ...) { - UseMethod("get_element_columns") -} -#' @export -get_element_columns.ASTR <- function(x, ...) { - get_cols_with_ac_class(x, c("ASTR_id", "ASTR_element")) -} - -#' @rdname ASTR -#' @export -get_ratio_columns <- function(x, ...) { - UseMethod("get_ratio_columns") -} -#' @export -get_ratio_columns.ASTR <- function(x, ...) { - get_cols_with_ac_class(x, c("ASTR_id", "ASTR_ratio")) -} - -#' @rdname ASTR -#' @export -get_concentration_columns <- function(x, ...) { - UseMethod("get_concentration_columns") -} -#' @export -get_concentration_columns.ASTR <- function(x, ...) { - get_cols_with_ac_class(x, c("ASTR_id", "ASTR_concentration")) -} - -get_cols_with_unit <- function(x, units) { - - units <- sapply(units, function(unit) transform_notation(unit)) - - df <- dplyr::select(x, tidyselect::where( - function(y) { - inherits(y, "units") - } - )) %>% - dplyr::select(tidyselect::where( - function(y) { - units::deparse_unit(y) %in% units - } - )) - - df <- cbind(x["ID"], df) - df <- preserve_ASTR_attrs(df, x) - df -} - -#' @rdname ASTR -#' @param units A character vector with units to be selected. -#' @export -get_unit_columns <- function(x, units, ...) { - UseMethod("get_unit_columns") -} -#' @export -get_unit_columns.ASTR <- function(x, units, ...) { - get_cols_with_unit(x, units) -} diff --git a/R/ASTR_conversion_atomic.R b/R/ASTR_conversion_atomic.R deleted file mode 100644 index 68a253c..0000000 --- a/R/ASTR_conversion_atomic.R +++ /dev/null @@ -1,165 +0,0 @@ -#' Conversion between wt% and at% -#' -#' Convert chemical compositions between weight percent (*wt%*) and atomic -#' percent (*at%*). Results are always normalised to 100%. -#' -#' The column names of the elements to be converted must be equivalent to their -#' chemical symbols. The functions convert only values in *wt%* or *at%*. If -#' concentrations are present in another concentration unit (e.g. *ppm*, -#' *µg/kg*), run [`unify_concentration_unit(df, -#' "wtP")`][unify_concentration_unit()] first to convert all concentrations to -#' *wt%*. If `df` is an [`ASTR object`][ASTR], only elements will be converted -#' to *at%*, and oxides in *wt%* are automatically excluded. To convert oxides -#' into *at%* and vice versa, convert to *wt%* first. -#' -#' @param df Data frame with compositional data. -#' @param elements Character vector with the chemical symbols of the elements -#' that should be converted. Default are all columns in an [`ASTR -#' object`][ASTR] in the unit to be converted. See *Details* for further -#' information -#' @param drop If `TRUE`, the default, columns with unconverted values are -#' dropped. If false, columns with unconverted values are kept and a suffix -#' added to the column names of the converted values. -#' * `_atP` for conversions to atomic percent -#' * `_wtP` for conversions to weight percent. -#' -#' @return The original data frame with the converted concentrations normalised -#' to 100%. -#' -#' @export -#' @name atomic_conversion -#' -#' @examples -#' -#' library(magrittr) -#' -#' # Convert weight percent to atomic percent and to weight percent -#' df <- data.frame(ID = 1, Si = 46.74, O = 53.26) # SiO2 composition -#' at <- wt_to_at(df, elements = c("Si", "O")) -#' at_to_wt(at, elements = c("Si", "O")) -#' -#' # preserve columns with unconverted values -#' wt_to_at(df, elements = c("Si", "O"), drop = FALSE) -#' -#' # Use with ASTR objects -#' # Create ASTR object -#' test_file <- system.file("extdata", "test_data_input_good.csv", package = "ASTR") -#' arch <- read_ASTR(test_file, id_column = "Sample", context = 1:7) -#' -#' # Convert columns in wt% to at% -#' arch_atP <- wt_to_at(arch) -#' -#' # To convert all applicable concentrations, unify units first: -#' arch_all <- unify_concentration_unit(arch, "wtP") %>% -#' wt_to_at() -#' -#' # Elements already present in the converted unit are ignored. -#' rowSums(get_unit_columns(arch_all, "atP")[-1], na.rm = TRUE) > 100 -#' -wt_to_at <- function(df, elements = colnames(get_unit_columns(df, "wtP")), drop = TRUE) { - - # Validate inputs - checkmate::assert_data_frame(df) - - # if ASTR object, include only columns with elements - if (inherits(df, "ASTR")) { - elements <- intersect(elements, elements_data) - } - - # Check if all requested elements are in df - missing_from_df <- setdiff(elements, names(df)) - if (length(missing_from_df) > 0) { - stop("The following elements are not present in df: ", - paste(missing_from_df, collapse = ", ")) - } - - # Check if all elements are valid chemical elements - invalid_elements <- setdiff(elements, elements_data) - if (length(invalid_elements) > 0) { - stop("The following elements are not valid chemical elements: ", - paste(invalid_elements, collapse = ", ")) - } - - moles <- t(t(df[elements]) / conversion_oxides$AtomicWeight[match(elements, conversion_oxides$Element)]) - - total <- rowSums(moles, na.rm = TRUE) - total[total == 0] <- NA_real_ - at_percent <- moles / total * 100 - - df_old <- df - - if (drop) { - # Replace original columns with atomic percent - df[elements] <- at_percent - } else { - # Add new columns with suffix - colnames(at_percent) <- paste0(elements, "_atP") - df[colnames(at_percent)] <- at_percent - } - - if (inherits(df_old, "ASTR")) { - df <- preserve_ASTR_attrs(df, df_old) - df[colnames(at_percent)] <- sapply( - df[colnames(at_percent)], - function(x) units::set_units(x, "atP"), - simplify = FALSE - ) - } - - return(df) -} - -#' @rdname atomic_conversion -#' @export -at_to_wt <- function(df, elements = colnames(get_unit_columns(df, "atP")), drop = TRUE) { - - # Validate inputs - checkmate::assert_data_frame(df) - - # if ASTR object, include only columns with elements - if (inherits(df, "ASTR")) { - elements <- intersect(elements, elements_data) - } - - # Check if all requested elements are in df - missing_from_df <- setdiff(elements, names(df)) - if (length(missing_from_df) > 0) { - stop("The following elements are not present in df: ", - paste(missing_from_df, collapse = ", ")) - } - - # Check if all elements are valid chemical elements - invalid_elements <- setdiff(elements, elements_data) - if (length(invalid_elements) > 0) { - stop("The following elements are not valid chemical elements: ", - paste(invalid_elements, collapse = ", ")) - } - - weight <- t(t(df[elements]) * conversion_oxides$AtomicWeight[match(elements, conversion_oxides$Element)]) - - total <- rowSums(weight, na.rm = TRUE) - total[total == 0] <- NA_real_ - wt_percent <- weight / total * 100 - - df_old <- df - - if (drop) { - # Replace original columns with atomic percent - df[elements] <- wt_percent - } else { - # Add new columns with suffix - colnames(wt_percent) <- paste0(elements, "_wtP") - df[colnames(wt_percent)] <- wt_percent - } - - if (inherits(df_old, "ASTR")) { - df <- preserve_ASTR_attrs(df, df_old) - df[colnames(wt_percent)] <- sapply( - df[colnames(wt_percent)], - function(x) units::set_units(x, "wtP"), - simplify = FALSE - ) - } - - return(df) -} diff --git a/R/ASTR_conversion_oxide.R b/R/ASTR_conversion_oxide.R deleted file mode 100644 index 855d1b5..0000000 --- a/R/ASTR_conversion_oxide.R +++ /dev/null @@ -1,471 +0,0 @@ -#' Oxide conversion functions -#' -#' Convert between element and oxide weight percent ("oxide%") compositions -#' using pre-compiled conversion factors. -#' -#' If the dataset includes already an element and its oxide, the conversion -#' leaves the values of the respective oxide or element unaffected. The -#' functions convert only values in *wt%*. If concentrations are present in -#' another concentration unit (e.g. *ppm*, *µg/kg*), run -#' [`unify_concentration_unit(df, "wtP")`][unify_concentration_unit()] first to -#' convert all concentrations to *wt%*. If the input is an [`ASTR -#' object`][ASTR], the functions convert only elements or oxides with the -#' respective other type being automatically excluded, even though the unit for -#' both is *wt%*. To convert oxides into *at%* and vice versa, convert to -#' *wt%* first. -#' -#' In `element_to_oxide()`, the parameter `oxide_preference` controls the -#' behaviour of the function if the element forms more than one oxide: -#' * `oxidising`: Use the oxide with the highest oxidation state of the element -#' (e.g., `Fe2O3`) -#' * `reducing`: Use the oxide with the lowest oxidation state of the element -#' (e.g., `FeO`) -#' * `ask`: The user is asked for each element which oxide should be used. -#' * named vector: A named vector mapping the oxides to be used to the -#' elements (e.g., `c(Fe = "FeO", Cu = "Cu2O")`) -#' -#' In `oxide_to_element()`, conversions from different oxides to the same -#' element (e.g., Fe2O3 and FeO to Fe) result in one -#' column for the element with the sum of all converted values of the respective -#' element. -#' -#' Conversion factors are pre-compiled for a wide range of oxides. consequently, -#' conversion is restricted to the oxides on this list. If you encounter an -#' oxide that is currently not included, please reach out to the package -#' maintainers or create a pull request in the [package's GitHub -#' repo](https://github.com/archaeothommy/ASTR) to add it. -#' -#' @param df Data frame with compositional data. -#' @param elements,oxides Character vector with the chemical symbols of the -#' elements or oxides that should be converted. -#' @param oxide_preference String that controls which oxide should be used if an -#' element forms more than one oxide. Allowed values are: `reducing`, -#' `oxidising`, `ask`, or a named vector mapping the specific oxide to its -#' element. See *Details* for further information. -#' @param which_concentrations Character string that determines by concentration -#' which of the `elements` or `oxides` are converted. Allowed values are: -#' * `all` (convert all elements; the default) -#' * `major` (convert elements with concentrations >= 1 wt%) -#' * `minor` (convert elements with concentrations between 0.1 and 1 wt%). -#' * `no_trace` (convert elements with concentrations >=0.1 wt%) -#' @param normalise If `TRUE`, converted concentrations will be normalised to -#' 100%. Default to `FALSE`. -#' @param drop If `FALSE`, the default, columns with unconverted values are -#' kept. If `TRUE`, columns with unconverted values are dropped. Dropping -#' column could result in loss of information as this will also drop columns -#' with values excluded from conversion by the parameter -#' `which_concentrations`. -#' -#' @returns The original data frame with the converted concentrations -#' -#' @export -#' @name oxide_conversion -#' -#' @examples -#' -#' library(magrittr) -#' -#' # Example data frame with element weight percents -#' df <- data.frame(ID = "Sample1", Si = 45, Fe = 50, Cr = 5) -#' -#' # Select elements by oxide_preference -#' element_to_oxide(df, elements = c("Si", "Fe", "Cr"), oxide_preference = "oxidising") -#' element_to_oxide(df, elements = c("Fe", "Cr"), oxide_preference = c(Fe = "FeO", Cr = "Cr2O3")) -#' \dontrun{ -#' element_to_oxide(df, elements = c("Si", "Fe", "Cr"), oxide_preference = "ask") -#' } -#' -#' # Conversions are reversible -#' oxides <- element_to_oxide( -#' df, -#' elements = names(df[-1]), -#' oxide_preference = "oxidising", -#' drop = TRUE -#' ) -#' elements <- oxide_to_element( -#' oxides, -#' oxides = names(oxides[-1]), -#' drop = TRUE -#' ) -#' all.equal(df, elements) -#' -#' # Loss of information by using 'which_concentration' to convert a subset when 'drop = TRUE' -#' df2 <- data.frame(ID = "feldspar", Na = 8.77, Al = 10.29, Si = 32.13, Ba = 0.3, Sr = 0.05) -#' element_to_oxide( -#' df2, -#' elements = names(df2[-1]), -#' which_concentration = "major", -#' oxide_preference = "reducing", -#' drop = TRUE -#' ) -#' -#' # Conversion from oxide to element summarises columns converting to the same element -#' df3 <- data.frame(Fe2O3 = 20, FeO = 20, Cr2O3 = 15, CrO2 = 15, CuO = 20, Cu2O = 20) -#' oxide_to_element(df3, oxides = names(df3), drop = TRUE) -#' -#' # Use with ASTR objects -#' # Create ASTR object -#' test_file <- system.file("extdata", "test_data_input_good.csv", package = "ASTR") -#' arch <- read_ASTR(test_file, id_column = "Sample", context = 1:7) -#' -#' # Convert columns from oxide to wt% -#' arch_wtP <- element_to_oxide(arch, oxide_preference = "oxidising") -#' -#' # To convert all applicable concentrations, unify units first: -#' arch_all <- unify_concentration_unit(arch, "wtP") %>% -#' element_to_oxide(oxide_preference = "oxidising") -#' -element_to_oxide <- function( - df, - elements = colnames(get_unit_columns(df, "wtP")), - oxide_preference, - which_concentrations = c("all", "major", "minor", "no_trace"), - normalise = FALSE, - drop = FALSE -) { - # Validate inputs - checkmate::assert_data_frame(df) - - checkmate::assert_character(elements, - any.missing = FALSE, - all.missing = FALSE, - pattern = paste0(elements_data, collapse = "|") - ) - checkmate::assert_character(oxide_preference, - any.missing = FALSE, - all.missing = FALSE - ) - checkmate::assert_character(which_concentrations, - any.missing = FALSE, - all.missing = FALSE, - pattern = "all|major|minor|no_trace" - ) - - which_concentrations <- match.arg(which_concentrations) - - if (inherits(df, "ASTR")) { - elements <- intersect(elements, elements_data) - } - - # Check if all requested elements are in df - missing_from_df <- setdiff(elements, names(df)) - if (length(missing_from_df) > 0) { - stop( - "The following elements are not present in df: ", - paste(missing_from_df, collapse = ", ") - ) - } - - # create subset of reference table for elements in data frame with recorded oxides - conversion_table <- conversion_oxides[conversion_oxides$Element %in% elements & !is.na(conversion_oxides$Oxide), ] - - # check that all requested elements have oxides - if (!all(elements %in% conversion_table$Element)) { - stop( - "Oxides of one or more elements not available. See 'ASTR::conversion_oxides' for a list of available oxides. ", - "To proceed, please exclude the elements from the conversion.\n\n", - "See instructions in the 'Details' section of the function documentation to add oxides to the list. " - ) - } - - # Handle oxide preference - if (length(oxide_preference) == 1 && !oxide_preference %in% conversion_table$Oxide) { - # Single string preference - switch(oxide_preference, - oxidising = { - pref <- conversion_table %>% - dplyr::group_by(.data$Element) %>% - dplyr::filter(.data$OxidationState == max(.data$OxidationState)) %>% - dplyr::select("Element", "Oxide") %>% - tibble::deframe() - }, - reducing = { - pref <- conversion_table %>% - dplyr::group_by(.data$Element) %>% - dplyr::filter(.data$OxidationState == min(.data$OxidationState)) %>% - dplyr::select("Element", "Oxide") %>% - tibble::deframe() - }, - ask = { - pref <- interactive_oxide_select(elements) - }, - { - stop("'oxide_preference' must either have the value 'oxidising', 'reducing', or 'ask', or be a named vector.") - } - ) - } else { - # Named vector preference - # check names are valid elements - invalid_elements <- setdiff(names(oxide_preference), conversion_oxides$Element) - if (length(invalid_elements) > 0) { - stop("Invalid element names in 'oxide_preference': ", paste0(invalid_elements, collapse = ", ")) - } - - # check values are valid oxides - invalid_oxides <- setdiff(oxide_preference, conversion_oxides$Oxide) - if (length(invalid_oxides) > 0) { - stop("Invalid oxide names in 'oxide_preference': ", paste0(invalid_oxides, collapse = ", ")) - } - - # check that the element matches the specified oxide - check <- oxide_preference - for (el in names(check)) { - ox <- conversion_oxides$Oxide[conversion_oxides$Element == el] - if (check[el] %in% ox) { - check[el] <- NA - } - } - - # if matching is not successful, throw error and specify non-matching pairs - if (any(!is.na(check))) { - check <- check[!is.na(check)] - stop( - "'oxide_preference' includes invalid combinations:\n", - paste(check, names(check), sep = " is not an oxide of ", collapse = "\n") - ) - } - - pref <- oxide_preference - } - - # Apply major/minor filter - switch(which_concentrations, - all = { - oxide_percent <- df - # do nothing, convert all - }, - major = { - # Only convert elements >= 1 wt% - oxide_percent <- df - oxide_percent[oxide_percent < 1] <- NA - }, - minor = { - # Only convert elements (0.1 - 1 wt%) - oxide_percent <- df - oxide_percent[oxide_percent < 0.1 | oxide_percent >= 1] <- NA - }, - no_trace = { - # Only elements (> 0.1 wt%) - oxide_percent <- df - oxide_percent[oxide_percent < 0.1] <- NA - } - ) - - # trim conversion_table to requested oxides - conversion_table <- conversion_table[conversion_table$Oxide %in% pref, ] - - oxide_percent <- t( - t(oxide_percent[elements]) * conversion_table$ElementToOxide[match(elements, conversion_table$Element)] - ) - - colnames(oxide_percent)[match(names(pref), colnames(oxide_percent))] <- paste0(pref, "_wtP") - - # Normalise if requested - if (normalise) { - oxide_percent <- normalise_rows(oxide_percent) - } - - df_old <- df - - # Add oxide columns to output - df[colnames(oxide_percent)] <- oxide_percent - - if (inherits(df, "ASTR")) { - df <- remove_units(df, recover_unit_names = TRUE) - df <- suppressWarnings( - as_ASTR(df, id_column = "ID", context = colnames(get_contextual_columns(df_old))) - ) - } else { - colnames(df) <- gsub("_wtP", "", colnames(df)) - } - - # drop input columns if requested - if (drop) { - df[elements] <- NULL - } - - return(df) -} - -#' @rdname oxide_conversion -#' @export -oxide_to_element <- function( - df, - oxides = colnames(get_unit_columns(df, "wtP")), - normalise = FALSE, - drop = FALSE -) { - #Validate inputs - checkmate::assert_data_frame(df) - - checkmate::assert_character( - oxides, - any.missing = FALSE, - all.missing = FALSE - ) - - if (inherits(df, "ASTR")) { - oxides <- intersect(oxides, oxides_data) - } - - # Check if all requested oxides are in df - missing <- setdiff(oxides, names(df)) - if (length(missing) > 0) { - stop( - "The following oxides are not present in df: ", - paste(missing, collapse = ", ") - ) - } - - # subset conversion table - conversion_table <- conversion_oxides[conversion_oxides$Oxide %in% oxides & - !is.na(conversion_oxides$OxideToElement), ] - - if (!all(oxides %in% conversion_table$Oxide)) { - stop( - "Conversion factors for one or more oxides are not available. ", - "See 'ASTR::conversion_oxides' for a list of available oxides.\n\n", - "See instructions in the 'Details' section of the function documentation to add oxides to the list." - ) - } - - # convert - element_percent <- df - - element_percent <- t( - t(element_percent[oxides]) * conversion_table$OxideToElement[match(oxides, conversion_table$Oxide)] - ) - - element_percent <- as.data.frame(element_percent) - - colnames(element_percent) <- paste0(conversion_table$Element[match(oxides, conversion_table$Oxide)], "_wtP") - - # make column names syntactically valid - colnames(element_percent) <- make.names(colnames(element_percent), unique = TRUE) - - # Sum duplicate elements (e.g., Fe from FeO + Fe2O3) - element_percent <- sum_duplicates(element_percent) - - # Normalise if requested - if (normalise) { - element_percent <- normalise_rows(element_percent) - } - - df_old <- df - - # Add element columns to output - df[colnames(element_percent)] <- element_percent - - if (inherits(df, "ASTR")) { - df <- remove_units(df, recover_unit_names = TRUE) - df <- suppressWarnings( - as_ASTR(df, id_column = "ID", context = colnames(get_contextual_columns(df_old))) - ) - } else { - colnames(df) <- gsub("_wtP", "", colnames(df)) - } - - - if (drop) { - df[oxides] <- NULL - } - - return(df) -} - -#' Interactive oxide selection -#' -#' Interactively compiles list of oxides from user input. -#' -#' @param elements A character vector with chemical symbols of elements -#' -#' @returns named vector with all oxides for the supplied list of elements -#' -#' @keywords internal -#' -interactive_oxide_select <- function(elements) { - message("Starting interactive selection of oxides") - - oxides <- stats::setNames(elements, elements) - - for (el in elements) { - ox <- conversion_oxides$Oxide[conversion_oxides$Element == el] - - if (length(ox) > 1) { - choice <- readline( - paste0("Choose oxide for ", el, " [available: ", paste0(ox, collapse = ", "), "]: ") - ) - - repeat { - if (choice %in% ox) break - choice <- readline( - paste0("Invalid input. Please choose from the available oxides [", paste0(ox, collapse = ", "), "]: ") - ) - } - } else { - choice <- ox - } - - oxides[el] <- choice - } - - message("Selection complete") - return(oxides) -} - -#' Sum columns with same column name -#' -#' The function recognises and includes column names that in fact have the same -#' name but were made unique by R functions. -#' -#' @param df A data frame -#' -#' @keywords internal -#' @importFrom magrittr %>% -#' @importFrom dplyr rowwise mutate ungroup c_across -#' @importFrom tidyselect starts_with -#' -sum_duplicates <- function(df) { - if (ncol(df) == 0) { - return(df) - } - - # get duplicated column names, even if they were made unique by R - col_names <- sub("\\.+[[:digit:]]+", "", colnames(df)) - col_names <- unique(col_names[duplicated(col_names)]) - - if (length(col_names) == 0) { - return(df) - } # No duplicates - - for (i in col_names) { - df <- df %>% - dplyr::rowwise() %>% - dplyr::mutate({{ i }} := sum(dplyr::c_across(tidyselect::starts_with(i))), .keep = "unused") %>% - dplyr::ungroup() - } - - return(df) -} - -#' Normalise rows to 100% -#' -#' @param df A matrix or data frame -#' -#' Normalises values in a vector to 100% -#' -#' @keywords internal -normalise_rows <- function(df) { - - if (ncol(df) == 0) { - return(df) - } - - row_sums <- rowSums(df, na.rm = TRUE) - row_sums[row_sums == 0] <- NA_real_ - - # Normalise and return as percentages - result <- df / row_sums * 100 - - return(result) -} diff --git a/R/ASTR_copper_alloy_classification_bb.R b/R/ASTR_copper_alloy_classification_bb.R index 8d12cc4..8fcfd73 100644 --- a/R/ASTR_copper_alloy_classification_bb.R +++ b/R/ASTR_copper_alloy_classification_bb.R @@ -61,56 +61,70 @@ copper_alloy_bb <- function( # Create subset with just ID and classification column copper_alloy <- data.frame( ID_sample = df[[id_column]], - Sn = df[[elements["Sn"]]], - Zn = df[[elements["Zn"]]], - Pb = df[[elements["Pb"]]], - result = rep("Unclassified", nrow(df)), + Sn = df[[elements["Sn"]]], + Zn = df[[elements["Zn"]]], + Pb = df[[elements["Pb"]]], + result = rep("Unclassified", nrow(df)), stringsAsFactors = FALSE ) - # Base alloy classes + # Identify rows where any element is NA — these stay Unclassified + na_mask <- is.na(copper_alloy$Sn) | + is.na(copper_alloy$Zn) | + is.na(copper_alloy$Pb) + # Base alloy classes # Copper: Zn < 3 and Sn < 3 - copper_alloy$result[copper_alloy$Zn < 3 & copper_alloy$Sn < 3] <- "Copper" + copper_alloy$result[!na_mask & + copper_alloy$Zn < 3 & + copper_alloy$Sn < 3] <- "Copper" - # Copper/brass: 3 ≤ Zn < 8 and Sn < 3 - copper_alloy$result[copper_alloy$Zn >= 3 & + # Copper/brass: 3 <= Zn < 8 and Sn < 3 + copper_alloy$result[!na_mask & + copper_alloy$Zn >= 3 & copper_alloy$Zn < 8 & copper_alloy$Sn < 3] <- "Copper/brass" - # Bronze: Sn ≥ 3 and Zn < 3 * Sn - copper_alloy$result[copper_alloy$Sn >= 3 & + # Bronze: Sn >= 3 and Zn < 3 * Sn + copper_alloy$result[!na_mask & + copper_alloy$Sn >= 3 & copper_alloy$Zn < 3 * copper_alloy$Sn] <- "Bronze" - # Bronze/gunmetal: Sn ≥ 3 and Zn between 0.33*Sn and 0.67*Sn - copper_alloy$result[copper_alloy$Sn >= 3 & + # Bronze/gunmetal: Sn >= 3 and Zn between 0.33*Sn and 0.67*Sn + copper_alloy$result[!na_mask & + copper_alloy$Sn >= 3 & copper_alloy$Zn > 0.33 * copper_alloy$Sn & copper_alloy$Zn < 0.67 * copper_alloy$Sn] <- "Bronze/gunmetal" - # Gunmetal: Zn > 0.67*Sn and Zn < 2.5*Sn and Sn ≥ 3 - copper_alloy$result[copper_alloy$Sn >= 3 & + # Gunmetal: Zn > 0.67*Sn and Zn < 2.5*Sn and Sn >= 3 + copper_alloy$result[!na_mask & + copper_alloy$Sn >= 3 & copper_alloy$Zn > 0.67 * copper_alloy$Sn & copper_alloy$Zn < 2.5 * copper_alloy$Sn] <- "Gunmetal" - # Brass/gunmetal: Zn > 2.5*Sn and Zn <= 4*Sn AND (Zn ≥ 8 OR Sn ≥ 3) - copper_alloy$result[(copper_alloy$Zn >= 8 | copper_alloy$Sn >= 3) & + # Brass/gunmetal: Zn > 2.5*Sn and Zn <= 4*Sn AND (Zn >= 8 OR Sn >= 3) + copper_alloy$result[!na_mask & + (copper_alloy$Zn >= 8 | copper_alloy$Sn >= 3) & copper_alloy$Zn > 2.5 * copper_alloy$Sn & copper_alloy$Zn <= 4 * copper_alloy$Sn] <- "Brass/gunmetal" - # Brass: Zn ≥ 8 and Zn > 4*Sn - copper_alloy$result[copper_alloy$Zn >= 8 & + # Brass: Zn >= 8 and Zn > 4*Sn + copper_alloy$result[!na_mask & + copper_alloy$Zn >= 8 & copper_alloy$Zn > 4 * copper_alloy$Sn] <- "Brass" - # Apply lead modifiers + # Apply lead modifiers only to non-NA rows ## (Leaded): Pb between 4 and 8 - copper_alloy$result[copper_alloy$Pb >= 4 & - copper_alloy$Pb <= 8] <- paste( - "(Leaded)", - copper_alloy$result[copper_alloy$Pb >= 4 & copper_alloy$Pb <= 8] + prefix_leaded <- !na_mask & copper_alloy$Pb >= 4 & copper_alloy$Pb <= 8 + copper_alloy$result[prefix_leaded] <- paste( + "(Leaded)", copper_alloy$result[prefix_leaded] ) ## Leaded: Pb > 8 - copper_alloy$result[copper_alloy$Pb > 8] <- paste("Leaded", copper_alloy$result[copper_alloy$Pb > 8]) + prefix_high_lead <- !na_mask & copper_alloy$Pb > 8 + copper_alloy$result[prefix_high_lead] <- paste( + "Leaded", copper_alloy$result[prefix_high_lead] + ) # Merge results back to original dataframe by ID copper_alloy_bb <- copper_alloy$result[match(df[[id_column]], copper_alloy$ID_sample)] diff --git a/R/ASTR_copper_alloy_classification_pollard.R b/R/ASTR_copper_alloy_classification_pollard.R index 1b1a0d5..778ac7c 100644 --- a/R/ASTR_copper_alloy_classification_pollard.R +++ b/R/ASTR_copper_alloy_classification_pollard.R @@ -54,11 +54,9 @@ copper_alloy_pollard <- function( group_as_symbol = FALSE, ...) { - # convert units to wt% - if (inherits(df, "ASTR")) { df <- convert_concentration_units(df, elements, "wtP", ...) - elements <- c(Sn = "Sn", Zn = "Zn", Pb = "Pb") # rename in case input was in oxides + elements <- c(Sn = "Sn", Zn = "Zn", Pb = "Pb") threshold <- units::set_units(1, "wtP") } else { threshold <- 1 # wt%, set in Pollard et al. (2015) @@ -72,6 +70,13 @@ copper_alloy_pollard <- function( Pb_flag = df[[elements["Pb"]]] >= threshold ) + # Identify rows where any element is NA — these stay Unclassified + flags$has_na <- apply( + flags[, c("Sn_flag", "Zn_flag", "Pb_flag")], + 1, + function(row) any(is.na(row)) + ) + # Convert flags into a pattern string flags$pattern <- apply( flags[, c("Sn_flag", "Zn_flag", "Pb_flag")], @@ -107,26 +112,34 @@ copper_alloy_pollard <- function( ) # Join with lookup table, preserving row order - out <- merge(flags[, c("ID_sample", "pattern")], - lookup, - by = "pattern", - all.x = TRUE) - - # Ensure "Unclassified" for any missing matches - out$alloy_name[is.na(out$alloy_name)] <- "Unclassified" - out$alloy_symbol[is.na(out$alloy_symbol)] <- "Unclassified" + out <- merge( + flags[, c("ID_sample", "pattern", "has_na")], + lookup, + by = "pattern", + all.x = TRUE + ) - # Add correct output column + # Add correct output column — NA in any element = Unclassified if (!group_as_symbol) { - copper_alloy_pollard <- out$alloy_name[match(df[[id_column]], out$ID_sample)] + copper_alloy_pollard <- ifelse( + out$has_na[match(df[[id_column]], out$ID_sample)], + "Unclassified", + out$alloy_name[match(df[[id_column]], out$ID_sample)] + ) } else { - copper_alloy_pollard <- out$alloy_symbol[match(df[[id_column]], out$ID_sample)] + copper_alloy_pollard <- ifelse( + out$has_na[match(df[[id_column]], out$ID_sample)], + "Unclassified", + out$alloy_symbol[match(df[[id_column]], out$ID_sample)] + ) } if (inherits(df, "ASTR")) { df_out <- df[c(colnames(get_contextual_columns(df)), elements)] df_out[["copper_alloy_pollard"]] <- copper_alloy_pollard - df_out[["copper_alloy_pollard"]] <- add_ASTR_class(df_out[["copper_alloy_pollard"]], "ASTR_context") + df_out[["copper_alloy_pollard"]] <- add_ASTR_class( + df_out[["copper_alloy_pollard"]], "ASTR_context" + ) } else { df_out <- df df_out[["copper_alloy_pollard"]] <- copper_alloy_pollard diff --git a/R/ASTR_copper_classification_Bray.R b/R/ASTR_copper_classification_Bray.R index 2850f10..0b8a4a7 100644 --- a/R/ASTR_copper_classification_Bray.R +++ b/R/ASTR_copper_classification_Bray.R @@ -80,6 +80,12 @@ copper_group_bray <- function( ) # Convert flags into a pattern string + flags$has_na <- apply( + flags[, c("As_flag", "Sb_flag", "Ag_flag", "Ni_flag")], + 1, + function(row) any(is.na(row)) + ) + flags$pattern <- apply( flags[, c("As_flag", "Sb_flag", "Ag_flag", "Ni_flag")], 1, @@ -130,15 +136,30 @@ copper_group_bray <- function( ) # Join with lookup table, preserving row order - out <- merge(flags[, c("ID_sample", "pattern")], lookup, by = "pattern", all.x = TRUE, sort = TRUE) + out <- merge( + flags[, c("ID_sample", "pattern", "has_na")], + lookup, + by = "pattern", + all.x = TRUE, + sort = TRUE + ) - # Add correct output column + # Add correct output column — NA in any element = Unclassified if (!group_as_number) { - copper_group_bray <- out$group_name[match(df[[id_column]], out$ID_sample)] + copper_group_bray <- ifelse( + out$has_na[match(df[[id_column]], out$ID_sample)], + "Unclassified", + out$group_name[match(df[[id_column]], out$ID_sample)] + ) } else { - copper_group_bray <- out$group_number[match(df[[id_column]], out$ID_sample)] + copper_group_bray <- ifelse( + out$has_na[match(df[[id_column]], out$ID_sample)], + NA_integer_, + out$group_number[match(df[[id_column]], out$ID_sample)] + ) } + # Return ASTR object or plain data frame if (inherits(df, "ASTR")) { df_out <- df[c(colnames(get_contextual_columns(df)), elements)] df_out[["copper_group_bray"]] <- copper_group_bray diff --git a/R/ASTR_data.R b/R/ASTR_data.R deleted file mode 100644 index bd0fe3f..0000000 --- a/R/ASTR_data.R +++ /dev/null @@ -1,71 +0,0 @@ -#' Chemical elements -#' -#' List of chemical elements as their symbols, sorted according to alphabet. -#' -#' @format a vector -#' -#' @family chemical reference data -#' @name elements_data -"elements_data" - -#' Oxides -#' -#' List of oxides, sorted according to alphabet. -#' -#' @format a vector -#' -#' @family chemical reference data -#' @name oxides_data -"oxides_data" - -#' Special oxide states -#' -#' List of values that are treated like oxides, but are no chemical oxides. -#' -#' @format a vector -#' -#' @family chemical reference data -#' @name special_oxide_states -"special_oxide_states" - -#' Isotopes -#' -#' List of naturally occurring isotopes, retrieved from -#' https://www.ciaaw.org/isotopic-abundances.htm, sorted according to chemical -#' element and isotope number -#' -#' @format a vector -#' -#' @family chemical reference data -#' @name isotopes_data -"isotopes_data" - -#' Conversion factors from oxides to elements -#' -#' @format A data frame with 151 rows and 8 variables: -#' \describe{ -#' \item{Element}{The symbol of a chemical element.} -#' \item{AtomicWeight}{The atomic weight (= molar mass) of the respective element.} -#' \item{Oxide}{The formula of the chemical element's oxide.} -#' \item{M}{The number of oxygen atoms in the oxide = the number of moles oxygen per mole oxide.} -#' \item{OxideWeight}{The molar mass of the oxide.} -#' \item{ElementToOxide}{The factor used in the conversion from the chemical element to its oxide.} -#' \item{OxideToElement}{The factor used in the conversion from the oxide to its chemical element.} -#' \item{OxidationState}{The oxidation state of the kation as numeric value.} -#' } -#' -#' @family chemical reference data -#' @name conversion_oxides -"conversion_oxides" - -#' Lead isotope data from Argentina -#' -#' Lead isotope data from ore deposits in Argentina prepared for the TerraLID database. -#' -#' @format `ArgentinaDatabase` -#' -#' A dataframe with 112 rows and 49 columns -#' -#' @source -#' @name ArgentinaDatabase -"ArgentinaDatabase" diff --git a/R/ASTR_geom_stacey_karmers.R b/R/ASTR_geom_stacey_karmers.R deleted file mode 100644 index 250dc0c..0000000 --- a/R/ASTR_geom_stacey_karmers.R +++ /dev/null @@ -1,294 +0,0 @@ -#' Lead Evolution Geom for Stacey & Kramers (1975) -#' -#' These Geoms draws and label isochron, geochron, and kappa lines used for -#' isotope age model referencing in lead isotope biplots. The lines follows the -#' model used by Stacey & Kramers (1975). -#' -#' The plotting system follows the convention of showing geochron and isochron -#' lines for the 207Pb/204Pb vs. 206Pb/204Pb plot and the kappa lines for -#' 208Pb/204Pb vs. 206Pb/204Pb plot. -#' -#' The geoms accept the following additional parameters through `...`: -#' * `Ti` : Initial time of the second stage in years (default 3.7 Ga). -#' * `interval` : Time interval for isochron labels in years (default 200 Ma). -#' * `show_geochron` : Logical; should the Geochron be plotted? (default `TRUE`). -#' * `show_isochrons` : Logical; should time isochrons be plotted? (default `TRUE`) -#' * `kappa_list` : Numeric vector of Kappa values to plot in "86" system. -#' -#' # Note -#' -#' Currently the plot will scale the xlim and ylim to their maximum bounds. To -#' prevent this, use [`coord_cartesian(xlim, ylim)`][ggplot2::coord_cartesian()] -#' to force the axis range to the desired values. -#' -#' @inheritParams ggplot2::layer -#' @param Mu1 Second-stage 238U/204Pb ratio (default 10). -#' @param Kappa Second-stage 232Th/238U ratio (default 4). -#' @param system Character "76" or "86" defining the isotope plot axis (default -#' "76"). -#' @param ... Additional parameters for the geoms (see *Details*) and other -#' arguments passed on to [ggplot2::layer()]. These are often aesthetics used -#' to set a fixed value, such as `colour = "red"` or `alpha = 0.5`. -#' -#' @section Aesthetics: `geom_sk_lines()` and `geom_sk_labels()` accept the -#' following aesthetic values: -#' -#' * `alpha` -#' * `colour` (controls the polygon outline) -#' * `fill` (controls the polygon fill) -#' * `linetype` -#' * `linewidth` (controls the outline thickness) -#' * `text.colour` (controls colour of the text) -#' * `size.unit` (controls size aesthetic in "mm", "pt", "cm", "in" or "pc") -#' -#' Learn more about setting these aesthetics in `vignette("ggplot2-specs")`. -#' -#' @references Stacey, J.S. and Kramers, J.D. (1975) Approximation of -#' terrestrial lead isotope evolution by a two-stage model. Earth and -#' Planetary Science Letters 26(2), pp. 207–221. -#' . -#' -#' @return A ggplot2 layer object. -#' -#' @family Pb isotope functions -#' -#' @export -#' @examples -#' # example code -#' -#' library(ggplot2) -#' set.seed(50) -#' df <- data.frame( -#' pb64 = rnorm(10, 18,0.2), -#' pb74 = rnorm(10, 15.7,0.1), -#' pb84 = rnorm(10, 37.5,0.1) -#' ) -#' -#' # Creating the Pb 207/204~206/204 plot -#' ggplot(df, aes(x = pb64, y = pb74)) + -#' geom_point() + -#' geom_sk_lines(system = "76") + -#' geom_sk_labels(system = "76") + -#' coord_cartesian( -#' xlim = range(df$pb64) * c(.99, 1.01), -#' ylim = range(df$pb74) * c(.99, 1.01) -#' ) + -#' labs( -#' x = expression({}^206*Pb / {}^204*Pb), -#' y = expression({}^207*Pb / {}^204*Pb), -#' ) -#' -#' # Creating the Pb 208/204~206/204 plot -#' ggplot(df, aes(x = pb64, y = pb84)) + -#' geom_point() + -#' geom_sk_lines(system = "86", -#' show_isochrons = FALSE, show_geochron = FALSE, -#' kappa_list = c(3.2, 3.4, 3.6, 3.8)) + -#' geom_sk_labels(system = "86", -#' show_isochrons = FALSE, show_geochron = FALSE, -#' kappa_list = c(3.2, 3.4, 3.6, 3.8)) + -#' coord_cartesian( -#' xlim = range(df$pb64) * c(.99, 1.01), -#' ylim = range(df$pb84) * c(.99, 1.01) -#' ) + -#' labs( -#' x = expression({}^206*Pb / {}^204*Pb), -#' y = expression({}^207*Pb / {}^204*Pb), -#' ) -#' -#' # Creating the Pb 207/204~206/204 plot with a seperate Geocrone color -#' -#' ggplot(df, aes(x = pb64, y = pb74)) + -#' geom_point() + -#' geom_sk_lines(system = "76", show_geochron = FALSE) + -#' geom_sk_lines(system = "76", show_isochrons = FALSE, -#' color = 'red', linetype = 'dashed') + -#' geom_sk_labels(system = "76", show_geochron = FALSE) + -#' geom_sk_labels(system = "76", show_isochrons = FALSE, color = 'red') + -#' coord_cartesian( -#' xlim = range(df$pb64) * c(.99, 1.01), -#' ylim = range(df$pb74) * c(.99, 1.01) -#' ) + -#' labs( -#' x = expression({}^206*Pb / {}^204*Pb), -#' y = expression({}^207*Pb / {}^204*Pb), -#' ) -#' -geom_sk_lines <- function(mapping = NULL, - data = NULL, - system = c("76", "86"), - Mu1 = 10, - Kappa = 4, - ...) { - layer( - stat = StatStaceyKramers, - data = data, - mapping = mapping, - geom = "path", - position = "identity", - inherit.aes = TRUE, # Inherits x (206) and y (207 or 208) - params = list( - system = match.arg(system), - Mu1 = Mu1, - Kappa = Kappa, - ... - ) - ) -} - -#' @rdname geom_sk_lines -#' @export -geom_sk_labels <- function(mapping = NULL, - data = NULL, - system = "76", - Mu1 = 10, - Kappa = 4, - ...) { - layer( - stat = StatStaceyKramers, - data = data, - # FIX: after_stat MUST be inside aes() - mapping = mapping, - geom = "text", - position = "identity", - inherit.aes = TRUE, # FIX: Must be TRUE to find x/y coordinates - params = list( - system = system, - Mu1 = Mu1, - Kappa = Kappa, - na.rm = TRUE, - hjust = -0.2, - vjust = -0.5, - size = 3, - ... - ) - ) -} - -# Stats ------------------------------------------------------------------- - -#' @import ggplot2 -#' @importFrom dplyr bind_rows filter mutate select -#' @importFrom rlang .data -StatStaceyKramers <- ggplot2::ggproto( - "StatStaceyKramers", - ggplot2::Stat, - required_aes = c("x", "y"), - - compute_group = function(data, - scales, - Mu1 = 10, - Kappa = 4, - Ti = 3.70e9, - interval = 200e6, - system = c("76", "86"), - show_geochron = TRUE, - show_isochrons = TRUE, - kappa_list = c(3.4, 3.6, 3.8, 4, 4.2, 4.4)) { - # Constants - ap <- 9.307 - bp <- 10.294 - cp <- 29.476 - a0 <- 11.152 - b0 <- 12.998 - c0 <- 31.230 - l238 <- 1.55125e-10 - l235 <- 9.8485e-10 - l232 <- 4.9475e-11 - u_ratio <- 137.88 - - fA <- function(t) exp(l238 * Ti) - exp(l238 * t) - fB <- function(t) exp(l235 * Ti) - exp(l235 * t) - fC <- function(t) exp(l232 * Ti) - exp(l232 * t) - - # Y-Pin logic for steep lines - y_lims <- scales$y$get_limits() - y_target <- y_lims[1] + 0.85 * (y_lims[2] - y_lims[1]) - - # --- 1. Growth Curve (Mu) --- - growth <- data.frame() - mu_label <- data.frame() - - if (system == "76") { - t_seq <- seq(0, Ti, length.out = 100) - gx <- a0 + (Mu1 * fA(t_seq)) - gy <- b0 + (Mu1 / u_ratio) * fB(t_seq) - - growth <- data.frame( - x = gx, y = gy, label = NA, angle = 0, - type = "growth", group = 1 - ) - mu_label <- data.frame( - x = gx[1], y = gy[1], label = paste("Mu", Mu1), - angle = 0, type = "label_mu", group = 2 - ) - } - - # --- 2. Isochrons (Time Lines) --- - isochrons <- data.frame() - if (show_isochrons) { - time_intervals <- seq(0, Ti, by = interval) - isochrons <- lapply(time_intervals, function(ti) { - y_orig <- if (system == "76") b0 else c0 - slope <- if (system == "76") (1 / u_ratio) * (fB(ti) / fA(ti)) else Kappa * (fC(ti) / fA(ti)) - xl <- (y_target - y_orig) / slope + a0 - data.frame( - x = c(a0, a0 + 50), y = c(y_orig, y_orig + slope * 50), - label = c(NA, paste0("T", ti / 1e6)), - x_lab = xl, y_lab = y_target, - angle = atan(slope) * (180 / pi), - type = "isochron", group = ti + 100 - ) - }) %>% dplyr::bind_rows() - } - - # --- 3. Kappa Lines (86 System Only) --- - kappa_data <- data.frame() - if (system == "86") { - x_lims <- scales$x$get_limits() - x_mid <- mean(x_lims) - kappa_data <- lapply(kappa_list, function(k) { - slope_k <- k * (fC(0) / fA(0)) - intercept_k <- c0 - (slope_k * a0) - y_mid <- (slope_k * x_mid) + intercept_k - data.frame( - x = c(x_lims[1] - 10, x_lims[2] + 10), - y = c((slope_k * (x_lims[1] - 10)) + intercept_k, (slope_k * (x_lims[2] + 10)) + intercept_k), - label = c(paste("K", k), NA), - x_lab = x_mid, y_lab = y_mid, - angle = atan(slope_k) * (180 / pi), - type = "kappa_line", group = k * 1000 - ) - }) %>% dplyr::bind_rows() - } - - # --- 4. Geochron --- - geochron <- data.frame() - if (show_geochron) { - T_earth <- 4.57e9 - slope_geo <- if (system == "76") (1 / u_ratio) * (exp(l235 * T_earth) - 1) / (exp(l238 * T_earth) - 1) - else Kappa * (exp(l232 * T_earth) - 1) / (exp(l238 * T_earth) - 1) - yp <- if (system == "76") bp else cp - xl_geo <- (y_target - yp) / slope_geo + ap - geochron <- data.frame( - x = c(ap, ap + 50), y = c(yp, yp + slope_geo * 50), - label = c(NA, "Geochron"), x_lab = xl_geo, y_lab = y_target, - angle = atan(slope_geo) * (180 / pi), - type = "geochron", group = 999 - ) - } - - all_data <- dplyr::bind_rows(growth, mu_label, isochrons, geochron, kappa_data) - - label_rows <- all_data %>% - dplyr::filter(!is.na(label)) %>% - dplyr::mutate( - x = ifelse(!is.na(x_lab), x_lab, x), - y = ifelse(!is.na(y_lab), y_lab, y) - ) - - line_rows <- all_data %>% dplyr::select(-x_lab, -y_lab) - - return(dplyr::bind_rows(line_rows, label_rows)) - } -) diff --git a/R/ASTR_unit_manipulation.R b/R/ASTR_unit_manipulation.R deleted file mode 100644 index 6fa6f01..0000000 --- a/R/ASTR_unit_manipulation.R +++ /dev/null @@ -1,159 +0,0 @@ -#' @rdname ASTR -#' @export -remove_units <- function(x, ...) { - UseMethod("remove_units") -} -#' @export -remove_units.ASTR <- function(x, recover_unit_names = FALSE, ...) { - # rename columns: recover units in column names - if (recover_unit_names) { - x <- dplyr::rename_with( - x, - function(column_names) { - unit_names <- purrr::map_chr( - column_names, - function(column_name) { - # render individual units - unit <- units(x[[column_name]]) - rendered_unit <- as.character(unit, neg_power = FALSE, prod_sep = "*") - # handle special cases - dplyr::recode_values( - rendered_unit, - "atP" ~ "at%", - "wtP" ~ "wt%", - "count/s" ~ "cps", - default = rendered_unit - ) - } - ) - paste0(column_names, "_", unit_names) - }, - tidyselect::where(function(y) { - class(y) == "units" && !is_ASTR_class(y, "ASTR_error") - }) - ) - } - # drop units - dplyr::mutate( - x, - dplyr::across( - tidyselect::where(function(y) { - class(y) == "units" - }), - units::drop_units - ) - ) -} - -#' @rdname ASTR -#' @param unit string with a unit definition that can be understood by -#' \link[units]{set_units}, e.g. "%", "kg", or "m/s^2" -#' @export -unify_concentration_unit <- function(x, unit, ...) { - UseMethod("unify_concentration_unit") -} -#' @export -unify_concentration_unit <- function(x, unit, ...) { - dplyr::mutate( - x, - dplyr::across( - tidyselect::where(function(y) { - class(y) == "units" && - units::ud_are_convertible(units::deparse_unit(y), "%") - }), - function(z) units::set_units(z, unit, mode = "standard") - ) - ) -} - -#' Convert units -#' -#' The function is intended to provide "on-the-fly" unit conversions inside -#' functions that require values in a certain unit. Use the respective -#' conversion functions for proper, user-facing unit conversions. It is not -#' intended to be used by users. It converts *ALL* values in the unit and -#' convertable units of the values intended to be converted to ensure that e.g. -#' normalisation is not performed on subsets. -#' -#' Only the converted values of the input are intended to be processed further -#' and except for them, columns of the unconverted ASTR object should be made -#' available to the user in the function calling this unit converter. -#' -#' @param df ASTR object -#' @param values Character vector with column names of the values to be -#' converted. -#' @param unit_to The unit the values should be converted to -#' @param ... Additional values passed to the conversion functions. This is -#' primarily intended for conversion into oxides because this function takes a -#' mandatory parameter that does not has a default value. -#' -#' @keywords internal -convert_concentration_units <- function(df, values, unit_to, ...) { - checkmate::assert_class(df, "ASTR") - - # exclude mixed oxides and elements - type <- intersect(values, elements_data) # length 0 = only oxides - - if (!length(type) %in% c(0, length(values))) { - stop("Unit conversion failed: Values include oxides and elements. Please convert one into another manually first.") - } - - # unify concentrations: SI unit or unitless -> target unit; atP or oxP -> wtP as common base - df <- unify_concentration_unit( - df, - unit = ifelse(unit_to %in% c("oxP", "atP"), "wtP", unit_to) - ) - - # get units of required values - unit_from <- sapply(df[values], function(x) units::deparse_unit(x)) - unit_from <- unique(unit_from) - - # check if all values are in the same unit - if (length(unit_from) > 1) { - stop( - "Unit conversion failed: Units cannot be converted into each other: ", - paste0(unique(unit_from), collapse = ", ") - ) - } - - # if handling only oxides: make sure values are in wt%, identify them - if (length(type) == 0) { - unit_from <- "oxP" - } - - # determine type of conversion (to-from) and convert columns accordingly - to_from <- paste0(unit_from, unit_to) - - switch(to_from, - atPwtP = { - df <- at_to_wt(df, ...) - }, - wtPatP = { - df <- wt_to_at(df, ...) - }, - wtPoxP = { - df <- element_to_oxide(df, ...) - }, - oxPwtP = { - df <- oxide_to_element(df, ...) - }, - atPoxP = { - cols <- colnames(get_unit_columns(df, "atP")) - - df <- at_to_wt(df) - df <- element_to_oxide(df, elements = cols, ...) - }, - oxPatP = { - cols <- intersect( - colnames(get_unit_columns(df, "wtP")), - oxides_data - ) - cols <- conversion_oxides[conversion_oxides[["Oxide"]] %in% cols, ][["Element"]] - - df <- oxide_to_element(df, ...) - df <- wt_to_at(df, elements = cols, ...) - } - ) - - return(df) -} diff --git a/R/ASTR_zzz.R b/R/ASTR_zzz.R deleted file mode 100644 index d575db4..0000000 --- a/R/ASTR_zzz.R +++ /dev/null @@ -1,49 +0,0 @@ -# defining global variables -utils::globalVariables( - c( - # ugly solution to avoid magrittr NOTE - # see http://stackoverflow.com/questions/9439256/ - # how-can-i-handle-r-cmd-check-no-visible-binding-for-global-variable-notes-when - ".", - # register data objects to make lintr aware of them - "isotopes_data", - "elements_data", - "oxides_data", - "special_oxide_states", - "conversion_oxides" - ) -) - -#' @importFrom magrittr "%>%" -#' @importFrom rlang .data := -#' -NULL - -# registers the dimensionless units at% (atom percent) and wt% (weight percent) -# when the package is loaded -.onLoad <- function(libname, pkgname) { - safe_install <- function(...) { - # tryCatch to prevent an error when these units are already defined in - # the current session - tryCatch( - units::install_unit(...), - error = function(e) NULL - ) - } - # define dummy base units (purely semantic) - # see ?units::install_unit for details on this mechanism - safe_install("atomic_basis") - safe_install("mass_basis", "unitless") - # create percent-like units - # the %-sign can not be used in custom unit names, so we use P - safe_install( - symbol = "atP", - def = "0.01 atomic_basis", - name = "atom percent" - ) - safe_install( - symbol = "wtP", - def = "0.01 mass_basis", - name = "weight percent" - ) -} diff --git a/R/ASTR_basic.R b/R/archchem_basic.R similarity index 50% rename from R/ASTR_basic.R rename to R/archchem_basic.R index 1d78077..9423406 100644 --- a/R/ASTR_basic.R +++ b/R/archchem_basic.R @@ -1,124 +1,122 @@ -#' @title ASTR Schema implementation +#' @name archchem +#' @rdname archchem #' -#' @name ASTR -#' @rdname ASTR +#' @title \strong{archchem} #' #' @description A tabular data format for chemical analysis datasets in -#' archaeology, including contextual information, numerical elemental, and -#' isotopic data. Columns are assigned units (using \link[units]{set_units}) -#' and categories (in an attribute `ASTR_class`) based on the column name. The -#' following functions allow to create objects of class `ASTR`, and to -#' interact with them. +#' archaeology, including contextual information, numerical elemental, and +#' isotopic data. Columns are assigned units (using \link[units]{set_units}) and +#' categories (in an attribute `archchem_class`) based on the column name. +#' The following functions allow to create objects of class `archchem`, and to +#' interact with them. #' \itemize{ -#' \item **as_ASTR**: Transforms an R `data.frame` to an object of class -#' `ASTR`. -#' \item **read_ASTR**: Reads data from a file (.csv, .xls, .xlsx) into -#' an object of class `ASTR`. -#' \item **validate**: Performs additional validation on `ASTR` and returns +#' \item **as_archchem**: Transforms an R `data.frame` to an object of class +#' `archchem`. +#' \item **read_archchem**: Reads data from a file (.csv, .xls, .xlsx) into +#' an object of class `archchem`. +#' \item **validate**: Performs additional validation on `archchem` and returns #' a `data.frame` as a workable list of potential issues. -#' \item **get_..._columns**: Subsets `ASTR` tables to columns of a certain -#' category (or `ASTR_class`), e.g. only contextual data columns. +#' \item **get_..._columns**: Subsets `archchem` tables to columns of a certain +#' category (or `archchem_class`), e.g. only contextual data columns. #' \item **remove_units**: Removes unit vector types from the analytical columns -#' in an `ASTR` table and replaces them with simple numeric columns of type +#' in an `archchem` table and replaces them with simple numeric columns of type #' `double`. #' \item **unify_concentration_unit**: Unifies the unit of each concentration column, #' e.g. to either % or ppm (or any SI unit) to avoid mixing units in derived analyses. #' } -#' As `ASTR` is derived from `tibble` it is directly compatible with the data -#' manipulation tools in the tidyverse. +#' As `archchem` is derived from `tibble` it is directly compatible with the +#' data manipulation tools in the tidyverse. #' #' @param df a data.frame containing the input table #' @param path file path (including extension) to the file to read #' @param ... further arguments passed to or from other methods #' @param id_column name of the ID column. Defaults to "ID" #' @param context columns that provide contextual (non-measurement) information; -#' may be column names, integer positions, or a logical inclusion vector +#' may be column names, integer positions, or a logical inclusion vector #' @param bdl strings representing “below detection limit” values. By default, -#' the following are recognized: "b.d.", "bd", "b.d.l.", "bdl", "% -#' magrittr::set_attr("ASTR_class", "ASTR_concentration") +#' conc$Sb_ppb <- units::set_units(arch$Sb_ppm, "ppb") %>% +#' magrittr::set_attr("archchem_class", "archchem_concentration") #' -#' # removing all units from ASTR tables +#' # removing all units from archchem tables #' remove_units(arch) #' -#' # applying tidyverse data manipulation on ASTR tables +#' # applying tidyverse data manipulation on archchem tables #' arch %>% #' dplyr::group_by(Site) %>% -#' dplyr::summarise(mean_Na2O = mean(Na2O)) +#' dplyr::summarise(mean_Na2O = mean(`Na2O_wt%`)) #' conc_subset <- conc %>% -#' dplyr::select(-Sn, -Sb) %>% -#' dplyr::filter(Na2O > units::set_units(4, "wtP")) +#' dplyr::select(-`Sn_µg/ml`, -`Sb_ppm`) %>% +#' dplyr::filter(`Na2O_wt%` > units::set_units(1, "%")) #' #' # unify all concentration units -#' unify_concentration_unit(conc_subset, "ppb") +#' unify_concentration_unit(conc_subset, "ppm") +#' # note that the column names are inaccurate now #' #' @export -as_ASTR <- function( +as_archchem <- function( df, id_column = "ID", context = c(), bdl = c("b.d.", "bd", "b.d.l.", "bdl", "% + df <- df %>% dplyr::mutate(ID = .data[[id_column]]) %>% dplyr::relocate("ID", .before = 1) # handle ID duplicates - if (length(unique(df1$ID)) != nrow(df1)) { + if (length(unique(df$ID)) != nrow(df)) { warning( "Detected multiple data rows with the same ID. They will be renamed ", "consecutively using the following convention: _1, _2, ... _n" ) } - df2 <- df1 %>% + df <- df %>% dplyr::group_by(.data[["ID"]]) %>% dplyr::mutate( - ID = if (dplyr::n() > 1) { - paste0(.data[["ID"]], "_", as.character(dplyr::row_number())) - } else { - .data[["ID"]] - } + ID = dplyr::case_when( + dplyr::n() > 1 ~ paste0(.data[["ID"]], "_", as.character(dplyr::row_number())), + .default = .data[["ID"]] + ) ) %>% dplyr::ungroup() # determine and apply column types - column_table <- parse_colnames(df2, context, drop_columns) - constructors <- build_constructors(column_table, bdl, bdl_strategy, guess_context_type, na) - col_list <- purrr::map2(df2, constructors, function(col, f) f(col)) %>% + constructors <- colnames_to_constructors( + df, context, bdl, bdl_strategy, guess_context_type, na, drop_columns + ) + df <- purrr::map2(df, constructors, function(col, f) f(col)) %>% purrr::discard(is.null) - df3 <- as.data.frame(col_list, check.names = FALSE) - # remove unit names from columns if they got a unit - df4 <- remove_unit_substrings(df3) # turn into tibble-derived object - df5 <- tibble::new_tibble(df4, nrow = nrow(df4), class = "ASTR") + df <- tibble::new_tibble(df, nrow = nrow(df), class = "archchem") # post-reading validation if (validate) { - validation_output <- validate(df5, quiet = FALSE) + validation_output <- validate(df, quiet = FALSE) if (nrow(validation_output) > 0) { warning( "See the full list of validation output with: ", - "ASTR::validate()." + "ASTR::validate()." ) } } - return(df5) + return(df) } -# helper function to rename column names -remove_unit_substrings <- function(x, ...) { - dplyr::rename_with( - x, - remove_suffix, - tidyselect::where(function(y) { - class(y) == "units" && !is_ASTR_class(y, "ASTR_error") - }) - ) +#' @rdname archchem +#' @param quiet ... +#' @export +validate <- function(x, quiet = TRUE, ...) { + UseMethod("validate") } -remove_suffix <- function(colname) { - sub("_.*$", "", colname, perl = TRUE) +#' @export +validate.default <- function(x, quiet = TRUE, ...) { + stop("x is not an object of class archchem") } +#' @export +validate.archchem <- function(x, quiet = TRUE, ...) { + # check for missingness in analytical columns + df_analytical <- get_analytical_columns(x)[-1] + missing_values <- purrr::map2_dfr( + df_analytical, colnames(df_analytical), + function(x, col) { + n_na <- sum(is.na(x)) + if (n_na > 0) { + tibble::tibble( + column = col, + count = n_na, + warning = "missing values" + ) + } + } + ) + if (!quiet && nrow(missing_values) > 0) { + warning( + sum(missing_values$count), + " missing values across ", + nrow(missing_values), + " analytical columns" + ) + } + all_warnings <- dplyr::bind_rows(missing_values) + return(all_warnings) +} + + #' @param path path to the file that should be read #' @param delim A character string with the separator for tabular data. Must be #' provided for all file types except `.xlsx` or `.xls`. Default to `,`. Use @@ -210,9 +232,9 @@ remove_suffix <- function(colname) { #' See their documentation for details: #' * [readxl::read_excel()] for file formats `.xlsx` or `.xls` #' * [readr::read_delim()] for all other file formats. -#' @rdname ASTR +#' @rdname archchem #' @export -read_ASTR <- function( +read_archchem <- function( path, id_column = "ID", context = c(), delim = ",", guess_context_type = TRUE, @@ -234,18 +256,7 @@ read_ASTR <- function( #} if (ext %in% c("xlsx", "xls") && !requireNamespace("readxl")) { - - if (!rlang::is_interactive()) { - stop("Import of Excel files requires the package `readxl`. Please install it or choose another file format.") - } - - answer <- readline("Package `readxl` required to import Excel files. Do you want to install it now? [Y/n]: ") - - if (tolower(answer) %in% c("yes", "y")) { - utils::install.packages("readxl") - } else { - stop("Please import your data in another file format or install 'readxl' manually.") - } + stop("Import of Excel files requires the package `readxl`. Please install it or choose another file format.") } # read input as character columns only @@ -261,7 +272,7 @@ read_ASTR <- function( xls = { readxl::read_xls( path, - col_types = "text", + col_types = "character", na = na, ... ) @@ -279,7 +290,7 @@ read_ASTR <- function( # remove columns without a header dplyr::select(!tidyselect::starts_with("...")) # transform to desired data type - as_ASTR( + as_archchem( input_file, id_column = id_column, context = context, bdl = bdl, bdl_strategy = bdl_strategy, @@ -289,8 +300,8 @@ read_ASTR <- function( ) } -#' @rdname ASTR -#' @param quiet should warnings be printed? Defaults to `TRUE` +#' @rdname archchem +#' @param quiet should warnings be printed? Defaults to TRUE #' @export validate <- function(x, quiet = TRUE, ...) { UseMethod("validate") @@ -298,11 +309,11 @@ validate <- function(x, quiet = TRUE, ...) { #' @export validate.default <- function(x, quiet = TRUE, ...) { - stop("x is not an object of class ASTR") + stop("x is not an object of class archchem") } #' @export -validate.ASTR <- function(x, quiet = TRUE, ...) { +validate.archchem <- function(x, quiet = TRUE, ...) { # check for missingness in analytical columns df_analytical <- get_analytical_columns(x)[-1] missing_values <- purrr::map2_dfr( @@ -330,13 +341,13 @@ validate.ASTR <- function(x, quiet = TRUE, ...) { return(all_warnings) } -#' @param x an object of class ASTR -#' @rdname ASTR +#' @param x an object of class archchem +#' @rdname archchem #' @export -format.ASTR <- function(x, ...) { +format.archchem <- function(x, ...) { out_str <- list() # compile information - out_str$title <- "\033[1mASTR table\033[22m" + out_str$title <- "\033[1marchchem table\033[22m" # analytical columns x_analytical <- colnames(get_analytical_columns(x)) if (length(x_analytical[-1]) > 0) { @@ -363,9 +374,9 @@ add_color <- function(x, col) { paste0("\033[0;", col, "m", x, "\033[0m") } -#' @rdname ASTR +#' @rdname archchem #' @export -print.ASTR <- function(x, ...) { +print.archchem <- function(x, ...) { # own format function cat(format(x, ...), "\n") # add table printed like a tibble @@ -374,39 +385,38 @@ print.ASTR <- function(x, ...) { print() } -#### adjustments to preserve ASTR properties with different dplyr verbs #### +#### adjustments to preserve archchem properties with different dplyr verbs #### # see ?dplyr_extending -# carry over ASTR_class column attribute -preserve_ASTR_attrs <- function(modified, original) { - for (nm in intersect(names(modified), names(original))) { - arch_attr <- attr(original[[nm]], "ASTR_class") - if (!is.null(arch_attr)) { - attr(modified[[nm]], "ASTR_class") <- arch_attr - } - } - tibble::new_tibble(modified, class = class(original)) +# carry over archchem_class column attribute +preserve_archchem_attrs <- function(modified, original) { + purrr::map2(modified, original, function(new_col, old_col) { + arch_attr <- attr(old_col, "archchem_class") + if (!is.null(arch_attr)) attr(new_col, "archchem_class") <- arch_attr + new_col + }) %>% + magrittr::set_names(names(modified)) %>% + tibble::new_tibble(nrow = nrow(modified), class = class(original)) } # row-slice method #' @exportS3Method dplyr::dplyr_row_slice -dplyr_row_slice.ASTR <- function(data, i, ...) { - sliced <- purrr::map(data, vctrs::vec_slice, i = i) - sliced_tbl <- tibble::new_tibble(sliced, class = class(data)) - preserve_ASTR_attrs(sliced_tbl, data) +dplyr_row_slice.archchem <- function(data, i, ...) { + sliced <- purrr::map(data, function(x) x[i]) + sliced_tbl <- tibble::new_tibble(sliced, nrow = length(i), class = class(data)) + preserve_archchem_attrs(sliced_tbl, data) } # column modification method #' @exportS3Method dplyr::dplyr_col_modify -dplyr_col_modify.ASTR <- function(data, cols) { +dplyr_col_modify.archchem <- function(data, cols) { modified_list <- utils::modifyList(as.list(data), cols) - modified_tbl <- tibble::new_tibble(modified_list, class = class(data)) - preserve_ASTR_attrs(modified_tbl, data) + modified_tbl <- tibble::new_tibble(modified_list, nrow = nrow(data), class = class(data)) + preserve_archchem_attrs(modified_tbl, data) } - # final reconstruction #' @exportS3Method dplyr::dplyr_reconstruct -dplyr_reconstruct.ASTR <- function(data, template) { - preserve_ASTR_attrs(data, template) +dplyr_reconstruct.archchem <- function(data, template) { + tibble::new_tibble(data, nrow = nrow(data), class = class(template)) } diff --git a/R/archchem_colname_parser.R b/R/archchem_colname_parser.R new file mode 100644 index 0000000..77bf2c0 --- /dev/null +++ b/R/archchem_colname_parser.R @@ -0,0 +1,268 @@ +#### column type constructor mechanism #### + +# define the correct constructor function for an archchem column +# based on some clever parsing of the column name +# SI-unit column types are defined with the units package +# https://cran.r-project.org/web/packages/units/index.html +# (so the udunits library) +colnames_to_constructors <- function( + x, + context, + bdl, bdl_strategy, + guess_context_type, na, + drop_columns +) { + purrr::imap( + colnames(x), + function(colname, idx) { + # use while for hacky switch statement + while (TRUE) { + # ID column + if (colname == "ID") { + return( + function(x) { + x <- add_archchem_class(x, "archchem_id") + return(x) + } + ) + break + } + # contextual columns + if (idx %in% context || colname %in% context) { + return( + function(x) { + if (guess_context_type && is.character(x)) { + x <- readr::parse_guess(x, na = na) + } + x <- add_archchem_class(x, "archchem_context") + return(x) + } + ) + break + } + # error columns + if (is_err(colname)) { + return( + function(x) { + x <- apply_bdl_strategy(x, colname, bdl, bdl_strategy) + x <- as_numeric_info(x, colname) + x <- add_archchem_class(x, c("archchem_error")) + } + ) + } + # ratios + if (is_isotope_ratio(colname)) { + return( + function(x) { + x <- as_numeric_info(x, colname) + x <- add_archchem_class(x, c("archchem_isotope", "archchem_ratio")) + return(x) + } + ) + break + } + if (is_isotope_delta_epsilon(colname)) { + # delta_epsilon <- extract_delta_epsilon_string(colname) + return( + function(x) { + # if (delta_epsilon == "d") { + # x / 10 # per mille -> percent + # } else if (delta_epsilon == "e") { + # x / 100 # parts per 10000 -> percent + # } + x <- as_numeric_info(x, colname) + x <- add_archchem_class(x, c("archchem_isotope", "archchem_ratio")) + return(x) + } + ) + break + } + if (is_elemental_ratio(colname)) { + return( + function(x) { + x <- as_numeric_info(x, colname) + x <- add_archchem_class(x, c("archchem_element", "archchem_ratio")) + return(x) + } + ) + break + } + # concentrations + if (is_concentration(colname)) { + unit_from_col <- extract_unit_string(colname) + # handle special cases + unit_from_col <- dplyr::case_match( + unit_from_col, + c("at%", "wt%") ~ "%", + c("cps") ~ "count/s", + .default = unit_from_col + ) + return( + function(x) { + x <- apply_bdl_strategy(x, colname, bdl, bdl_strategy) + x <- as_numeric_info(x, colname) + x <- units::set_units(x, value = unit_from_col, mode = "standard") + x <- add_archchem_class(x, c("archchem_concentration")) + return(x) + } + ) + break + } + # handle everything not recognized by the parser: + m <- paste0( + "Column name \"", + colname, + "\" could not be parsed. ", + "Either analytical columns do not conform to ASTR conventions or ", + "contextual columns are not specified as such." + ) + if (drop_columns) { + warning(m) + return(function(x) { + NULL + }) + } else { + stop(m) + } + } + } + ) +} + +add_archchem_class <- function(x, class) { + attr(x, "archchem_class") <- class + return(x) +} + +as_numeric_info <- function(x, colname) { + withCallingHandlers( + y <- as.numeric(x), + warning = function(w) { + message <- conditionMessage(w) + warning( + paste0( + "Issue when transforming column \"", colname, "\" to numeric values: " + ), + message, + call. = FALSE + ) + tryInvokeRestart("muffleWarning") + } + ) + return(y) +} + +# colname only an argument in case we want to implement more specific handling +# eventually +apply_bdl_strategy <- function(x, colname, bdl, bdl_strategy) { + bdl_values <- which(grepl(paste(bdl, collapse = "|"), x, perl = FALSE)) + x[bdl_values] <- bdl_strategy() + return(x) +} + +#### regex validators #### + +is_err <- function(colname) { + grepl(err(), colname, perl = TRUE) +} +is_isotope_ratio <- function(colname) { + grepl(isotope_ratio(), colname, perl = TRUE) +} +is_isotope_delta_epsilon <- function(colname) { + grepl(isotope_delta_epsilon(), colname, perl = TRUE) +} +is_elemental_ratio <- function(colname) { + grepl(elemental_ratio(), colname, perl = TRUE) +} +is_concentration <- function(colname) { + grepl(concentration(), colname, perl = TRUE) +} +extract_unit_string <- function(colname) { + pos <- regexpr("(?<=_).*", colname, perl = TRUE) + regmatches(colname, pos) +} +extract_delta_epsilon_string <- function(colname) { + substr(colname, 1, 1) +} + +#### regex patterns #### + +# collate vectors to string with | to indicate OR in regex +isotopes_list <- function() { + paste0(isotopes, collapse = "|") +} +elements_list <- function() { + paste0(elements, collapse = "|") +} +oxides_list <- function() { + all_oxide_like_states <- c(oxides, special_oxide_states) + paste0(all_oxide_like_states, collapse = "|") +} +ox_elem_list <- function() paste0(oxides_list(), "|", elements_list()) +ox_elem_iso_list <- function() paste0(ox_elem_list(), "|", isotopes_list()) + +# special_type_list <- function() { +# paste0(c( +# "wt%", "at%", "w/w%" +# #"ppm", "ppb", "ppt", "%", , +# #"\u2030" # for the per-mille symbol +# ), collapse = "|") +# } + +# define regex pattern for isotope ratio: +# any isotope followed by a / and another isotope, e.g. 206Pb/204Pb +isotope_ratio <- function() { + paste0("(", isotopes_list(), ")/(", isotopes_list(), ")") +} + +# define regex pattern for delta and espilon notation: +# letter d OR e followed by any isotope +isotope_delta_epsilon <- function() { + paste0( + "(", paste0(c("d", "e"), collapse = "|"), + ")(", isotopes_list(), ")" + ) +} + +# error states +err <- function() { + paste0(c( + err_2sd(), err_sd(), + err_2sd_percent(), err_sd_percent(), + err_2se(), err_se() + ), collapse = "|") +} +err_2sd <- function() "\\_err2SD" +err_sd <- function() "\\_errSD" +err_2sd_percent <- function() "\\_err2SD%" +err_sd_percent <- function() "\\_errSD%" +err_2se <- function() "\\_err2SE" +err_se <- function() "\\_errSE" + +# define regex pattern for element ratios: +# any combination of two elements or oxides connected by + , - or / that may or +# may not be enclosed in parentheses followed by a / and any combination of two +# elements or oxides connected by +, -, or / that may or may not be enclosed in +# parentheses, e.g. Sb/As, SiO2/Feo, (Al2O3+SiO2)/(K2O-Na20), (Feo/Mno)/(SiO2) +elemental_ratio <- function() { + paste0( + "\\(?(", ox_elem_list(), ")([\\+-/](", + ox_elem_list(), "))?\\)?/\\(?(", + ox_elem_list(), ")([\\+-/](", + ox_elem_list(), "))?\\)?" + ) +} + +# define regex pattern for concentrations: +# any combination of one or more elements, isotopes, or oxides connected by +# + or - and followed by an underscore that may or may be enclosed in +# parentheses, e.g. Sb_, Feo+SiO2_, (Al2O3+SiO2)_ +# The underscore enforces that concentrations always have a unit and prevents +# partial matching in elemental ratios +concentration <- function() { + paste0( + "^\\(?(", + ox_elem_iso_list(), ")(?!/)((\\+|-)(", + ox_elem_iso_list(), "))*\\)?_" + ) +} diff --git a/R/archchem_column_select.R b/R/archchem_column_select.R new file mode 100644 index 0000000..452badf --- /dev/null +++ b/R/archchem_column_select.R @@ -0,0 +1,81 @@ +# functions to select sets of columns for archchem tables + +is_archchem_class <- function(x, classes) { + any(attr(x, "archchem_class") %in% classes) +} + +get_cols_with_ac_class <- function(x, classes) { + dplyr::select(x, tidyselect::where( + function(y) { + is_archchem_class(y, classes) + } + )) +} + +get_cols_without_ac_class <- function(x, classes) { + dplyr::select(x, tidyselect::where( + function(y) { + !is_archchem_class(y, classes) + } + )) +} + +#' @rdname archchem +#' @export +get_contextual_columns <- function(x, ...) { + UseMethod("get_contextual_columns") +} +#' @export +get_contextual_columns.archchem <- function(x, ...) { + get_cols_with_ac_class(x, c("archchem_id", "archchem_context")) +} + +#' @rdname archchem +#' @export +get_analytical_columns <- function(x, ...) { + UseMethod("get_analytical_columns") +} +#' @export +get_analytical_columns.archchem <- function(x, ...) { + get_cols_without_ac_class(x, "archchem_context") +} + +#' @rdname archchem +#' @export +get_isotope_columns <- function(x, ...) { + UseMethod("get_isotope_columns") +} +#' @export +get_isotope_columns.archchem <- function(x, ...) { + get_cols_with_ac_class(x, c("archchem_id", "archchem_isotope")) +} + +#' @rdname archchem +#' @export +get_element_columns <- function(x, ...) { + UseMethod("get_element_columns") +} +#' @export +get_element_columns.archchem <- function(x, ...) { + get_cols_with_ac_class(x, c("archchem_id", "archchem_element")) +} + +#' @rdname archchem +#' @export +get_ratio_columns <- function(x, ...) { + UseMethod("get_ratio_columns") +} +#' @export +get_ratio_columns.archchem <- function(x, ...) { + get_cols_with_ac_class(x, c("archchem_id", "archchem_ratio")) +} + +#' @rdname archchem +#' @export +get_concentration_columns <- function(x, ...) { + UseMethod("get_concentration_columns") +} +#' @export +get_concentration_columns.archchem <- function(x, ...) { + get_cols_with_ac_class(x, c("archchem_id", "archchem_concentration")) +} diff --git a/R/archchem_unit_manipulation.R b/R/archchem_unit_manipulation.R new file mode 100644 index 0000000..ffecdd6 --- /dev/null +++ b/R/archchem_unit_manipulation.R @@ -0,0 +1,38 @@ +#' @rdname archchem +#' @export +remove_units <- function(x, ...) { + UseMethod("remove_units") +} +#' @export +remove_units.archchem <- function(x, ...) { + dplyr::mutate( + x, + dplyr::across( + tidyselect::where(function(y) { + class(y) == "units" + }), + units::drop_units + ) + ) +} + +#' @rdname archchem +#' @param unit string with a unit definition that can be understood by +#' \link[units]{set_units}, e.g. "%", "kg", or "m/s^2" +#' @export +unify_concentration_unit <- function(x, unit, ...) { + UseMethod("unify_concentration_unit") +} +#' @export +unify_concentration_unit <- function(x, unit, ...) { + dplyr::mutate( + x, + dplyr::across( + tidyselect::where(function(y) { + class(y) == "units" && + is_archchem_class(y, "archchem_concentration") + }), + function(z) units::set_units(z, unit, mode = "standard") + ) + ) +} diff --git a/R/data.R b/R/data.R new file mode 100644 index 0000000..7a5ecaa --- /dev/null +++ b/R/data.R @@ -0,0 +1,72 @@ +#' Elements +#' +#' List of elements, sorted according to alphabet +#' +#' @format a vector +#' +#' @family chemical_reference_data +#' @name elements +"elements" + +#' Oxides +#' +#' List of oxides, retrieved from https://www.wikidoc.org/index.php/Oxide, +#' sorted according to alphabet +#' +#' @format a vector +#' +#' @family chemical_reference_data +#' @name oxides +"oxides" + +#' Isotopes +#' +#' List of naturally occurring isotopes, retrieved from https://www.ciaaw.org/isotopic-abundances.htm, +#' sorted according to chemical element and isotope number +#' +#' @format a vector +#' +#' @family chemical_reference_data +#' @name isotopes +"isotopes" + +#' archchem_example_input +#' +#' A dataset that contains fictitious data mimicking lead slags +#' including composition, isotopic, and contextual information. +#' The variable names conform to ASTR conventions (see "ASTR Schema" vignette). +#' +#' \itemize{ +#' \item Sample. Individual samples for which compositional and isotopic data, +#' and contextual information is provided in this dataset. +#' \item Lab.no, Site, latitude, longitude, Type, method_comp. Columns containing +#' contextual information on the samples. +#' \item 143Nd/144Nd, d65Cu, d65Cu_err2SD, 206Pb/204Pb, 206Pb/204Pb_err2SD, +#' 207Pb/204Pb, 207Pb/204Pb_err2SD, 208Pb/204Pb, 208Pb/204Pb_err2SD,207Pb/206Pb, +#' 207Pb/206Pb_err2SD,208Pb/206Pb, 208Pb/206Pb_err2SD. Columns containing isotopic data. +#' \item Na2O_wt%, BaO_wt%, Pb_wt%, MgO_wt%, Al2O3_wt%, SiO2_wt%, SiO2_errSD%, +#' P2O5_wt%, S_at%, CaO_wt%,TiO2_wt%, MnO_wt%, FeOtot_wt%, FeOtot_err2SD, ZnO%, +#' K2O_wt%, Cu_wt%, As_wt%, LOI_wt%, Ag_ppb, Sn_µg/ml, Sb_ppm, Te_ppm, Bi_ppm, +#' U_ppm, V_ppm, Cr_ppm, Co_ppm, Ni_ppm, Sr_ppm, Se_ppm, FeOtot/SiO2, (Na2O+K2O)/SiO2. +#' Columns containing compositional data. +#' } +#' +#' @docType data +#' @keywords datasets +#' @name archchem_example_input +#' @usage data(archchem_example_input) +#' @format A data frame with 15 observations and 53 variables. +#' +"archchem_example_input" + +#' ArgentinaDatabase +#' +#' Lead isotope data from ore deposits in Argentina prepared for TerraLID database. +#' +#' @format ## `ArgentinaDatabase` +#' +#' A dataframe with 112 rows and 49 columns +#' +#' @source +#' @name ArgentinaDatabase +"ArgentinaDatabase" diff --git a/R/ASTR_geom_kde2.R b/R/geom_kde2.R similarity index 98% rename from R/ASTR_geom_kde2.R rename to R/geom_kde2.R index fcbe08c..727f3b5 100644 --- a/R/ASTR_geom_kde2.R +++ b/R/geom_kde2.R @@ -1,4 +1,4 @@ -#' Draw 2D kernel density estimate polygons by quantiles +#' Draw 2D Kernel Density Estimate Polygons by Quantiles #' #' @description #' This geom creates polygons based on a 2D kernel density estimate, which is @@ -17,7 +17,7 @@ #' quantile to be drawn. The default, `0.02`, helps avoid creating #' polygons around single outlier points. #' @param fallback_to_points Logical. To prevent points from being drawn for -#' groups that fail density estimation, set this to `FALSE`. For example, if you +#' groups that fail density estimation, set this to FALSE. For example, if you #' want more control over the point aesthetics, independent of the KDE regions, #' set this to FALSE and use geom_point to plot those points #' @param ... Other arguments passed on to [ggplot2::layer()]. These are @@ -87,7 +87,6 @@ #' ggplot(df, aes(x, y, fill = group, colour = group)) + #' geom_kde2d(alpha = 0.4) + #' theme_minimal() - geom_kde2d <- function(mapping = NULL, data = NULL, inherit.aes = TRUE, diff --git a/R/ASTR_pointcloud_distribution.R b/R/pointcloud_distribution.R similarity index 78% rename from R/ASTR_pointcloud_distribution.R rename to R/pointcloud_distribution.R index 7a996c1..3e1cf2b 100644 --- a/R/ASTR_pointcloud_distribution.R +++ b/R/pointcloud_distribution.R @@ -1,4 +1,4 @@ -#' Comparing isotope samples to reference data in 3D space +#' Comparing Isotope Samples to Reference Data in 3D Space #' #' This package compares isotope samples to reference data in 3D space to #' identify isotopic consistency and the possibility of mixing between sources. @@ -10,37 +10,35 @@ #' @param isotope_sample,isotope_ref Character vectors with column names of #' isotope ratios. Default to `c("206Pb/204Pb", "207Pb/204Pb", #' "208Pb/204Pb")`. -#' @param id_sample String with the column name of the sample IDs. Default is -#' `ID` -#' @param id_ref String with the column name of the variable used for subsetting -#' the reference data. Default is "ID". +#' @param id_sample,id_ref String with the column name of the sample IDs and +#' identifier for the reference groups. Default `ID`. #' #' @returns A `list` of three elements: #' #' * in_hull: `logical`. Boolean value indicating the **inclusion** of sample -#' data within the convex **hull** of the reference data. +#' data within the convex **hull** of the reference data. #' * centroids: `data.frame`. The coordinates of the **centroids** (mean values) -#' for each defined reference group. +#' for each defined reference group. #' * distances: `matrix`. A distance **matrix** where rows represent the samples -#' and columns represent the reference **centroids**, containing the distance -#' of each sample from each centroid. +#' and columns represent the reference **centroids**, containing the distance +#' of each sample from each centroid. #' #' @details Calculates the **convex hull** for the complete set of reference -#' points and all specified **subgroups**. It determines the inclusion or -#' exclusion of sample **isotope values** within these hulls. +#' points and all specified **subgroups**. It determines the inclusion or +#' exclusion of sample **isotope values** within these hulls. #' -#' The function also calculates: +#' The function also calculates: #' * The **centroid** of each reference subgroup as **mean value** of points -#' within each vertex group. +#' within each vertex group. #' * The **distance** from each sample point to every subgroup's centroid. #' -#' Interpretation: Inclusion within a hull suggests the sample is part of the -#' **mixing group** (main hull) or is highly likely to be the specific **end -#' member** (subgroup hull). The distance calculation provides a measure of -#' proximity to these end member centers. +#' Interpretation: Inclusion within a hull suggests the sample is part of +#' the **mixing group** (main hull) or is highly likely to be the specific **end +#' member** (subgroup hull). The distance calculation provides a measure of +#' proximity to these end member centers. #' #' @importFrom geometry convhulln inhulln -#' @importFrom rdist cdist +#' @importFrom rdist cdist #' @importFrom stats aggregate as.formula #' #' @export @@ -81,10 +79,15 @@ pointcloud_distribution <- function(df, "208Pb/204Pb"), isotope_ref = isotope_sample, id_sample = "ID", - id_ref = "ID") { + id_ref = id_sample) { # Checks for isotope columns - checkmate::assert_character(isotope_sample, len = 3) - checkmate::assert_character(isotope_ref, len = 3) + if (length(isotope_sample) != 3) { + stop("isotope_sample must have exactly 3 values.") + } + + if (length(isotope_ref) != 3) { + stop("isotope_ref must have exactly 3 values.") + } # Checks for Sample ID cols if (!(id_sample %in% names(df))) { diff --git a/R/sysdata.rda b/R/sysdata.rda new file mode 100644 index 0000000..9420ba2 Binary files /dev/null and b/R/sysdata.rda differ diff --git a/R/ASTR_utils.R b/R/utils.R similarity index 69% rename from R/ASTR_utils.R rename to R/utils.R index 7bf5198..e85ef28 100644 --- a/R/ASTR_utils.R +++ b/R/utils.R @@ -60,30 +60,3 @@ return_numeric_columns <- function(df, columns, all = FALSE) { } df[columns] } - -#' Transform unit in ratio notation into notation with negative exponents -#' -#' This is necessary to align with output of units from [units::deparse_unit()]. -#' Example: m/s2 -> m s-2 -#' -#' @param unit Character string -#' @keywords internal -#' -transform_notation <- function(unit) { - checkmate::assert_character(unit, len = 1) - - unit <- unlist(strsplit(unit, "/")) - if (length(unit) == 2) { - unit[3] <- sub("[[:alpha:]]*", "", unit[2]) - if (unit[3] == "") { - unit[3] <- "1" - } - unit[2] <- sub("[[:digit:]]*$", "", unit[2]) - unit[2] <- paste0(unit[2:3], collapse = "-") - unit <- paste0(unit[1:2], collapse = " ") - } - if (length(unit) > 2) { - stop("This unit cannot be converted into a format with negative exponents. Please provide it in the proper format.") - } - unit -} diff --git a/R/zzz.R b/R/zzz.R new file mode 100644 index 0000000..1da2d4b --- /dev/null +++ b/R/zzz.R @@ -0,0 +1,10 @@ +# defining global variables +# ugly solution to avoid magrittr NOTE +# see http://stackoverflow.com/questions/9439256/ +# how-can-i-handle-r-cmd-check-no-visible-binding-for-global-variable-notes-when +globalVariables(".") + +#' @importFrom magrittr "%>%" +#' @importFrom rlang .data +#' +NULL diff --git a/README.Rmd b/README.Rmd index fe0d0dd..688c9bb 100644 --- a/README.Rmd +++ b/README.Rmd @@ -13,77 +13,22 @@ knitr::opts_chunk$set( ) ``` -# ASTR (Archaemetric Standards and Tools in R) +# ASTR [![R-CMD-check](https://github.com/archaeothommy/ASTR/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/archaeothommy/ASTR/actions/workflows/R-CMD-check.yaml) -[![CRAN status](https://www.r-pkg.org/badges/version/ASTR)](https://CRAN.R-project.org/package=ASTR) [![Codecov test coverage](https://codecov.io/gh/archaeothommy/ASTR/graph/badge.svg)](https://codecov.io/gh/archaeothommy/ASTR) -ASTR defines and implements a community reporting standard for archaeometric datasets. It also provides easy-to-use functions for common plots, statistical analyses, data processing, and data transformation workflows in archaeometry. - -## Overview - -ASTR aims to increase reproducibility of data processing by facilitating the use of scripting languages in archeometry in the narrower sense, i.e., the material scientific investigation of usually inorganic archaeological materials. - -### Community reporting standard - -The community reporting standard defines a [set of conventions on the structure and naming of datasets](vignettes/VG.ASTRschema.0.0.2.Rmd) to make them interoperable and allow automated handling of the data. Based on these conventions, ASTR - -* Recognises and seamlessly isotopic and chemical data, their units, and analytical precision, -* Handles unit conversion on the fly, including non-SI units such as *ppm*, *at%*, and *cps* (counts per second) and between oxides and elements - -### Tools - -The collection provides easy-to-use functions for a wide range of tasks such as - -* [ggplot2](https://ggplot2.tidyverse.org/) geoms for standard plots (e.g., spidergrams, KDE) -* Material classification (e.g., copper types) -* Data transformation and processing (e.g., calculation of δ-values from standard-sample-bracketing measurements) -* Data conversion (e.g., calculation of lead isotope age model parameters) -* Statistics (e.g. distribution of data in a pointcloud of reference data) -* Normalisation of data to standard compositions (e.g., chondritic composition) -* Unit conversion (e.g., at% to wt% and vice versa) - -See the full list on the [package website](https://archaeothommy.github.io/ASTR/index.html). - -Functions do not expect datasets according to the community reporting standard but default values for their input follow its conventions, making them particularly easy to use. - - +The goal of ASTR is to ... ## Installation You can install the development version of ASTR from [GitHub](https://github.com/) with: -``` {r, eval = FALSE} - install.packages("pak") - pak::pak("archaeothommy/ASTR") +``` r +# install.packages("pak") +#pak::pak("archaeothommy/ASTR") ``` -## Getting started - -We recommend reading the following resources to become familiar with the package: - -* Community reporting standard: [Conventions](vignettes/VG.ASTRschema.0.0.2.Rmd) and their [explanation](vignettes/VG.ASTR.Conventions.explained.Rmd) - -## Contributing and Code of Conduct - -Please read our [contributor guide](https://archaeothommy.github.io/ASTR/CONTRIBUTING.html) to learn how to contribute to ASTR. The ASTR project is released with a [Contributor Code of Conduct](https://archaeothommy.github.io/ASTR/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. - -## Acknowledgements and funding - -ASTR was initiated in the workshop *Towards an Archaeological Science Toolbox in R “ASTR”* at the [Lorentz Center](https://www.lorentzcenter.nl/) in Leiden (The Netherlands). In addition to the in-kind funding of the Lorentz Center, the workshop received funding from the Stichting Nederlands Museum voor Anthropologie en Praehistorie (Foundation for Anthropology and Prehistory in the Netherlands). The workshop and further development of ASTR received funding from the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) – project 571205551. diff --git a/README.md b/README.md index 8a8d080..88e8bfc 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,17 @@ -# ASTR (Archaeometric Standards and Tools in R) +# ASTR [![R-CMD-check](https://github.com/archaeothommy/ASTR/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/archaeothommy/ASTR/actions/workflows/R-CMD-check.yaml) -[![CRAN -status](https://www.r-pkg.org/badges/version/ASTR)](https://CRAN.R-project.org/package=ASTR) [![Codecov test coverage](https://codecov.io/gh/archaeothommy/ASTR/graph/badge.svg)](https://codecov.io/gh/archaeothommy/ASTR) -ASTR defines and implements a community reporting standard for -archaeometric datasets. It also provides easy-to-use functions for -common plots, statistical analyses, data processing, and data -transformation workflows in archaeometry. - -## Overview - -ASTR aims to increase reproducibility of data processing by facilitating -the use of scripting languages in archeometry in the narrower sense, -i.e., the material scientific investigation of usually inorganic -archaeological materials. - -### Community reporting standard - -The community reporting standard defines a [set of conventions on the -structure and naming of datasets](vignettes/VG.ASTRschema.0.0.2.Rmd) to -make them interoperable and allow automated handling of the data. Based -on these conventions, ASTR - -- Recognises and seamlessly isotopic and chemical data, their units, and - analytical precision, -- Handles unit conversion on the fly, including non-SI units such as - *ppm*, *at%*, and *cps* (counts per second) and between oxides and - elements - -### Tools - -The collection provides easy-to-use functions for a wide range of tasks -such as - -- [ggplot2](https://ggplot2.tidyverse.org/) geoms for standard plots - (e.g., spidergrams, KDE) -- Material classification (e.g., copper types) -- Data transformation and processing (e.g., calculation of δ-values from - standard-sample-bracketing measurements) -- Data conversion (e.g., calculation of lead isotope age model - parameters) -- Statistics (e.g. distribution of data in a pointcloud of reference - data) -- Normalisation of data to standard compositions (e.g., chondritic - composition) -- Unit conversion (e.g., at% to wt% and vice versa) - -See the full list on the [package -website](https://archaeothommy.github.io/ASTR/index.html). - -Functions do not expect datasets according to the community reporting -standard but default values for their input follow its conventions, -making them particularly easy to use. - - +The goal of ASTR is to … ## Installation @@ -79,36 +19,6 @@ You can install the development version of ASTR from [GitHub](https://github.com/) with: ``` r - install.packages("pak") - pak::pak("archaeothommy/ASTR") +# install.packages("pak") +#pak::pak("archaeothommy/ASTR") ``` - -## Getting started - -We recommend reading the following resources to become familiar with the -package: - -- Community reporting standard: - [Conventions](vignettes/VG.ASTRschema.0.0.2.Rmd) and their - [explanation](vignettes/VG.ASTR.Conventions.explained.Rmd) - -## Contributing and Code of Conduct - -Please read our [contributor -guide](https://archaeothommy.github.io/ASTR/CONTRIBUTING.html) to learn -how to contribute to ASTR. The ASTR project is released with a -[Contributor Code of -Conduct](https://archaeothommy.github.io/ASTR/CODE_OF_CONDUCT.html). By -contributing to this project, you agree to abide by its terms. - -## Acknowledgements and funding - -ASTR was initiated in the workshop *Towards an Archaeological Science -Toolbox in R “ASTR”* at the [Lorentz -Center](https://www.lorentzcenter.nl/) in Leiden (The Netherlands). In -addition to the in-kind funding of the Lorentz Center, the workshop -received funding from the Stichting Nederlands Museum voor Anthropologie -en Praehistorie (Foundation for Anthropology and Prehistory in the -Netherlands). The workshop and further development of ASTR received -funding from the Deutsche Forschungsgemeinschaft (DFG, German Research -Foundation) – project 571205551. diff --git a/_pkgdown.yml b/_pkgdown.yml index f99197d..ea4603c 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,12 +1,9 @@ url: https://archaeothommy.github.io/ASTR/ home: - title: 'ASTR: Archaeometric Standards and Tools in R' + title: 'ASTR: Archaeological Science Toolbox in R' description: | - ASTR defines and implements a community reporting standard for archaeometric - datasets. It also provides easy-to-use functions for common plots, - statistical analyses, data processing, and data transformation workflows - in archaeometry. + coming soon template: bootstrap: 5 @@ -17,63 +14,12 @@ navbar: left: [reference, articles, news] right: [search, github] -reference: -- title: ASTR objects - desc: > - Functions for creating and handling ASTR objects. - contents: - - ASTR -- title: Data subsetting - desc: > - Pre-compiled lists for easier subsetting of data - contents: - - isotopes_data - - elements_data - - oxides_data - - special_oxide_states -- title: Unit conversions - desc: > - Functions and data tables for conversions between untis not covered in - {units} - contents: - - atomic_conversion - - oxide_conversion - - conversion_oxides -- title: Calculations, Classifications, Statistics - desc: > - Functions for data transformation - contents: - - copper_alloy_bb - - copper_alloy_pollard - - copper_group_bray - - age_models - - pointcloud_distribution -- title: Visualisation - desc: > - Functions for plotting data - contents: - - geom_kde2d - - geom_sk_lines -- title: Data - desc: > - Datasets included in the package - contents: - - ArgentinaDatabase - -articles: -- title: ASTR schema - navbar: ASTR schema - desc: > - These articles describe the ASTR schema, its implementation, and how to - work with ASTR objects. - contents: - - VG.ASTR.Schema.0.0.2 - - VG.ASTR.Conventions.explained - - VG.ASTR.Schema.Implementation - - ASTR.showcase -- title: Specific functions - navbar: Specific functions - desc: > - These articles illustrate the use of specific functions in the package. - contents: - - KDE2_vignette +# reference: +# - title: "Data import and export" +# desc: > +# Functions to import and export data +# contents: +# - +# - title: ... +# see https://pkgdown.r-lib.org/articles/pkgdown.html#reference for further details +# repeat for articles and other section, see e.g. https://github.com/r-lib/usethis/blob/main/_pkgdown.yml diff --git a/data-raw/.DS_Store b/data-raw/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/data-raw/.DS_Store differ diff --git a/data-raw/data_prep.R b/data-raw/data_prep.R index 3af47f3..22c9553 100644 --- a/data-raw/data_prep.R +++ b/data-raw/data_prep.R @@ -2,24 +2,43 @@ #### chemical reference data #### -conversion_oxides <- read.csv( - file = "data-raw/oxide_conversion.csv", - na.strings = "", - stringsAsFactors = FALSE +elements <- c( + # sorted according to alphabet + "Ac", "Ag", "Al", "Am", "Ar", "As", "At", "Au", "B", "Ba", "Be", "Bh", "Bi", + "Bk", "Br", "C", "Ca", "Cd", "Ce", "Cf", "Cl", "Cm", "Co", "Cr", "Cs", "Cu", + "Ds", "Db", "Dy", "Er", "Es", "Eu", "F", "Fe", "Fm", "Fr", "Ga", "Gd", "Ge", + "H", "He", "Hf", "Hg", "Ho", "Hs", "I", "In", "Ir", "K", "Kr", "La", "Li", + "Lr", "Lu", "Md", "Mg", "Mn", "Mo", "Mt", "N", "Na", "Nb", "Nd", "Ne", "Ni", + "No", "Np", "O", "Os", "P", "Pa", "Pb", "Pd", "Pm", "Po", "Pr", "Pt", "Pu", + "Ra", "Rb", "Re", "Rf", "Rg", "Rh", "Rn", "Ru", "S", "Sb", "Sc", "Se", "Sg", + "Si", "Sm", "Sn", "Sr", "Ta", "Tb", "Tc", "Te", "Th", "Ti", "Tl", "Tm", "U", + "V", "W", "Xe", "Y", "Yb", "Zn", "Zr" ) -elements_data <- unique(conversion_oxides$Element) - -oxides_data <- na.omit(unique(conversion_oxides$Oxide)) +oxides <- c( + # retrieved from https://www.wikidoc.org/index.php/Oxide, + # sorted according to alphabet + "Ag2O", "AgO", "Al2O3", "AlO", "As2O3", "As2O5", "Au2O3", "B2O3", "BaO", "BeO", + "Bi2O3", "C2O", "CaO", "CdO", "CeO2", "Cl2O", "Cl2O7", "ClO2", "CO", "CO2", + "CO3", "CoO", "Cr2O3", "CrO2", "CrO3", "Cu2O", "CuO", "Er2O3", "Fe2O3", + "FeO", "Ga2O3", "Gd2O3", "GeO2", "H2O", "HfO2", "HgO", "Ho2O3", "In2O3", + "K2O", "La2O3", "Li2O", "Lu2O3", "MgO", "Mn2O7", "MnO", "MnO2", "MoO3", "N2O3", + "N2O4", "N2O5", "Na2O", "Ni2O3", "Ni2O5", "NiO", "NO", "NO2", "O4", "OF2", + "OsO4", "P2O5", "P4O6", "PbO", "PbO2", "PdO", "Pm2O3", "PuO2", "Rb2O", + "Re2O7", "ReO3", "Rh2O3", "RuO2", "RuO4", "Sb2O3", "Sb2O5", "Sc2O3", "SeO2", + "SeO3", "SiO2", "Sm2O3", "SnO", "SnO2", "SO", "SO2", "SO3", "SrO", "Ta2O5", + "Tb2O3", "TeO2", "TeO3", "ThO2", "Ti2O3", "TiO", "TiO2", "Tl2O", "Tl2O3", + "Tm2O3", "UO2", "UO3", "V2O3", "V2O5", "VO", "VO2", "W2O3", "WO2", "WO3", + "XeO3", "XeO4", "Y2O3", "Yb2O3", "ZnO", "ZrO2" +) special_oxide_states <- c( "LOI", # loss of ignition "FeOtot", # total iron - "Fe2O3tot", - "Bal", "Balance" # reported by pXRF instruments + "Fe2O3tot" ) -isotopes_data <- c( +isotopes <- c( # all naturally occurring isotopes, retrieved from https://www.ciaaw.org/isotopic-abundances.htm # sorted according to chemical element and isotope number "1H", "2H", "3He", "4He", "6Li", "7Li", "9Be", "10B", "11B", "12C", "13C", @@ -59,12 +78,11 @@ isotopes_data <- c( ) usethis::use_data( - elements_data, - oxides_data, + elements, + oxides, special_oxide_states, - isotopes_data, - conversion_oxides, - overwrite = TRUE, internal = FALSE + isotopes, + overwrite = TRUE, internal = TRUE ) # units <- c( @@ -73,3 +91,11 @@ usethis::use_data( # ) # # usethis::use_data(isotopes, overwrite = T) + +#### archem data input table #### + +archchem_example_input <- readr::read_csv("data-raw/test_data_input_good.csv") + +usethis::use_data(archchem_example_input, + overwrite = TRUE +) diff --git a/data-raw/oxide_conversion.csv b/data-raw/oxide_conversion.csv deleted file mode 100644 index 6757c7c..0000000 --- a/data-raw/oxide_conversion.csv +++ /dev/null @@ -1,152 +0,0 @@ -Element,AtomicWeight,Oxide,M,OxideWeight,ElementToOxide,OxideToElement,OxidationState -Ac,227,,,,,, -Ag,107.868,Ag2O,2,231.735,1.074160085,0.930959933,1 -Ag,107.868,AgO,1,123.867,1.148320169,0.870837269,2 -Al,26.982,Al2O3,2,101.961,1.889426284,0.529261188,3 -Al,26.982,AlO,1,42.981,1.592950856,0.627765757,2 -Am,243,,,,,, -Ar,39.948,,,,,, -As,74.922,As2O3,2,197.841,1.320313126,0.757396091,3 -As,74.922,As2O5,2,229.839,1.533855209,0.651952019,5 -At,210,,,,,, -Au,196.967,Au2O3,2,441.931,1.121840207,0.891392548,3 -B,10.811,B2O3,2,69.619,3.219822403,0.310576136,3 -Ba,137.327,BaO,1,153.326,1.116502946,0.895653705,2 -Be,9.012,BeO,1,25.011,2.775299601,0.360321459,2 -Bh,270,,,,,, -Bi,208.98,Bi2O3,2,465.957,1.114836348,0.896992641,3 -Bk,247,,,,,, -Br,79.904,,,,,, -C,12.011,C2O,2,40.021,1.666014487,0.600234877,1 -C,12.011,CO,1,28.01,2.332028973,0.428811139,2 -C,12.011,CO2,1,44.009,3.664057947,0.272921448,4 -Ca,40.078,CaO,1,56.077,1.399196567,0.714695865,2 -Cd,112.411,CdO,1,128.41,1.142325929,0.8754069,2 -Ce,140.116,CeO2,1,172.114,1.228367924,0.814088337,4 -Cf,251,,,,,, -Cl,35.45,Cl2O,2,86.897,1.225627645,0.815908489,1 -Cl,35.45,Cl2O7,2,182.89,2.579408743,0.387650085,7 -Cl,35.45,ClO2,1,67.448,1.902623413,0.525590084,4 -Cm,247,,,,,, -Co,58.933,CoO,1,74.932,1.27147778,0.786486414,2 -Cr,51.996,Cr2O3,2,151.989,1.461545119,0.68420741,3 -Cr,51.996,CrO2,1,83.994,1.615393492,0.619044217,4 -Cr,51.996,CrO3,1,99.993,1.923090238,0.5199964,6 -Cs,132.90545,Cs2O,2,281.81,1.060189782,0.943227352,1 -Cu,63.546,Cu2O,2,143.091,1.125885186,0.888190033,1 -Cu,63.546,CuO,1,79.545,1.251770371,0.798868565,2 -Db,268,,,,,, -Ds,281,,,,,, -Dy,162.5,,,,,, -Er,167.259,Er2O3,2,382.515,1.143481068,0.874522568,3 -Es,252,,,,,, -Eu,151.964,Eu2O3,2,351.925,1.157922271,0.863615827,3 -F,18.998,OF2,2,53.996,1.420902917,0.703777357,1 -Fe,55.845,Fe2O3,2,159.687,1.429734085,0.699430761,3 -Fe,55.845,FeO,1,71.844,1.28648939,0.77730917,2 -Fm,257,,,,,, -Fr,223,,,,,, -Ga,69.723,Ga2O3,2,187.443,1.344197754,0.743938157,3 -Gd,157.25,Gd2O3,2,362.497,1.152613672,0.867593387,3 -Ge,72.64,GeO2,1,104.638,1.440501101,0.694202871,4 -H,1.007,H2O,2,18.013,8.943892751,0.111808139,1 -He,4.0026,,,,,, -Hf,178.49,HfO2,1,210.488,1.179270547,0.847981833,4 -Hg,200.59,HgO,1,216.589,1.079759709,0.926131983,2 -Ho,164.93,Ho2O3,2,377.857,1.145507185,0.872975755,3 -Hs,277,,,,,, -I,126.9,,,,,, -In,114.818,In2O3,2,277.633,1.209013395,0.827120695,3 -Ir,192.217,,,,,, -K,39.098,K2O,2,94.195,1.204601258,0.83015022,1 -Kr,83.798,,,,,, -La,138.905,La2O3,2,325.807,1.172769159,0.852682723,3 -Li,6.941,Li2O,2,29.881,2.15249964,0.464576152,1 -Lr,262,,,,,, -Lu,174.967,Lu2O3,2,397.931,1.13716015,0.879383612,3 -Md,258,,,,,, -Mg,24.305,MgO,1,40.304,1.658259617,0.603041882,2 -Mn,54.938,MnO,1,70.937,1.291219193,0.774461846,2 -Mn,54.938,Mn2O7,2,221.869,2.019267174,0.495229167,7 -Mn,54.938,MnO2,1,86.936,1.582438385,0.631936137,4 -Mo,95.96,MoO3,1,143.957,1.500177157,0.666587939,6 -Mt,278,,,,,, -N,14.007,N2O3,2,76.011,2.71332191,0.36855192,3 -N,14.007,N2O5,2,108.009,3.855536517,0.259367275,5 -N,14.007,NO,1,30.006,2.142214607,0.466806639,2 -N,14.007,NO2,1,46.005,3.284429214,0.304466906,4 -Na,22.99,Na2O,2,61.979,1.347955633,0.74186418,1 -Nb,92.90637,,,,,, -Nd,144.242,Nd2O3,2,336.481,1.166376645,0.857355987,3 -Ne,20.1797,,,,,, -Ni,58.693,Ni2O3,2,165.383,1.408881809,0.709782747,3 -Ni,58.693,Ni2O5,2,197.381,1.681469681,0.59471783,5 -Ni,58.693,NiO,1,74.692,1.272587872,0.785800353,2 -No,259,,,,,, -Np,237,,,,,, -O,15.999,O4,,63.996,,,0 -Os,190.23,OsO4,1,254.226,1.336413815,0.748271223,8 -P,30.974,P2O5,2,141.943,2.291324982,0.436428707,5 -P,30.974,P4O6,4,219.89,1.774794989,0.563445359,3 -Pa,231.03588,,,,,, -Pb,207.2,PbO,1,223.199,1.077215251,0.928319571,2 -Pb,207.2,PbO2,1,239.198,1.154430502,0.866227978,4 -Pd,106.42,PdO,1,122.419,1.150338282,0.869309503,2 -Pm,145,Pm2O3,2,337.997,1.165506897,0.857995781,3 -Po,209,,,,,, -Pr,140.90766,Pr2O3,2,329.812,1.170312529,0.854472609,3 -Pr,140.90766,Pr6O11,6,1021.435,1.208161193,0.827704122,3.67 -Pt,195.084,,,,,, -Pu,244,PuO2,1,275.998,1.131139344,0.884064377,4 -Ra,226,,,,,, -Rb,85.468,Rb2O,2,186.935,1.093596434,0.914414101,1 -Re,186.207,Re2O7,2,484.407,1.300721777,0.768803919,7 -Re,186.207,ReO3,1,234.204,1.257761523,0.795063278,6 -Rf,267,,,,,, -Rg,282,,,,,, -Rh,102.906,Rh2O3,2,253.809,1.233207976,0.810893231,3 -Rn,222,,,,,, -Ru,101.07,RuO2,1,133.068,1.316592461,0.759536478,4 -Ru,101.07,RuO4,1,165.066,1.633184921,0.612300534,8 -S,32.065,SO,1,48.064,1.498955247,0.667131325,2 -S,32.065,SO2,1,64.063,1.997910494,0.500522923,4 -S,32.065,SO3,1,80.062,2.496865741,0.400502111,6 -Sb,121.76,Sb2O3,2,291.517,1.197096748,0.83535437,3 -Sb,121.76,Sb2O5,2,323.515,1.32849458,0.752731713,5 -Sc,44.956,Sc2O3,2,137.909,1.533821959,0.651966152,3 -Se,78.96,SeO2,1,110.958,1.405243161,0.711620613,4 -Se,78.96,SeO3,1,126.957,1.607864742,0.621942863,6 -Sg,269,,,,,, -Si,28.086,SiO2,1,60.084,2.139286477,0.467445576,4 -Sm,150.36,Sm2O3,2,348.717,1.159606943,0.86236117,3 -Sn,118.71,SnO,1,134.709,1.134773819,0.88123288,2 -Sn,118.71,SnO2,1,150.708,1.269547637,0.78768214,4 -Sr,87.62,SrO,1,103.619,1.182595298,0.845597815,2 -Ta,180.948,Ta2O5,2,441.891,1.221044167,0.818971194,5 -Tb,158.925,Tb2O3,2,365.847,1.151005191,0.868805812,3 -Tc,98,,,,,, -Te,127.6,TeO2,1,159.598,1.250768025,0.799508766,4 -Te,127.6,TeO3,1,175.597,1.376152038,0.726663895,6 -Th,232.038,ThO2,1,264.036,1.137899827,0.87881198,4 -Ti,47.867,Ti2O3,2,143.731,1.501357929,0.666063688,3 -Ti,47.867,TiO,1,63.866,1.33423862,0.749491122,2 -Ti,47.867,TiO2,1,79.865,1.668477239,0.599348901,4 -Tl,204.383,Tl2O,2,424.765,1.039139752,0.962334467,1 -Tl,204.383,Tl2O3,2,456.763,1.117419257,0.894919247,3 -Tm,168.934,Tm2O3,2,385.865,1.142058437,0.875611937,3 -U,238.029,UO2,1,270.027,1.134428998,0.881500739,4 -U,238.029,UO3,1,286.026,1.201643497,0.832193577,6 -V,50.942,V2O3,2,149.881,1.471094578,0.679765948,3 -V,50.942,V2O5,2,181.879,1.78515763,0.560174622,5 -V,50.942,VO,1,66.941,1.314063052,0.760998491,2 -V,50.942,VO2,1,82.94,1.628126104,0.614203038,4 -W,183.84,W2O3,2,415.677,1.130540144,0.884532943,3 -W,183.84,WO2,1,215.838,1.174053525,0.851749924,4 -W,183.84,WO3,1,231.837,1.261080287,0.792970924,6 -Xe,131.293,XeO3,1,179.29,1.36557166,0.732294049,6 -Xe,131.293,XeO4,1,195.289,1.48742888,0.672301051,8 -Y,88.906,Y2O3,2,225.809,1.269931163,0.787444256,3 -Yb,173.054,Yb2O3,2,394.105,1.138676367,0.878212659,3 -Zn,65.38,ZnO,1,81.379,1.244707862,0.803401369,2 -Zr,91.224,ZrO2,1,123.222,1.350762957,0.740322345,4 -,,,,,,, diff --git a/data-raw/test_data_input_good.csv b/data-raw/test_data_input_good.csv new file mode 100644 index 0000000..5322c4e --- /dev/null +++ b/data-raw/test_data_input_good.csv @@ -0,0 +1,15 @@ +Sample,Lab no.,Site,latitude,longitude,Type,method_comp,143Nd/144Nd,d65Cu,d65Cu_err2SD,Na2O_wt%,BaO_wt%,Pb_wt%,MgO_wt%,Al2O3_wt%,SiO2_wt%,SiO2_errSD%,P2O5_wt%,S_at%,CaO_wt%,TiO2_wt%,MnO_wt%,FeOtot_wt%,FeOtot_err2SD,ZnO_%,K2O_wt%,Cu_wt%,As_wt%,LOI_wt%,Ag_ppb,Sn_µg/ml,Sb_ppm,Te_ppm,Bi_ppm,U_ppm,V_ppm,Cr_ppm,Co_ppm,Ni_ppm,Sr_ppm,Se_ppm,FeOtot/SiO2,(Na2O+K2O)/SiO2,206Pb/204Pb,206Pb/204Pb_err2SD,207Pb/204Pb,207Pb/204Pb_err2SD,208Pb/204Pb,208Pb/204Pb_err2SD,207Pb/206Pb,207Pb/206Pb_err2SD,208Pb/206Pb,208Pb/206Pb_err2SD +TR-001,3421/19,Bochum,51.48165,7.21648,1,ICP-MS,0.513014,1.24,0.124,3.1,0.07,6.34,0.77,3.92,31.63,4.3,0.15,2.57,2.11,0.52,0.2,43.83,4.12,5.64,1.34,0.11,0.02,1.89,500,85,370,2,18,3,60,160,60,60,130,<5,1.386,0.14037,18.61147,0.01082,15.65405,0.00915,38.7563,0.0227,0.8411,0.00006,2.08239,0.00017 +TR-002_1,3423/19,Oviedo,43.36029,-5.84476,2,ICP-MS,0.512994,0.88,0.06,2.2,0.07,3.52,0.55,3.46,29.06,2.88,-,NA,2.34,0.49,0.54,51.02,3.89,4.07,1.26,0.22,0.01,-,200,85,210,2,20,2,60,140,70,100,120,<5,1.756,0.11906,18.61617,0.01629,15.65682,0.01341,38.76404,0.0345,0.84103,0.00013,2.08229,0.00033 +TR-002_2,3435/19,Oviedo,43.36029,-5.84476,2,ICP-MS,0.512996,0.85,0.05,5,0.054,3.6,0.33,5.87,30.5,5.71,0.11,3.68,2,0.55,0.1,30.59,2.94,6.87,1.54,0.74,bdl,-,210,98,256,<1.5,47,-,63,99,55,87,121,15,1.003,0.21443,18.61615,0.01698,15.6574,0.01441,38.76411,0.03452,0.84107,0.00014,2.08228,0.00033 +TR-003,3422/19,佛山,23.02677,113.13148,3,ICP-MS,0.513008,2.76,0.276,6.9,0.04,5.07,0.76,4.33,25.73,2.22,0.23,2.76,3.91,0.27,0.7,46.09,3.5,5.87,1.66,0.13,0.01,NA,350,45,400,2,bdl,2,45,30,30,20,250,<5,1.791,0.33269,18.61272,0.00926,15.65677,0.00747,38.76097,0.0182,0.84119,0.0001,2.08251,0.00025 +TR-004,3429/19,Băiuț,43.234895,23.124983,4,ICP-MS,,-8.21,-0.821,3,0.03,9.15,0.52,4.17,43.5,4.65,0.4,0.57,1.79,0.24,1,31.91,2.87,2.26,2.15,0.14,0.03,3.57,400,14,410,2,6,3,55,75,n.a.,10,160,<5,0.734,0.11839,18.63562,0.01189,15.64765,0.00989,38.73583,0.02561,0.83966,0.00009,2.07858,0.00023 +TR-005,3430/19,Şuior,41.445566,24.935661,5,ICP-MS,,0.06,0.004,4.1,0.07,12.61,0.58,3.58,33.83,3.67,0.29,0.61,2.06,0.18,0.49,36.57,5.486,1.66,1.21,0.09,0.11,5.66,250,181,453,6,9,3,54,41,8,47,258,-,1.081,0.15696,18.63952,0.01802,15.65502,0.01513,38.75729,0.04157,0.83989,0.00012,2.07923,0.00032 +TR-006.1,3431/19,Blagodat,41.453133,25.505011,5,ICP-MS,,1.48,0.222,3.4,0.05,12.68,0.64,5.6,33.81,3,0.43,0.77,,NA,1.52,35.52,2.66,2.46,2.26,0.21,0.23,0.12,120,566,701,8,9,bdl,75,106,22,19,122,3,1.051,0.16741,18.64465,0.01468,15.65836,0.0121,38.76615,0.02716,0.83984,0.00009,2.07928,0.00023 +TR-006.2,3432/19,Pezinok,45.92125,15.919219,1,ICP-MS,,-0.42,-0.042,1.8,0.04,5.31,0.59,4.47,26.39,2.87,0.62,3.04,4.28,NA,0.4,41.2,3.89,11.65,1.86,0.43,0.02,0.89,430,203,231,15,3,b.d.l.,84,91,47,34,280,3,1.561,0.13869,18.83274,0.01608,15.82161,0.0135,39.20161,0.03356,0.84852,0.00007,2.10238,0.00017 +TR-006.3,3433/19,Free State Geduld Mines,50.35621322,7.651313679,4,ICP-MS,,0.3,0.02,5.1,0.09,2.36,0.53,3.73,21.18,3.44,0.24,3.93,4.08,0.15,0.46,48.26,2.268,6.8,2.01,0.59,0.08,4.75,300,5594,107,6,5,5,32,63,17,37,310,<5,2.279,0.33569,18.83312,0.01875,15.82042,0.01619,39.20067,0.04173,0.84846,0.00007,2.10235,0.00018 +smn348,3424/19,Aggenys,50.99159628,8.02757263,3,ICP-MS,0.512977,0.24,0.024,4.1,0.34,47.49,0.7,6.27,31.73,6.12,0.28,0.21,7.14,NA,0.24,5.26,0.305,0.03,1.34,0.07,0.06,n.a.,2420,32,3310,9,150,NA,61,45,-,4,287,5,0.166,0.17145,18.80371,0.03129,15.81646,0.026,39.15557,0.06458,0.84955,0.00007,2.10313,0.00026 +smn349,3425/19,Chiprovtsi,50.6890264,6.406379006,3,ICP-MS,0.513004,0.54,0.01,3.4,0.04,2.53,0.46,2.91,16.91,3.73,0.22,3.57,2.5,0.14,0.21,56.36,6.763,4.89,1.34,0.15,0.01,4.22,140,23,95,5,1,3,37,36,69,39,155,<5,3.333,0.28031,18.8076,0.0155,15.82128,0.01309,39.17608,0.03091,0.84963,0.00012,2.10388,0.00022 +smn350,3426/19,Krusov Dol; Krushev Dol,40.695753,24.591976,5,ICP-MS,0.512991,2.04,0.8,4.5,0.07,1.56,0.58,3.6,28.49,4.89,0.19,1.95,1.39,0.17,0.13,47.64,4.235,6.56,0.98,0.16,0.02,6.01,1610,45,78,5,4,3,40,33,43,39,165,<5,1.672,0.19235,18.81356,0.01557,15.82045,0.01305,39.17244,0.03263,0.84931,0.00007,2.10297,0.00022 +smn351,3427/19,Masua,37.726179,24.012951,1,ICP-MS,,-0.24,-0.0504,3.2,0.04,3.64,0.88,5.24,38.04,10.12,0.3,1.35,2.1,0.34,1.32,43.21,2.161,1.52,1.48,0.27,0.05,3.22,100,15,610,2,1,2,80,190,20,50,100,<5,1.136,0.12303,18.81501,0.01535,15.80824,0.0135,39.13346,0.03109,0.84859,0.00007,2.10076,0.00018 +8896,3428/19,Σπαρτη,37.07446,22.43009,1,ICP-MS,,-0.42,-0.042,3.7,0.06,7.51,0.84,3.97,31.67,4.3,0.18,0.83,3.51,0.24,0.34,45.9,2.387,0.85,1.32,0.09,0.14,n.a.,100,146,390,<1.5,<0.3,1,40,100,10,65,120,<5,1.449,0.15851,18.82037,0.01483,15.81119,0.01252,39.13715,0.03182,0.84851,0.00007,2.1003,0.00024 diff --git a/data/archchem_example_input.rda b/data/archchem_example_input.rda new file mode 100644 index 0000000..13d15a0 Binary files /dev/null and b/data/archchem_example_input.rda differ diff --git a/data/conversion_oxides.rda b/data/conversion_oxides.rda deleted file mode 100644 index d1eb149..0000000 Binary files a/data/conversion_oxides.rda and /dev/null differ diff --git a/data/elements.rda b/data/elements.rda new file mode 100644 index 0000000..2ae208c Binary files /dev/null and b/data/elements.rda differ diff --git a/data/elements_data.rda b/data/elements_data.rda deleted file mode 100644 index 62739e0..0000000 Binary files a/data/elements_data.rda and /dev/null differ diff --git a/data/isotopes.rda b/data/isotopes.rda new file mode 100644 index 0000000..3b557b7 Binary files /dev/null and b/data/isotopes.rda differ diff --git a/data/isotopes_data.rda b/data/isotopes_data.rda deleted file mode 100644 index 65cfa23..0000000 Binary files a/data/isotopes_data.rda and /dev/null differ diff --git a/data/oxides.rda b/data/oxides.rda new file mode 100644 index 0000000..35399d0 Binary files /dev/null and b/data/oxides.rda differ diff --git a/data/oxides_data.rda b/data/oxides_data.rda deleted file mode 100644 index 5ad3b96..0000000 Binary files a/data/oxides_data.rda and /dev/null differ diff --git a/data/special_oxide_states.rda b/data/special_oxide_states.rda deleted file mode 100644 index 6beeb83..0000000 Binary files a/data/special_oxide_states.rda and /dev/null differ diff --git a/dev_guide/Drafts/Oxide_element.R b/dev_guide/Drafts/Oxide_element.R deleted file mode 100644 index 0ba267a..0000000 --- a/dev_guide/Drafts/Oxide_element.R +++ /dev/null @@ -1,139 +0,0 @@ - -# Goals of the oxide_conversion function: - -# convert element compositions to oxides and vice versa -# be able to select which oxide to convert to depending on material (optional, set a default list) -# be able to normalize the data after conversion, for elements to oxides and oxide to elements (optional) -# be able to select what elements get converted to oxides: -# ("major" = (wt%>1), "minor" = (wt% > 0.1), "all") - - -#requirements: -#select only compositional data -#if normalised, need to convert all units to % or wt% prior to normalisation -##normalisation equation: -##normalised_oxide_or_element = ([oxide_or_element_composition]*100)/(sum of (all_element_or_oxides_to_be_normalised) -#if only converting oxides at the major or minor threshold, will need special handling of the normalisation - - -conversion_table <- read.csv("oxide_conversion.csv", stringsAsFactors = FALSE) - -default_oxides <- c( - "H2O","LiO2","BeO","B2O3","CO2","N2O5","Na2O","MgO","Al2O3","SiO2","P2O5","SO3", - "K2O","CaO","Sc2O3","TiO2","V2O5","Cr2O3","MnO","FeO","CoO","NiO","CuO","ZnO","Ga2O3", - "GeO2","As2O3","SeO2","Rb2O","SrO","Y2O3","ZrO2","MoO3","Ru2O3","Rh2O3", - "PdO","Ag2O","CdO","SnO2","Sb2O3","TeO2","BaO","La2O3","CeO2", - "Pm2O3","Sm2O3","Gd2O3","Tb2O3","Ho2O3","Er2O3","Tm2O3","Yb2O3","Lu2O3", - "HfO2","Ta2O5","WO3","Re2O7","OsO4","HgO","Tl2O3","PbO","Bi2O3","UO3" -) - -df <- read.csv("test.csv", stringsAsFactors = FALSE) - -clean_df <- df -cols <- grep("_(wt%|%|ppm|ppb)$", names(clean_df), value = TRUE) - - -for (nm in cols) { - x <- as.character(clean_df[[nm]]) - x[grepl("lod", x, ignore.case = TRUE)] <- NA # turn " 1 - if (mode == "minor") keep <- x > 0.1 - keep -} - -make_element_to_oxide_map <- function(conversion_table, preferred_oxides = default_oxides) { - ct <- conversion_table[conversion_table$Oxide %in% preferred_oxides, ] - ct$rank <- match(ct$Oxide, preferred_oxides) - ct <- ct[order(ct$rank), ] - ct <- ct[!duplicated(ct$Element), ] - rownames(ct) <- ct$Element - ct -} - -elements_to_oxides <- function(df, - conversion_table, - preferred_oxides = default_oxides, - which_elements = c("all","major","minor"), - normalize = FALSE) { - - which_elements <- match.arg(which_elements) - - ## (a) keep only element columns that exist in df - elem_cols <- intersect(names(df), elements) - if (!length(elem_cols)) stop("No element columns found in df.") - - ## (b) build mapping + keep only elements we can map - map <- make_element_to_oxide_map(conversion_table, preferred_oxides) - have_map <- elem_cols %in% rownames(map) - if (!all(have_map)) { - warning("No oxide mapping for: ", paste(elem_cols[!have_map], collapse = ", ")) - } - elem_cols <- elem_cols[have_map] - if (!length(elem_cols)) stop("No mappable element columns found.") - - ## (c) numeric matrix of selected elements - X <- as.matrix(df[elem_cols]) - storage.mode(X) <- "double" - - ## (d) multiply by element->oxide factors - factors <- as.numeric(map[elem_cols, "element_to_oxide"]) - XO <- sweep(X, 2, factors, "*") - colnames(XO) <- map[elem_cols, "Oxide"] - - ## (e) thresholds (per row) if "major" (>1) or "minor" (>0.1) - if (which_elements != "all") { - thr <- if (which_elements == "major") 1 else 0.1 - XO[X <= thr] <- NA_real_ # only convert values above the threshold - } - - ## (f) collapse duplicate oxide names (e.g., if multiple elements mapped to same oxide choice) - ox_names <- colnames(XO) - if (any(duplicated(ox_names))) { - unq <- unique(ox_names) - agg <- matrix(0, nrow = nrow(XO), ncol = length(unq)) - for (i in seq_along(unq)) { - j <- which(ox_names == unq[i]) - agg[, i] <- rowSums(XO[, j, drop = FALSE], na.rm = TRUE) - } - XO <- agg - colnames(XO) <- unq - } - - ## (g) build output: drop converted element cols, add oxide cols - out <- df - out[elem_cols] <- NULL - for (j in seq_len(ncol(XO))) out[[colnames(XO)[j]]] <- XO[, j] - - ## (h) optional normalization over the converted oxide set - if (normalize) { - sel <- colnames(XO) - s <- rowSums(out[sel], na.rm = TRUE) - for (nm in sel) out[[nm]] <- (out[[nm]] * 100) / s - } - - out -} - -ox_df <- elements_to_oxides(clean_df, conversion_table, - preferred_oxides = default_oxides, - which_elements = "all", - normalize = FALSE) - -ox_df_norm <- elements_to_oxides(clean_df, conversion_table, - preferred_oxides = default_oxides, - which_elements = "major", - normalize = TRUE) - -## this works, but it is not optimised in any sense, and not set to work directly -## with the data yet -- all tbd diff --git a/inst/extdata/input_format.xlsx b/inst/extdata/input_format.xlsx index 5986850..68df68b 100644 Binary files a/inst/extdata/input_format.xlsx and b/inst/extdata/input_format.xlsx differ diff --git a/man/ASTR-package.Rd b/man/ASTR-package.Rd index bf55071..09ca130 100644 --- a/man/ASTR-package.Rd +++ b/man/ASTR-package.Rd @@ -2,54 +2,46 @@ % Please edit documentation in R/ASTR-package.R \docType{package} \name{ASTR-package} +\alias{ASTR} \alias{ASTR-package} -\title{ASTR: Archaeometric Standards and Tools in R} +\title{ASTR: What the Package Does (One Line, Title Case)} \description{ -ASTR defines and implements a community reporting standard for archaeometric datasets. It also provides easy-to-use functions for common plots, statistical analyses, data processing and transformation workflows in archaeometry. +What the package does (one paragraph). } \seealso{ Useful links: \itemize{ - \item \url{https://archaeothommy.github.io/ASTR/} - \item \url{https://github.com/archaeothommy/ASTR} - \item Report bugs at \url{https://github.com/archaeothommy/ASTR/issues} + \item \url{https://example.com} } } \author{ -\strong{Maintainer}: Thomas Rose \email{roseth@posteo.com} (\href{https://orcid.org/0000-0002-8186-3566}{ORCID}) +\strong{Maintainer}: Rose Thomas \email{roseth@posteo.com} (\href{https://orcid.org/0000-0002-8186-3566}{ORCID}) Authors: \itemize{ - \item Mathias Ayine Abagna - \item Andrea Acevedo Mejia (\href{https://orcid.org/0009-0002-7441-1737}{ORCID}) - \item Gilberto Artioli (\href{https://orcid.org/0000-0002-8693-7392}{ORCID}) - \item María Florencia Becerra (\href{https://orcid.org/0000-0001-6302-7452}{ORCID}) - \item Adam Kevin Benfer (\href{https://orcid.org/0009-0004-1253-1068}{ORCID}) - \item Lisa Bellemère - \item Thomas Edward Birch (\href{https://orcid.org/0000-0002-4568-9767}{ORCID}) - \item Karan Desai (\href{https://orcid.org/0009-0008-8224-8435}{ORCID}) - \item Paolo d'Imporzano - \item Tzilla Eshel (\href{https://orcid.org/0000-0003-0976-0877}{ORCID}) - \item Valerio Gentile (\href{https://orcid.org/0000-0003-4402-2730}{ORCID}) - \item Sabine Klein (\href{https://orcid.org/0000-0002-3939-4428}{ORCID}) - \item Catherine Klesner (\href{https://orcid.org/0000-0002-2264-9383}{ORCID}) - \item Kathryn Murphy (\href{https://orcid.org/0000-0002-5906-7299}{ORCID}) - \item Ben Marwick (\href{https://orcid.org/0000-0001-7879-4531}{ORCID}) - \item Stephen Merkel (\href{https://orcid.org/0000-0001-8730-6923}{ORCID}) - \item Marco Daniele Pelizzari - \item Alexandra Rodler (\href{https://orcid.org/0000-0002-4087-7160}{ORCID}) - \item Benjamin Sabatini (\href{https://orcid.org/0000-0002-4199-0253}{ORCID}) - \item Clemens Schmid (\href{https://orcid.org/0000-0003-3448-5715}{ORCID}) - \item Berber van der Meulen-van der Veen (\href{https://orcid.org/0000-0001-5297-0269}{ORCID}) - \item Chen Wang (\href{https://orcid.org/0009-0007-1851-2388}{ORCID}) - \item Katrin Julia Westner (\href{https://orcid.org/0000-0001-5529-1165}{ORCID}) -} - -Other contributors: -\itemize{ - \item Deutsche Forschungsgemeinschaft (\href{https://ror.org/018mejw64}{ROR}) [funder] - \item Lorentz Center (\href{https://ror.org/00d503m77}{ROR}) [funder] + \item Acevedo Mejia Andrea (\href{https://orcid.org/0009-0002-7441-1737}{ORCID}) + \item Artioli Gilberto (\href{https://orcid.org/0000-0002-8693-7392}{ORCID}) + \item Becerra María Florencia (\href{https://orcid.org/0000-0001-6302-7452}{ORCID}) + \item Benfer Adam Kevin (\href{https://orcid.org/0009-0004-1253-1068}{ORCID}) + \item Bellemère Lisa + \item Birch Thomas Edward (\href{https://orcid.org/0000-0002-4568-9767}{ORCID}) + \item Desai Karan (\href{https://orcid.org/0009-0008-8224-8435}{ORCID}) + \item d'Imporzano Paolo + \item Eshel Tzilla (\href{https://orcid.org/0000-0003-0976-0877}{ORCID}) + \item Gentile Valerio (\href{https://orcid.org/0000-0003-4402-2730}{ORCID}) + \item Klein Sabine (\href{https://orcid.org/0000-0002-3939-4428}{ORCID}) + \item Klesner Catherine (\href{https://orcid.org/0000-0002-2264-9383}{ORCID}) + \item Murphy Kathryn (\href{https://orcid.org/0000-0002-5906-7299}{ORCID}) + \item Marwick Ben (\href{https://orcid.org/0000-0001-7879-4531}{ORCID}) + \item Merkel Stephen (\href{https://orcid.org/0000-0001-8730-6923}{ORCID}) + \item Pelizzari Marco Daniele + \item Rodler Alexandra (\href{https://orcid.org/0000-0002-4087-7160}{ORCID}) + \item Sabatini Benjamin (\href{https://orcid.org/0000-0002-4199-0253}{ORCID}) + \item Schmid Clemens (\href{https://orcid.org/0000-0003-3448-5715}{ORCID}) + \item van der Meulen-van der Veen Berber (\href{https://orcid.org/0000-0001-5297-0269}{ORCID}) + \item Wang Chen (\href{https://orcid.org/0009-0007-1851-2388}{ORCID}) + \item Westner Katrin Julia (\href{https://orcid.org/0000-0001-5529-1165}{ORCID}) } } diff --git a/man/ArgentinaDatabase.Rd b/man/ArgentinaDatabase.Rd index eabe98b..3a2ff94 100644 --- a/man/ArgentinaDatabase.Rd +++ b/man/ArgentinaDatabase.Rd @@ -1,14 +1,15 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_data.R +% Please edit documentation in R/data.R \docType{data} \name{ArgentinaDatabase} \alias{ArgentinaDatabase} -\title{Lead isotope data from Argentina} +\title{ArgentinaDatabase} \format{ -\code{ArgentinaDatabase} +\subsection{\code{ArgentinaDatabase}}{ A dataframe with 112 rows and 49 columns } +} \source{ \url{https://globalid.dmt-lb.de/} } @@ -16,6 +17,6 @@ A dataframe with 112 rows and 49 columns ArgentinaDatabase } \description{ -Lead isotope data from ore deposits in Argentina prepared for the TerraLID database. +Lead isotope data from ore deposits in Argentina prepared for TerraLID database. } \keyword{datasets} diff --git a/man/age_models.Rd b/man/age_models.Rd index 9bb67e5..6b5154b 100644 --- a/man/age_models.Rd +++ b/man/age_models.Rd @@ -38,8 +38,7 @@ albarede_juteau_1984( ) } \arguments{ -\item{df}{The data frame from which the age model parameters should be -calculated.} +\item{df}{The data frame from which the age model should be calculated.} \item{ratio_206_204}{Name of the column with the 206Pb/204Pb ratio as character string. Default is \verb{206Pb/204Pb}.} @@ -60,16 +59,9 @@ calculate: }} } \value{ -If \code{df} is an \link[=ASTR]{ASTR object}, the output is an object of the -same type including the ID column, the contextual columns, the lead isotope -ratios used for calculation of the age model parameters, and the calculated -age model parameters. In all other cases, the data frame provided as input -with columns added for the calculated age model parameters. - -The used age model is indicated in the column names of the output by the -abbreviations for the models given above. They represent the initials of -the author's last names and the publication year (e. g. \code{SK75} for Stacey & -Kramers 1975). +The data frame provided as input with columns added for the model +age, mu, and kappa value(s) of the respective age models. The used model is +indicated in the column names of the output by the abbreviations given above. } \description{ The functions calculate the age model and their respective mu and kappa @@ -78,15 +70,26 @@ values according to the publications they are named after (see to calculate all age models simultaneously. } \details{ +The implemented age models are: +\itemize{ +\item Stacey & Kramers (1975): \code{\link[=stacey_kramers_1975]{stacey_kramers_1975()}} +\item Cumming & Richards (1975): \code{\link[=cumming_richards_1975]{cumming_richards_1975()}} +\item Albarède & Juteau (1984): \code{\link[=albarede_juteau_1984]{albarede_juteau_1984()}} +} + +The used model is indicated in the column names of the output by the initials +of the author's last names and the publication year (e. g.\code{SK75} for Stacey +& Kramers 1975). + See the references for the respective publications of the age models. The function for the age model of Albarède & Juteau (1984) is based on the -MATLAB-script of F. Albarède (version 2020-11-06). The age model published in -Albarède et al. (2012) should not be used according to F. Albarède and is +MATLAB-script of F. Albarède (version 2020-11-06). The age model published +in Albarède et al. (2012) should not be used according to F. Albarède and is therefore not implemented. Instead, he recommends to use the age model published in Albarède & Juteau (1984). -The ratio of 208Pb/204Pb is not necessary for \link{cumming_richards_1975}. The -function takes it as argument only to be consistent with the input of the +The ratio of 208Pb/204Pb is not necessary for \link{cumming_richards_1975}. +The function takes it as argument only to be consistent with the input of the other age model functions. If provided, it will be ignored. } \examples{ @@ -107,7 +110,7 @@ stacey_kramers_1975(df) } \references{ Albarède, F. and Juteau, M. (1984) Unscrambling the lead model -ages. Geochimica et Cosmochimica Acta 48(1), pp. 207-212. +ages. Geochimica et Cosmochimica Acta 48(1), pp. 207–212. \url{https://dx.doi.org/10.1016/0016-7037(84)90364-8}. Albarède, F., Desaulty, A.-M. and Blichert-Toft, J. (2012) A geological @@ -120,10 +123,5 @@ continuously changing earth. Earth and Planetary Science Letters 28(2), pp. Stacey, J.S. and Kramers, J.D. (1975) Approximation of terrestrial lead isotope evolution by a two-stage model. Earth and Planetary Science Letters -26(2), pp. 207–221. \url{https://dx.doi.org/10.1016/0012-821X(75)90088-6}. -} -\seealso{ -Other Pb isotope functions: -\code{\link{geom_sk_lines}()} +26(2), pp. 207–221. \% - magrittr::set_attr("ASTR_class", "ASTR_concentration") +conc$Sb_ppb <- units::set_units(arch$Sb_ppm, "ppb") \%>\% + magrittr::set_attr("archchem_class", "archchem_concentration") -# removing all units from ASTR tables +# removing all units from archchem tables remove_units(arch) -# applying tidyverse data manipulation on ASTR tables +# applying tidyverse data manipulation on archchem tables arch \%>\% dplyr::group_by(Site) \%>\% - dplyr::summarise(mean_Na2O = mean(Na2O)) + dplyr::summarise(mean_Na2O = mean(`Na2O_wt\%`)) conc_subset <- conc \%>\% - dplyr::select(-Sn, -Sb) \%>\% - dplyr::filter(Na2O > units::set_units(4, "wtP")) + dplyr::select(-`Sn_µg/ml`, -`Sb_ppm`) \%>\% + dplyr::filter(`Na2O_wt\%` > units::set_units(1, "\%")) # unify all concentration units -unify_concentration_unit(conc_subset, "ppb") +unify_concentration_unit(conc_subset, "ppm") +# note that the column names are inaccurate now } diff --git a/man/archchem_example_input.Rd b/man/archchem_example_input.Rd new file mode 100644 index 0000000..5d84133 --- /dev/null +++ b/man/archchem_example_input.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{archchem_example_input} +\alias{archchem_example_input} +\title{archchem_example_input} +\format{ +A data frame with 15 observations and 53 variables. +} +\usage{ +data(archchem_example_input) +} +\description{ +A dataset that contains fictitious data mimicking lead slags +including composition, isotopic, and contextual information. +The variable names conform to ASTR conventions (see "ASTR Schema" vignette). +} +\details{ +\itemize{ +\item Sample. Individual samples for which compositional and isotopic data, +and contextual information is provided in this dataset. +\item Lab.no, Site, latitude, longitude, Type, method_comp. Columns containing +contextual information on the samples. +\item 143Nd/144Nd, d65Cu, d65Cu_err2SD, 206Pb/204Pb, 206Pb/204Pb_err2SD, +207Pb/204Pb, 207Pb/204Pb_err2SD, 208Pb/204Pb, 208Pb/204Pb_err2SD,207Pb/206Pb, +207Pb/206Pb_err2SD,208Pb/206Pb, 208Pb/206Pb_err2SD. Columns containing isotopic data. +\item Na2O_wt\%, BaO_wt\%, Pb_wt\%, MgO_wt\%, Al2O3_wt\%, SiO2_wt\%, SiO2_errSD\%, +P2O5_wt\%, S_at\%, CaO_wt\%,TiO2_wt\%, MnO_wt\%, FeOtot_wt\%, FeOtot_err2SD, ZnO\%, +K2O_wt\%, Cu_wt\%, As_wt\%, LOI_wt\%, Ag_ppb, Sn_µg/ml, Sb_ppm, Te_ppm, Bi_ppm, +U_ppm, V_ppm, Cr_ppm, Co_ppm, Ni_ppm, Sr_ppm, Se_ppm, FeOtot/SiO2, (Na2O+K2O)/SiO2. +Columns containing compositional data. +} +} +\keyword{datasets} diff --git a/man/atomic_conversion.Rd b/man/atomic_conversion.Rd deleted file mode 100644 index 9405dd7..0000000 --- a/man/atomic_conversion.Rd +++ /dev/null @@ -1,72 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_conversion_atomic.R -\name{atomic_conversion} -\alias{atomic_conversion} -\alias{wt_to_at} -\alias{at_to_wt} -\title{Conversion between wt\% and at\%} -\usage{ -wt_to_at(df, elements = colnames(get_unit_columns(df, "wtP")), drop = TRUE) - -at_to_wt(df, elements = colnames(get_unit_columns(df, "atP")), drop = TRUE) -} -\arguments{ -\item{df}{Data frame with compositional data.} - -\item{elements}{Character vector with the chemical symbols of the elements -that should be converted. Default are all columns in an \code{\link[=ASTR]{ASTR object}} in the unit to be converted. See \emph{Details} for further -information} - -\item{drop}{If \code{TRUE}, the default, columns with unconverted values are -dropped. If false, columns with unconverted values are kept and a suffix -added to the column names of the converted values. -\itemize{ -\item \verb{_atP} for conversions to atomic percent -\item \verb{_wtP} for conversions to weight percent. -}} -} -\value{ -The original data frame with the converted concentrations normalised -to 100\%. -} -\description{ -Convert chemical compositions between weight percent (\emph{wt\%}) and atomic -percent (\emph{at\%}). Results are always normalised to 100\%. -} -\details{ -The column names of the elements to be converted must be equivalent to their -chemical symbols. The functions convert only values in \emph{wt\%} or \emph{at\%}. If -concentrations are present in another concentration unit (e.g. \emph{ppm}, -\emph{µg/kg}), run \code{\link[=unify_concentration_unit]{unify_concentration_unit(df, "wtP")}} first to convert all concentrations to -\emph{wt\%}. If \code{df} is an \code{\link[=ASTR]{ASTR object}}, only elements will be converted -to \emph{at\%}, and oxides in \emph{wt\%} are automatically excluded. To convert oxides -into \emph{at\%} and vice versa, convert to \emph{wt\%} first. -} -\examples{ - -library(magrittr) - -# Convert weight percent to atomic percent and to weight percent -df <- data.frame(ID = 1, Si = 46.74, O = 53.26) # SiO2 composition -at <- wt_to_at(df, elements = c("Si", "O")) -at_to_wt(at, elements = c("Si", "O")) - -# preserve columns with unconverted values -wt_to_at(df, elements = c("Si", "O"), drop = FALSE) - -# Use with ASTR objects -# Create ASTR object -test_file <- system.file("extdata", "test_data_input_good.csv", package = "ASTR") -arch <- read_ASTR(test_file, id_column = "Sample", context = 1:7) - -# Convert columns in wt\% to at\% -arch_atP <- wt_to_at(arch) - -# To convert all applicable concentrations, unify units first: -arch_all <- unify_concentration_unit(arch, "wtP") \%>\% - wt_to_at() - -# Elements already present in the converted unit are ignored. -rowSums(get_unit_columns(arch_all, "atP")[-1], na.rm = TRUE) > 100 - -} diff --git a/man/conversion_oxides.Rd b/man/conversion_oxides.Rd deleted file mode 100644 index ab6d02b..0000000 --- a/man/conversion_oxides.Rd +++ /dev/null @@ -1,34 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_data.R -\docType{data} -\name{conversion_oxides} -\alias{conversion_oxides} -\title{Conversion factors from oxides to elements} -\format{ -A data frame with 151 rows and 8 variables: -\describe{ -\item{Element}{The symbol of a chemical element.} -\item{AtomicWeight}{The atomic weight (= molar mass) of the respective element.} -\item{Oxide}{The formula of the chemical element's oxide.} -\item{M}{The number of oxygen atoms in the oxide = the number of moles oxygen per mole oxide.} -\item{OxideWeight}{The molar mass of the oxide.} -\item{ElementToOxide}{The factor used in the conversion from the chemical element to its oxide.} -\item{OxideToElement}{The factor used in the conversion from the oxide to its chemical element.} -\item{OxidationState}{The oxidation state of the kation as numeric value.} -} -} -\usage{ -conversion_oxides -} -\description{ -Conversion factors from oxides to elements -} -\seealso{ -Other chemical reference data: -\code{\link{elements_data}}, -\code{\link{isotopes_data}}, -\code{\link{oxides_data}}, -\code{\link{special_oxide_states}} -} -\concept{chemical reference data} -\keyword{datasets} diff --git a/man/convert_concentration_units.Rd b/man/convert_concentration_units.Rd deleted file mode 100644 index 1e5fb78..0000000 --- a/man/convert_concentration_units.Rd +++ /dev/null @@ -1,34 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_unit_manipulation.R -\name{convert_concentration_units} -\alias{convert_concentration_units} -\title{Convert units} -\usage{ -convert_concentration_units(df, values, unit_to, ...) -} -\arguments{ -\item{df}{ASTR object} - -\item{values}{Character vector with column names of the values to be -converted.} - -\item{unit_to}{The unit the values should be converted to} - -\item{...}{Additional values passed to the conversion functions. This is -primarily intended for conversion into oxides because this function takes a -mandatory parameter that does not has a default value.} -} -\description{ -The function is intended to provide "on-the-fly" unit conversions inside -functions that require values in a certain unit. Use the respective -conversion functions for proper, user-facing unit conversions. It is not -intended to be used by users. It converts \emph{ALL} values in the unit and -convertable units of the values intended to be converted to ensure that e.g. -normalisation is not performed on subsets. -} -\details{ -Only the converted values of the input are intended to be processed further -and except for them, columns of the unconverted ASTR object should be made -available to the user in the function calling this unit converter. -} -\keyword{internal} diff --git a/man/copper_alloy_bb.Rd b/man/copper_alloy_bb.Rd deleted file mode 100644 index b36b7ec..0000000 --- a/man/copper_alloy_bb.Rd +++ /dev/null @@ -1,69 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_copper_alloy_classification_bb.R -\name{copper_alloy_bb} -\alias{copper_alloy_bb} -\title{Copper alloy classification according to Bayley & Butcher (2004)} -\usage{ -copper_alloy_bb( - df, - elements = c(Sn = "Sn", Zn = "Zn", Pb = "Pb"), - id_column = "ID", - ... -) -} -\arguments{ -\item{df}{data frame with the data to be classified.} - -\item{elements}{named character vector with column names of Sn, Zn, and Pb -concentrations.} - -\item{id_column}{name of the column in \code{df} with the identifiers of each -row. Default to \code{ID}.} - -\item{...}{Additional arguments for unit conversion, see \link{atomic_conversion} -and \link{oxide_conversion} for details.} -} -\value{ -If \code{df} is an \link[=ASTR]{ASTR object}, the output is an object of the -same type including the ID column, the contextual columns, the elements -used for classification and the alloy type. In all other cases, the data -frame provided as input with the column for the alloy type. -} -\description{ -Classification of copper alloy artefacts according to Bayley & -Butcher (2004) based on Zn, Sn, and Pb concentrations in wt\%. -Classification uses specific thresholds and ratios to define alloy types. -} -\examples{ -sample_df <- data.frame( - ID = 1:5, - Sn = c(5, 1, 4, 0.5, 2), - Zn = c(12, 20, 6, 2, 10), - Pb = c(1, 0.5, 5, 9, 12) -) -copper_alloy_bb(sample_df) - -# For ASTR objects, units and oxides are automatically converted -sample_df <- as_ASTR( - data.frame( - ID = 1:8, - SnO_wtP = c(0.5, 0.5, 5, 5, 0.5, 5, 5, 5), - ZnO_wtP = c(0.5, 0.5, 0.5, 0.5, 5, 5, 0.5, 5), - PbO_wtP = c(0.5, 5, 0.5, 5, 0.5, 0.5, 5, 5) - ) -) -copper_alloy_bb(sample_df, elements = c(Sn = "SnO", Zn = "ZnO", Pb = "PbO")) - -} -\references{ -Bayley, J. and Butcher, S. (2004). Roman brooches in Britain: a -technological and typological study based on the Richborough Collection. -London: Society of Antiquaries of London. -\url{https://doi.org/10.26530/20.500.12657/50365} -} -\seealso{ -Other copper alloy classifications: -\code{\link{copper_alloy_pollard}()}, -\code{\link{copper_group_bray}()} -} -\concept{copper alloy classifications} diff --git a/man/copper_alloy_pollard.Rd b/man/copper_alloy_pollard.Rd deleted file mode 100644 index 08ff352..0000000 --- a/man/copper_alloy_pollard.Rd +++ /dev/null @@ -1,73 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_copper_alloy_classification_pollard.R -\name{copper_alloy_pollard} -\alias{copper_alloy_pollard} -\title{Copper alloy classification according to Pollard et al. (2015).} -\usage{ -copper_alloy_pollard( - df, - elements = c(Sn = "Sn", Zn = "Zn", Pb = "Pb"), - id_column = "ID", - group_as_symbol = FALSE, - ... -) -} -\arguments{ -\item{df}{data frame with the data to be classified.} - -\item{elements}{named character vector with column names of Sn, Zn, and Pb.} - -\item{id_column}{name of the column in \code{df} with the identifiers of each row. -Default to \code{ID}.} - -\item{group_as_symbol}{logical. If \code{FALSE}, the default, copper groups are -reported as their label. Otherwise, copper groups are reported by their -symbol.} - -\item{...}{Additional arguments for unit conversion, see \link{atomic_conversion} -and \link{oxide_conversion} for details.} -} -\value{ -If \code{df} is an \link[=ASTR]{ASTR object}, the output is an object of the -same type including the ID column, the contextual columns, the elements -used for classification and the alloy type. In all other cases, the data -frame provided as input with the column for the alloy type. -} -\description{ -Classification of copper alloy artefacts following the system -proposed in Pollard et al. (2015) based Sn, Zn, and Pb concentrations in -wt\%. -} -\examples{ -sample_df <- data.frame( - ID = 1:8, - Sn = c(0.5, 0.5, 5, 5, 0.5, 5, 5, 5), - Zn = c(0.5, 0.5, 0.5, 0.5, 5, 5, 0.5, 5), - Pb = c(0.5, 5, 0.5, 5, 0.5, 0.5, 5, 5) -) -copper_alloy_pollard(sample_df) - -# For ASTR objects, units and oxides are automatically converted -sample_df <- as_ASTR( - data.frame( - ID = 1:8, - SnO_wtP = c(0.5, 0.5, 5, 5, 0.5, 5, 5, 5), - ZnO_wtP = c(0.5, 0.5, 0.5, 0.5, 5, 5, 0.5, 5), - PbO_wtP = c(0.5, 5, 0.5, 5, 0.5, 0.5, 5, 5) - ) -) -copper_alloy_pollard(sample_df, elements = c(Sn = "SnO", Zn = "ZnO", Pb = "PbO")) - -} -\references{ -Pollard, A. M., Bray, P., Gosden, C., Wilson, A., and Hamerow, H. -(2015). Characterising copper-based metals in Britain in the first -millennium AD: a preliminary quantification of metal flow and recycling. -Antiquity 89(345), pp. 697-713. \url{https://doi.org/10.15184/aqy.2015.20} -} -\seealso{ -Other copper alloy classifications: -\code{\link{copper_alloy_bb}()}, -\code{\link{copper_group_bray}()} -} -\concept{copper alloy classifications} diff --git a/man/copper_group_bray.Rd b/man/copper_group_bray.Rd index 30361fa..30a370e 100644 --- a/man/copper_group_bray.Rd +++ b/man/copper_group_bray.Rd @@ -7,9 +7,8 @@ copper_group_bray( df, elements = c(As = "As", Sb = "Sb", Ag = "Ag", Ni = "Ni"), - id_column = "ID", - group_as_number = FALSE, - ... + id_sample = "ID", + group_as_number = FALSE ) } \arguments{ @@ -18,26 +17,21 @@ copper_group_bray( \item{elements}{named character vector with the column names of the As, Sb, Ag, and Ni concentrations.} -\item{id_column}{name of the column in \code{df} with the identifiers of each row. +\item{id_sample}{name of the column in \code{df} with the identifiers of each row. Default to \code{ID}.} \item{group_as_number}{logical. If \code{FALSE}, the default, copper groups are reported as their label. Otherwise, copper groups are reported by their number.} - -\item{...}{Additional arguments for unit conversion, see \link{atomic_conversion} -and \link{oxide_conversion} for details.} } \value{ -If \code{df} is an \link[=ASTR]{ASTR object}, the output is an object of the -same type including the ID column, the contextual columns, the elements -used for classification and the alloy type. In all other cases, the data -frame provided as input with the column for the alloy type. +The original data frame with the added column \code{copper_group_bray}. } \description{ Classification of copper artefacts according to Bray et al. (2015) into one of 16 trace element compositional groups based on As, Sb, -Ag, or Ni being below or above 0.1 wt\%. +Ag, or Ni being below or above 0.1 wt\%. Concentrations must be given in +wt\%. } \examples{ # create dataset @@ -54,18 +48,6 @@ copper_group_bray(sample_df) # classification with group number as output copper_group_bray(sample_df, group_as_number = TRUE) -# For ASTR objects, units and oxides are automatically converted -sample_df2 <- as_ASTR( - data.frame( - ID = 1:3, - As2O3_wtP = c(0.2, 0.01, 0.15), - Sb2O3_wtP = c(0.00, 0.2, 0.11), - Ag2O_wtP = c(0.00, 0.00, 0.12), - NiO_wtP = c(0.00, 50, 0.20) - ) -) -copper_group_bray(sample_df2, elements = c(As = "As2O3", Sb = "Sb2O3", Ag = "Ag2O", Ni = "NiO")) - } \references{ Bray, P., Cuénod, A., Gosden, C., Hommel, P., Liu, P. and @@ -73,9 +55,3 @@ Pollard, A. M. (2015), Form and flow: the ‘karmic cycle’ of copper. Journal of Archaeological Science 56, pp. 202-209. \url{https://doi.org/10.1016/j.jas.2014.12.013}. } -\seealso{ -Other copper alloy classifications: -\code{\link{copper_alloy_bb}()}, -\code{\link{copper_alloy_pollard}()} -} -\concept{copper alloy classifications} diff --git a/man/elements.Rd b/man/elements.Rd new file mode 100644 index 0000000..af73262 --- /dev/null +++ b/man/elements.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{elements} +\alias{elements} +\title{Elements} +\format{ +a vector +} +\usage{ +elements +} +\description{ +List of elements, sorted according to alphabet +} +\seealso{ +Other chemical_reference_data: +\code{\link{isotopes}}, +\code{\link{oxides}} +} +\concept{chemical_reference_data} +\keyword{datasets} diff --git a/man/elements_data.Rd b/man/elements_data.Rd deleted file mode 100644 index f7c8c84..0000000 --- a/man/elements_data.Rd +++ /dev/null @@ -1,24 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_data.R -\docType{data} -\name{elements_data} -\alias{elements_data} -\title{Chemical elements} -\format{ -a vector -} -\usage{ -elements_data -} -\description{ -List of chemical elements as their symbols, sorted according to alphabet. -} -\seealso{ -Other chemical reference data: -\code{\link{conversion_oxides}}, -\code{\link{isotopes_data}}, -\code{\link{oxides_data}}, -\code{\link{special_oxide_states}} -} -\concept{chemical reference data} -\keyword{datasets} diff --git a/man/geom_kde2d.Rd b/man/geom_kde2d.Rd index c2f8cd6..aed442d 100644 --- a/man/geom_kde2d.Rd +++ b/man/geom_kde2d.Rd @@ -1,8 +1,8 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_geom_kde2.R +% Please edit documentation in R/geom_kde2.R \name{geom_kde2d} \alias{geom_kde2d} -\title{Draw 2D kernel density estimate polygons by quantiles} +\title{Draw 2D Kernel Density Estimate Polygons by Quantiles} \usage{ geom_kde2d( mapping = NULL, @@ -57,7 +57,7 @@ when no data exists, use \code{TRUE}. If \code{NA}, all levels are shown in leg but unobserved levels are omitted.} \item{fallback_to_points}{Logical. To prevent points from being drawn for -groups that fail density estimation, set this to \code{FALSE}. For example, if you +groups that fail density estimation, set this to FALSE. For example, if you want more control over the point aesthetics, independent of the KDE regions, set this to FALSE and use geom_point to plot those points} diff --git a/man/geom_sk_lines.Rd b/man/geom_sk_lines.Rd deleted file mode 100644 index 48cac01..0000000 --- a/man/geom_sk_lines.Rd +++ /dev/null @@ -1,174 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_geom_stacey_karmers.R -\name{geom_sk_lines} -\alias{geom_sk_lines} -\alias{geom_sk_labels} -\title{Lead Evolution Geom for Stacey & Kramers (1975)} -\usage{ -geom_sk_lines( - mapping = NULL, - data = NULL, - system = c("76", "86"), - Mu1 = 10, - Kappa = 4, - ... -) - -geom_sk_labels( - mapping = NULL, - data = NULL, - system = "76", - Mu1 = 10, - Kappa = 4, - ... -) -} -\arguments{ -\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and -\code{inherit.aes = TRUE} (the default), it is combined with the default mapping -at the top level of the plot. You must supply \code{mapping} if there is no plot -mapping.} - -\item{data}{The data to be displayed in this layer. There are three -options: - -If \code{NULL}, the default, the data is inherited from the plot -data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. - -A \code{data.frame}, or other object, will override the plot -data. All objects will be fortified to produce a data frame. See -\code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. - -A \code{function} will be called with a single argument, -the plot data. The return value must be a \code{data.frame}, and -will be used as the layer data. A \code{function} can be created -from a \code{formula} (e.g. \code{~ head(.x, 10)}).} - -\item{system}{Character "76" or "86" defining the isotope plot axis (default -"76").} - -\item{Mu1}{Second-stage 238U/204Pb ratio (default 10).} - -\item{Kappa}{Second-stage 232Th/238U ratio (default 4).} - -\item{...}{Additional parameters for the geoms (see \emph{Details}) and other -arguments passed on to \code{\link[ggplot2:layer]{ggplot2::layer()}}. These are often aesthetics used -to set a fixed value, such as \code{colour = "red"} or \code{alpha = 0.5}.} -} -\value{ -A ggplot2 layer object. -} -\description{ -These Geoms draws and label isochron, geochron, and kappa lines used for -isotope age model referencing in lead isotope biplots. The lines follows the -model used by Stacey & Kramers (1975). -} -\details{ -The plotting system follows the convention of showing geochron and isochron -lines for the 207Pb/204Pb vs. 206Pb/204Pb plot and the kappa lines for -208Pb/204Pb vs. 206Pb/204Pb plot. - -The geoms accept the following additional parameters through \code{...}: -\itemize{ -\item \code{Ti} : Initial time of the second stage in years (default 3.7 Ga). -\item \code{interval} : Time interval for isochron labels in years (default 200 Ma). -\item \code{show_geochron} : Logical; should the Geochron be plotted? (default \code{TRUE}). -\item \code{show_isochrons} : Logical; should time isochrons be plotted? (default \code{TRUE}) -\item \code{kappa_list} : Numeric vector of Kappa values to plot in "86" system. -} -} -\section{Note}{ -Currently the plot will scale the xlim and ylim to their maximum bounds. To -prevent this, use \code{\link[ggplot2:coord_cartesian]{coord_cartesian(xlim, ylim)}} -to force the axis range to the desired values. -} - -\section{Aesthetics}{ - \code{geom_sk_lines()} and \code{geom_sk_labels()} accept the -following aesthetic values: -\itemize{ -\item \code{alpha} -\item \code{colour} (controls the polygon outline) -\item \code{fill} (controls the polygon fill) -\item \code{linetype} -\item \code{linewidth} (controls the outline thickness) -\item \code{text.colour} (controls colour of the text) -\item \code{size.unit} (controls size aesthetic in "mm", "pt", "cm", "in" or "pc") - -Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. -} -} - -\examples{ -# example code - -library(ggplot2) -set.seed(50) -df <- data.frame( - pb64 = rnorm(10, 18,0.2), - pb74 = rnorm(10, 15.7,0.1), - pb84 = rnorm(10, 37.5,0.1) -) - -# Creating the Pb 207/204~206/204 plot -ggplot(df, aes(x = pb64, y = pb74)) + - geom_point() + - geom_sk_lines(system = "76") + - geom_sk_labels(system = "76") + - coord_cartesian( - xlim = range(df$pb64) * c(.99, 1.01), - ylim = range(df$pb74) * c(.99, 1.01) - ) + - labs( - x = expression({}^206*Pb / {}^204*Pb), - y = expression({}^207*Pb / {}^204*Pb), - ) - -# Creating the Pb 208/204~206/204 plot -ggplot(df, aes(x = pb64, y = pb84)) + - geom_point() + - geom_sk_lines(system = "86", - show_isochrons = FALSE, show_geochron = FALSE, - kappa_list = c(3.2, 3.4, 3.6, 3.8)) + - geom_sk_labels(system = "86", - show_isochrons = FALSE, show_geochron = FALSE, - kappa_list = c(3.2, 3.4, 3.6, 3.8)) + - coord_cartesian( - xlim = range(df$pb64) * c(.99, 1.01), - ylim = range(df$pb84) * c(.99, 1.01) - ) + - labs( - x = expression({}^206*Pb / {}^204*Pb), - y = expression({}^207*Pb / {}^204*Pb), - ) - -# Creating the Pb 207/204~206/204 plot with a seperate Geocrone color - -ggplot(df, aes(x = pb64, y = pb74)) + - geom_point() + - geom_sk_lines(system = "76", show_geochron = FALSE) + - geom_sk_lines(system = "76", show_isochrons = FALSE, - color = 'red', linetype = 'dashed') + - geom_sk_labels(system = "76", show_geochron = FALSE) + - geom_sk_labels(system = "76", show_isochrons = FALSE, color = 'red') + - coord_cartesian( - xlim = range(df$pb64) * c(.99, 1.01), - ylim = range(df$pb74) * c(.99, 1.01) - ) + - labs( - x = expression({}^206*Pb / {}^204*Pb), - y = expression({}^207*Pb / {}^204*Pb), - ) - -} -\references{ -Stacey, J.S. and Kramers, J.D. (1975) Approximation of -terrestrial lead isotope evolution by a two-stage model. Earth and -Planetary Science Letters 26(2), pp. 207–221. -\url{https://dx.doi.org/10.1016/0012-821X(75)90088-6}. -} -\seealso{ -Other Pb isotope functions: -\code{\link{age_models}} -} -\concept{Pb isotope functions} diff --git a/man/interactive_oxide_select.Rd b/man/interactive_oxide_select.Rd deleted file mode 100644 index b29e248..0000000 --- a/man/interactive_oxide_select.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_conversion_oxide.R -\name{interactive_oxide_select} -\alias{interactive_oxide_select} -\title{Interactive oxide selection} -\usage{ -interactive_oxide_select(elements) -} -\arguments{ -\item{elements}{A character vector with chemical symbols of elements} -} -\value{ -named vector with all oxides for the supplied list of elements -} -\description{ -Interactively compiles list of oxides from user input. -} -\keyword{internal} diff --git a/man/isotopes.Rd b/man/isotopes.Rd new file mode 100644 index 0000000..10ad16b --- /dev/null +++ b/man/isotopes.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{isotopes} +\alias{isotopes} +\title{Isotopes} +\format{ +a vector +} +\usage{ +isotopes +} +\description{ +List of naturally occurring isotopes, retrieved from https://www.ciaaw.org/isotopic-abundances.htm, +sorted according to chemical element and isotope number +} +\seealso{ +Other chemical_reference_data: +\code{\link{elements}}, +\code{\link{oxides}} +} +\concept{chemical_reference_data} +\keyword{datasets} diff --git a/man/isotopes_data.Rd b/man/isotopes_data.Rd deleted file mode 100644 index 53b0e20..0000000 --- a/man/isotopes_data.Rd +++ /dev/null @@ -1,26 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_data.R -\docType{data} -\name{isotopes_data} -\alias{isotopes_data} -\title{Isotopes} -\format{ -a vector -} -\usage{ -isotopes_data -} -\description{ -List of naturally occurring isotopes, retrieved from -https://www.ciaaw.org/isotopic-abundances.htm, sorted according to chemical -element and isotope number -} -\seealso{ -Other chemical reference data: -\code{\link{conversion_oxides}}, -\code{\link{elements_data}}, -\code{\link{oxides_data}}, -\code{\link{special_oxide_states}} -} -\concept{chemical reference data} -\keyword{datasets} diff --git a/man/normalise_rows.Rd b/man/normalise_rows.Rd deleted file mode 100644 index 7642585..0000000 --- a/man/normalise_rows.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_conversion_oxide.R -\name{normalise_rows} -\alias{normalise_rows} -\title{Normalise rows to 100\%} -\usage{ -normalise_rows(df) -} -\arguments{ -\item{df}{A matrix or data frame - -Normalises values in a vector to 100\%} -} -\description{ -Normalise rows to 100\% -} -\keyword{internal} diff --git a/man/oxide_conversion.Rd b/man/oxide_conversion.Rd deleted file mode 100644 index 7930a9e..0000000 --- a/man/oxide_conversion.Rd +++ /dev/null @@ -1,148 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_conversion_oxide.R -\name{oxide_conversion} -\alias{oxide_conversion} -\alias{element_to_oxide} -\alias{oxide_to_element} -\title{Oxide conversion functions} -\usage{ -element_to_oxide( - df, - elements = colnames(get_unit_columns(df, "wtP")), - oxide_preference, - which_concentrations = c("all", "major", "minor", "no_trace"), - normalise = FALSE, - drop = FALSE -) - -oxide_to_element( - df, - oxides = colnames(get_unit_columns(df, "wtP")), - normalise = FALSE, - drop = FALSE -) -} -\arguments{ -\item{df}{Data frame with compositional data.} - -\item{elements, oxides}{Character vector with the chemical symbols of the -elements or oxides that should be converted.} - -\item{oxide_preference}{String that controls which oxide should be used if an -element forms more than one oxide. Allowed values are: \code{reducing}, -\code{oxidising}, \code{ask}, or a named vector mapping the specific oxide to its -element. See \emph{Details} for further information.} - -\item{which_concentrations}{Character string that determines by concentration -which of the \code{elements} or \code{oxides} are converted. Allowed values are: -\itemize{ -\item \code{all} (convert all elements; the default) -\item \code{major} (convert elements with concentrations >= 1 wt\%) -\item \code{minor} (convert elements with concentrations between 0.1 and 1 wt\%). -\item \code{no_trace} (convert elements with concentrations >=0.1 wt\%) -}} - -\item{normalise}{If \code{TRUE}, converted concentrations will be normalised to -100\%. Default to \code{FALSE}.} - -\item{drop}{If \code{FALSE}, the default, columns with unconverted values are -kept. If \code{TRUE}, columns with unconverted values are dropped. Dropping -column could result in loss of information as this will also drop columns -with values excluded from conversion by the parameter -\code{which_concentrations}.} -} -\value{ -The original data frame with the converted concentrations -} -\description{ -Convert between element and oxide weight percent ("oxide\%") compositions -using pre-compiled conversion factors. -} -\details{ -If the dataset includes already an element and its oxide, the conversion -leaves the values of the respective oxide or element unaffected. The -functions convert only values in \emph{wt\%}. If concentrations are present in -another concentration unit (e.g. \emph{ppm}, \emph{µg/kg}), run -\code{\link[=unify_concentration_unit]{unify_concentration_unit(df, "wtP")}} first to -convert all concentrations to \emph{wt\%}. If the input is an \code{\link[=ASTR]{ASTR object}}, the functions convert only elements or oxides with the -respective other type being automatically excluded, even though the unit for -both is \emph{wt\%}. To convert oxides into \emph{at\%} and vice versa, convert to -\emph{wt\%} first. - -In \code{element_to_oxide()}, the parameter \code{oxide_preference} controls the -behaviour of the function if the element forms more than one oxide: -\itemize{ -\item \code{oxidising}: Use the oxide with the highest oxidation state of the element -(e.g., \code{Fe2O3}) -\item \code{reducing}: Use the oxide with the lowest oxidation state of the element -(e.g., \code{FeO}) -\item \code{ask}: The user is asked for each element which oxide should be used. -\item named vector: A named vector mapping the oxides to be used to the -elements (e.g., \code{c(Fe = "FeO", Cu = "Cu2O")}) -} - -In \code{oxide_to_element()}, conversions from different oxides to the same -element (e.g., Fe\if{html}{\out{}}2\if{html}{\out{}}O\if{html}{\out{}}3\if{html}{\out{}} and FeO to Fe) result in one -column for the element with the sum of all converted values of the respective -element. - -Conversion factors are pre-compiled for a wide range of oxides. consequently, -conversion is restricted to the oxides on this list. If you encounter an -oxide that is currently not included, please reach out to the package -maintainers or create a pull request in the \href{https://github.com/archaeothommy/ASTR}{package's GitHub repo} to add it. -} -\examples{ - -library(magrittr) - -# Example data frame with element weight percents -df <- data.frame(ID = "Sample1", Si = 45, Fe = 50, Cr = 5) - -# Select elements by oxide_preference -element_to_oxide(df, elements = c("Si", "Fe", "Cr"), oxide_preference = "oxidising") -element_to_oxide(df, elements = c("Fe", "Cr"), oxide_preference = c(Fe = "FeO", Cr = "Cr2O3")) -\dontrun{ -element_to_oxide(df, elements = c("Si", "Fe", "Cr"), oxide_preference = "ask") -} - -# Conversions are reversible -oxides <- element_to_oxide( - df, - elements = names(df[-1]), - oxide_preference = "oxidising", - drop = TRUE -) -elements <- oxide_to_element( - oxides, - oxides = names(oxides[-1]), - drop = TRUE -) -all.equal(df, elements) - -# Loss of information by using 'which_concentration' to convert a subset when 'drop = TRUE' -df2 <- data.frame(ID = "feldspar", Na = 8.77, Al = 10.29, Si = 32.13, Ba = 0.3, Sr = 0.05) -element_to_oxide( - df2, - elements = names(df2[-1]), - which_concentration = "major", - oxide_preference = "reducing", - drop = TRUE -) - -# Conversion from oxide to element summarises columns converting to the same element -df3 <- data.frame(Fe2O3 = 20, FeO = 20, Cr2O3 = 15, CrO2 = 15, CuO = 20, Cu2O = 20) -oxide_to_element(df3, oxides = names(df3), drop = TRUE) - -# Use with ASTR objects -# Create ASTR object -test_file <- system.file("extdata", "test_data_input_good.csv", package = "ASTR") -arch <- read_ASTR(test_file, id_column = "Sample", context = 1:7) - -# Convert columns from oxide to wt\% -arch_wtP <- element_to_oxide(arch, oxide_preference = "oxidising") - -# To convert all applicable concentrations, unify units first: -arch_all <- unify_concentration_unit(arch, "wtP") \%>\% - element_to_oxide(oxide_preference = "oxidising") - -} diff --git a/man/oxides.Rd b/man/oxides.Rd new file mode 100644 index 0000000..bbba673 --- /dev/null +++ b/man/oxides.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{oxides} +\alias{oxides} +\title{Oxides} +\format{ +a vector +} +\usage{ +oxides +} +\description{ +List of oxides, retrieved from https://www.wikidoc.org/index.php/Oxide, +sorted according to alphabet +} +\seealso{ +Other chemical_reference_data: +\code{\link{elements}}, +\code{\link{isotopes}} +} +\concept{chemical_reference_data} +\keyword{datasets} diff --git a/man/oxides_data.Rd b/man/oxides_data.Rd deleted file mode 100644 index 7e1de6f..0000000 --- a/man/oxides_data.Rd +++ /dev/null @@ -1,24 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_data.R -\docType{data} -\name{oxides_data} -\alias{oxides_data} -\title{Oxides} -\format{ -a vector -} -\usage{ -oxides_data -} -\description{ -List of oxides, sorted according to alphabet. -} -\seealso{ -Other chemical reference data: -\code{\link{conversion_oxides}}, -\code{\link{elements_data}}, -\code{\link{isotopes_data}}, -\code{\link{special_oxide_states}} -} -\concept{chemical reference data} -\keyword{datasets} diff --git a/man/pointcloud_distribution.Rd b/man/pointcloud_distribution.Rd index 6b31734..3ac69c9 100644 --- a/man/pointcloud_distribution.Rd +++ b/man/pointcloud_distribution.Rd @@ -1,8 +1,8 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_pointcloud_distribution.R +% Please edit documentation in R/pointcloud_distribution.R \name{pointcloud_distribution} \alias{pointcloud_distribution} -\title{Comparing isotope samples to reference data in 3D space} +\title{Comparing Isotope Samples to Reference Data in 3D Space} \usage{ pointcloud_distribution( df, @@ -10,7 +10,7 @@ pointcloud_distribution( isotope_sample = c("206Pb/204Pb", "207Pb/204Pb", "208Pb/204Pb"), isotope_ref = isotope_sample, id_sample = "ID", - id_ref = "ID" + id_ref = id_sample ) } \arguments{ @@ -23,11 +23,8 @@ column.} \item{isotope_sample, isotope_ref}{Character vectors with column names of isotope ratios. Default to \code{c("206Pb/204Pb", "207Pb/204Pb", "208Pb/204Pb")}.} -\item{id_sample}{String with the column name of the sample IDs. Default is -\code{ID}} - -\item{id_ref}{String with the column name of the variable used for subsetting -the reference data. Default is "ID".} +\item{id_sample, id_ref}{String with the column name of the sample IDs and +identifier for the reference groups. Default \code{ID}.} } \value{ A \code{list} of three elements: @@ -55,13 +52,13 @@ The function also calculates: \item The \strong{centroid} of each reference subgroup as \strong{mean value} of points within each vertex group. \item The \strong{distance} from each sample point to every subgroup's centroid. +} -Interpretation: Inclusion within a hull suggests the sample is part of the -\strong{mixing group} (main hull) or is highly likely to be the specific \strong{end +Interpretation: Inclusion within a hull suggests the sample is part of +the \strong{mixing group} (main hull) or is highly likely to be the specific \strong{end member} (subgroup hull). The distance calculation provides a measure of proximity to these end member centers. } -} \examples{ # Create synthetic data set.seed(24021999) diff --git a/man/special_oxide_states.Rd b/man/special_oxide_states.Rd deleted file mode 100644 index 605dee9..0000000 --- a/man/special_oxide_states.Rd +++ /dev/null @@ -1,24 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_data.R -\docType{data} -\name{special_oxide_states} -\alias{special_oxide_states} -\title{Special oxide states} -\format{ -a vector -} -\usage{ -special_oxide_states -} -\description{ -List of values that are treated like oxides, but are no chemical oxides. -} -\seealso{ -Other chemical reference data: -\code{\link{conversion_oxides}}, -\code{\link{elements_data}}, -\code{\link{isotopes_data}}, -\code{\link{oxides_data}} -} -\concept{chemical reference data} -\keyword{datasets} diff --git a/man/sum_duplicates.Rd b/man/sum_duplicates.Rd deleted file mode 100644 index f5b55ed..0000000 --- a/man/sum_duplicates.Rd +++ /dev/null @@ -1,16 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_conversion_oxide.R -\name{sum_duplicates} -\alias{sum_duplicates} -\title{Sum columns with same column name} -\usage{ -sum_duplicates(df) -} -\arguments{ -\item{df}{A data frame} -} -\description{ -The function recognises and includes column names that in fact have the same -name but were made unique by R functions. -} -\keyword{internal} diff --git a/man/transform_notation.Rd b/man/transform_notation.Rd deleted file mode 100644 index 88c96dc..0000000 --- a/man/transform_notation.Rd +++ /dev/null @@ -1,16 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ASTR_utils.R -\name{transform_notation} -\alias{transform_notation} -\title{Transform unit in ratio notation into notation with negative exponents} -\usage{ -transform_notation(unit) -} -\arguments{ -\item{unit}{Character string} -} -\description{ -This is necessary to align with output of units from \code{\link[units:deparse_unit]{units::deparse_unit()}}. -Example: m/s2 -> m s-2 -} -\keyword{internal} diff --git a/tests/testthat.R b/tests/testthat.R index 6be89e9..71c9383 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -8,5 +8,6 @@ library(testthat) library(ASTR) +library(tibble) test_check("ASTR") diff --git a/tests/testthat/_snaps/ASTR_basic.md b/tests/testthat/_snaps/ASTR_basic.md deleted file mode 100644 index e2aaf91..0000000 --- a/tests/testthat/_snaps/ASTR_basic.md +++ /dev/null @@ -1,183 +0,0 @@ -# reading of a basic example table works as expected - - Code - as.data.frame(test_input) - Output - ID 206Pb/204Pb Al2O3 SiO2+Al2O3 204Pb other other2 K2O - 1 troet 0.5 3 [count/s] 20 [ng/kg] 7 [mg/kg] troet 27 23 [wtP] - d18O SiO2/FeO Mn Zn SiO2/(FeO+MnO) Sb/As Sn - 1 -5.32 0.5 2.45 [atP] 240 [mg/kg] 0.32 5.69 56 [µg/g] - K2O+MgO+Na2O - 1 54 [wtP] - ---- - - Code - as.data.frame(test_input2) - Output - ID Sample Lab no. Site latitude longitude Type - 1 TR-001 TR-001 3421/19 Bochum 51.48165 7.216480 1 - 2 TR-002_1 TR-002_1 3423/19 Oviedo 43.36029 -5.844760 2 - 3 TR-002_2 TR-002_2 3435/19 Oviedo 43.36029 -5.844760 2 - 4 TR-003 TR-003 3422/19 佛山 23.02677 113.131480 3 - 5 TR-004 TR-004 3429/19 Băiuț 43.23490 23.124983 4 - 6 TR-005 TR-005 3430/19 Şuior 41.44557 24.935661 5 - 7 TR-006.1 TR-006.1 3431/19 Blagodat 41.45313 25.505011 5 - 8 TR-006.2 TR-006.2 3432/19 Pezinok 45.92125 15.919219 1 - 9 TR-006.3 TR-006.3 3433/19 Free State Geduld Mines 50.35621 7.651314 4 - 10 smn348 smn348 3424/19 Aggenys 50.99160 8.027573 3 - 11 smn349 smn349 3425/19 Chiprovtsi 50.68903 6.406379 3 - 12 smn350 smn350 3426/19 Krusov Dol; Krushev Dol 40.69575 24.591976 5 - 13 smn351 smn351 3427/19 Masua 37.72618 24.012951 1 - 14 8896 8896 3428/19 Σπαρτη 37.07446 22.430090 1 - method_comp 143Nd/144Nd d65Cu d65Cu_err2SD Na2O BaO Pb - 1 ICP-MS 0.513014 1.24 0.1240 3.1 [wtP] 0.070 [wtP] 6.34 [wtP] - 2 ICP-MS 0.512994 0.88 0.0600 2.2 [wtP] 0.070 [wtP] 3.52 [wtP] - 3 ICP-MS 0.512996 0.85 0.0500 5.0 [wtP] 0.054 [wtP] 3.60 [wtP] - 4 ICP-MS 0.513008 2.76 0.2760 6.9 [wtP] 0.040 [wtP] 5.07 [wtP] - 5 ICP-MS NA -8.21 -0.8210 3.0 [wtP] 0.030 [wtP] 9.15 [wtP] - 6 ICP-MS NA 0.06 0.0040 4.1 [wtP] 0.070 [wtP] 12.61 [wtP] - 7 ICP-MS NA 1.48 0.2220 3.4 [wtP] 0.050 [wtP] 12.68 [wtP] - 8 ICP-MS NA -0.42 -0.0420 1.8 [wtP] 0.040 [wtP] 5.31 [wtP] - 9 ICP-MS NA 0.30 0.0200 5.1 [wtP] 0.090 [wtP] 2.36 [wtP] - 10 ICP-MS 0.512977 0.24 0.0240 4.1 [wtP] 0.340 [wtP] 47.49 [wtP] - 11 ICP-MS 0.513004 0.54 0.0100 3.4 [wtP] 0.040 [wtP] 2.53 [wtP] - 12 ICP-MS 0.512991 2.04 0.8000 4.5 [wtP] 0.070 [wtP] 1.56 [wtP] - 13 ICP-MS NA -0.24 -0.0504 3.2 [wtP] 0.040 [wtP] 3.64 [wtP] - 14 ICP-MS NA -0.42 -0.0420 3.7 [wtP] 0.060 [wtP] 7.51 [wtP] - MgO Al2O3 SiO2 SiO2_errSD% P2O5 S - 1 0.77 [wtP] 3.92 [wtP] 31.63 [wtP] 4.30 [%] 0.15 [wtP] 2.57 [atP] - 2 0.55 [wtP] 3.46 [wtP] 29.06 [wtP] 2.88 [%] NA [wtP] NA [atP] - 3 0.33 [wtP] 5.87 [wtP] 30.50 [wtP] 5.71 [%] 0.11 [wtP] 3.68 [atP] - 4 0.76 [wtP] 4.33 [wtP] 25.73 [wtP] 2.22 [%] 0.23 [wtP] 2.76 [atP] - 5 0.52 [wtP] 4.17 [wtP] 43.50 [wtP] 4.65 [%] 0.40 [wtP] 0.57 [atP] - 6 0.58 [wtP] 3.58 [wtP] 33.83 [wtP] 3.67 [%] 0.29 [wtP] 0.61 [atP] - 7 0.64 [wtP] 5.60 [wtP] 33.81 [wtP] 3.00 [%] 0.43 [wtP] 0.77 [atP] - 8 0.59 [wtP] 4.47 [wtP] 26.39 [wtP] 2.87 [%] 0.62 [wtP] 3.04 [atP] - 9 0.53 [wtP] 3.73 [wtP] 21.18 [wtP] 3.44 [%] 0.24 [wtP] 3.93 [atP] - 10 0.70 [wtP] 6.27 [wtP] 31.73 [wtP] 6.12 [%] 0.28 [wtP] 0.21 [atP] - 11 0.46 [wtP] 2.91 [wtP] 16.91 [wtP] 3.73 [%] 0.22 [wtP] 3.57 [atP] - 12 0.58 [wtP] 3.60 [wtP] 28.49 [wtP] 4.89 [%] 0.19 [wtP] 1.95 [atP] - 13 0.88 [wtP] 5.24 [wtP] 38.04 [wtP] 10.12 [%] 0.30 [wtP] 1.35 [atP] - 14 0.84 [wtP] 3.97 [wtP] 31.67 [wtP] 4.30 [%] 0.18 [wtP] 0.83 [atP] - CaO TiO2 MnO FeOtot FeOtot_err2SD ZnO - 1 2.11 [wtP] 0.52 [wtP] 0.20 [wtP] 43.83 [wtP] 4.120 [wtP] 5.64 [%] - 2 2.34 [wtP] 0.49 [wtP] 0.54 [wtP] 51.02 [wtP] 3.890 [wtP] 4.07 [%] - 3 2.00 [wtP] 0.55 [wtP] 0.10 [wtP] 30.59 [wtP] 2.940 [wtP] 6.87 [%] - 4 3.91 [wtP] 0.27 [wtP] 0.70 [wtP] 46.09 [wtP] 3.500 [wtP] 5.87 [%] - 5 1.79 [wtP] 0.24 [wtP] 1.00 [wtP] 31.91 [wtP] 2.870 [wtP] 2.26 [%] - 6 2.06 [wtP] 0.18 [wtP] 0.49 [wtP] 36.57 [wtP] 5.486 [wtP] 1.66 [%] - 7 NA [wtP] NA [wtP] 1.52 [wtP] 35.52 [wtP] 2.660 [wtP] 2.46 [%] - 8 4.28 [wtP] NA [wtP] 0.40 [wtP] 41.20 [wtP] 3.890 [wtP] 11.65 [%] - 9 4.08 [wtP] 0.15 [wtP] 0.46 [wtP] 48.26 [wtP] 2.268 [wtP] 6.80 [%] - 10 7.14 [wtP] NA [wtP] 0.24 [wtP] 5.26 [wtP] 0.305 [wtP] 0.03 [%] - 11 2.50 [wtP] 0.14 [wtP] 0.21 [wtP] 56.36 [wtP] 6.763 [wtP] 4.89 [%] - 12 1.39 [wtP] 0.17 [wtP] 0.13 [wtP] 47.64 [wtP] 4.235 [wtP] 6.56 [%] - 13 2.10 [wtP] 0.34 [wtP] 1.32 [wtP] 43.21 [wtP] 2.161 [wtP] 1.52 [%] - 14 3.51 [wtP] 0.24 [wtP] 0.34 [wtP] 45.90 [wtP] 2.387 [wtP] 0.85 [%] - K2O Cu As LOI Ag Sn - 1 1.34 [wtP] 0.11 [wtP] 0.02 [wtP] 1.89 [wtP] 500 [ng/g] 85 [µg/ml] - 2 1.26 [wtP] 0.22 [wtP] 0.01 [wtP] NA [wtP] 200 [ng/g] 85 [µg/ml] - 3 1.54 [wtP] 0.74 [wtP] NA [wtP] NA [wtP] 210 [ng/g] 98 [µg/ml] - 4 1.66 [wtP] 0.13 [wtP] 0.01 [wtP] NA [wtP] 350 [ng/g] 45 [µg/ml] - 5 2.15 [wtP] 0.14 [wtP] 0.03 [wtP] 3.57 [wtP] 400 [ng/g] 14 [µg/ml] - 6 1.21 [wtP] 0.09 [wtP] 0.11 [wtP] 5.66 [wtP] 250 [ng/g] 181 [µg/ml] - 7 2.26 [wtP] 0.21 [wtP] 0.23 [wtP] 0.12 [wtP] 120 [ng/g] 566 [µg/ml] - 8 1.86 [wtP] 0.43 [wtP] 0.02 [wtP] 0.89 [wtP] 430 [ng/g] 203 [µg/ml] - 9 2.01 [wtP] 0.59 [wtP] 0.08 [wtP] 4.75 [wtP] 300 [ng/g] 5594 [µg/ml] - 10 1.34 [wtP] 0.07 [wtP] 0.06 [wtP] NA [wtP] 2420 [ng/g] 32 [µg/ml] - 11 1.34 [wtP] 0.15 [wtP] 0.01 [wtP] 4.22 [wtP] 140 [ng/g] 23 [µg/ml] - 12 0.98 [wtP] 0.16 [wtP] 0.02 [wtP] 6.01 [wtP] 1610 [ng/g] 45 [µg/ml] - 13 1.48 [wtP] 0.27 [wtP] 0.05 [wtP] 3.22 [wtP] 100 [ng/g] 15 [µg/ml] - 14 1.32 [wtP] 0.09 [wtP] 0.14 [wtP] NA [wtP] 100 [ng/g] 146 [µg/ml] - Sb Te Bi U V Cr - 1 370 [mg/kg] 2 [mg/kg] 18 [mg/kg] 3 [mg/kg] 60 [mg/kg] 160 [mg/kg] - 2 210 [mg/kg] 2 [mg/kg] 20 [mg/kg] 2 [mg/kg] 60 [mg/kg] 140 [mg/kg] - 3 256 [mg/kg] NA [mg/kg] 47 [mg/kg] NA [mg/kg] 63 [mg/kg] 99 [mg/kg] - 4 400 [mg/kg] 2 [mg/kg] NA [mg/kg] 2 [mg/kg] 45 [mg/kg] 30 [mg/kg] - 5 410 [mg/kg] 2 [mg/kg] 6 [mg/kg] 3 [mg/kg] 55 [mg/kg] 75 [mg/kg] - 6 453 [mg/kg] 6 [mg/kg] 9 [mg/kg] 3 [mg/kg] 54 [mg/kg] 41 [mg/kg] - 7 701 [mg/kg] 8 [mg/kg] 9 [mg/kg] NA [mg/kg] 75 [mg/kg] 106 [mg/kg] - 8 231 [mg/kg] 15 [mg/kg] 3 [mg/kg] NA [mg/kg] 84 [mg/kg] 91 [mg/kg] - 9 107 [mg/kg] 6 [mg/kg] 5 [mg/kg] 5 [mg/kg] 32 [mg/kg] 63 [mg/kg] - 10 3310 [mg/kg] 9 [mg/kg] 150 [mg/kg] NA [mg/kg] 61 [mg/kg] 45 [mg/kg] - 11 95 [mg/kg] 5 [mg/kg] 1 [mg/kg] 3 [mg/kg] 37 [mg/kg] 36 [mg/kg] - 12 78 [mg/kg] 5 [mg/kg] 4 [mg/kg] 3 [mg/kg] 40 [mg/kg] 33 [mg/kg] - 13 610 [mg/kg] 2 [mg/kg] 1 [mg/kg] 2 [mg/kg] 80 [mg/kg] 190 [mg/kg] - 14 390 [mg/kg] NA [mg/kg] NA [mg/kg] 1 [mg/kg] 40 [mg/kg] 100 [mg/kg] - Co Ni Sr Se FeOtot/SiO2 (Na2O+K2O)/SiO2 - 1 60 [mg/kg] 60 [mg/kg] 130 [mg/kg] NA [mg/kg] 1.386 0.14037 - 2 70 [mg/kg] 100 [mg/kg] 120 [mg/kg] NA [mg/kg] 1.756 0.11906 - 3 55 [mg/kg] 87 [mg/kg] 121 [mg/kg] 15 [mg/kg] 1.003 0.21443 - 4 30 [mg/kg] 20 [mg/kg] 250 [mg/kg] NA [mg/kg] 1.791 0.33269 - 5 NA [mg/kg] 10 [mg/kg] 160 [mg/kg] NA [mg/kg] 0.734 0.11839 - 6 8 [mg/kg] 47 [mg/kg] 258 [mg/kg] NA [mg/kg] 1.081 0.15696 - 7 22 [mg/kg] 19 [mg/kg] 122 [mg/kg] 3 [mg/kg] 1.051 0.16741 - 8 47 [mg/kg] 34 [mg/kg] 280 [mg/kg] 3 [mg/kg] 1.561 0.13869 - 9 17 [mg/kg] 37 [mg/kg] 310 [mg/kg] NA [mg/kg] 2.279 0.33569 - 10 NA [mg/kg] 4 [mg/kg] 287 [mg/kg] 5 [mg/kg] 0.166 0.17145 - 11 69 [mg/kg] 39 [mg/kg] 155 [mg/kg] NA [mg/kg] 3.333 0.28031 - 12 43 [mg/kg] 39 [mg/kg] 165 [mg/kg] NA [mg/kg] 1.672 0.19235 - 13 20 [mg/kg] 50 [mg/kg] 100 [mg/kg] NA [mg/kg] 1.136 0.12303 - 14 10 [mg/kg] 65 [mg/kg] 120 [mg/kg] NA [mg/kg] 1.449 0.15851 - 206Pb/204Pb 206Pb/204Pb_err2SD 207Pb/204Pb 207Pb/204Pb_err2SD 208Pb/204Pb - 1 18.61147 0.01082 15.65405 0.00915 38.75630 - 2 18.61617 0.01629 15.65682 0.01341 38.76404 - 3 18.61615 0.01698 15.65740 0.01441 38.76411 - 4 18.61272 0.00926 15.65677 0.00747 38.76097 - 5 18.63562 0.01189 15.64765 0.00989 38.73583 - 6 18.63952 0.01802 15.65502 0.01513 38.75729 - 7 18.64465 0.01468 15.65836 0.01210 38.76615 - 8 18.83274 0.01608 15.82161 0.01350 39.20161 - 9 18.83312 0.01875 15.82042 0.01619 39.20067 - 10 18.80371 0.03129 15.81646 0.02600 39.15557 - 11 18.80760 0.01550 15.82128 0.01309 39.17608 - 12 18.81356 0.01557 15.82045 0.01305 39.17244 - 13 18.81501 0.01535 15.80824 0.01350 39.13346 - 14 18.82037 0.01483 15.81119 0.01252 39.13715 - 208Pb/204Pb_err2SD 207Pb/206Pb 207Pb/206Pb_err2SD 208Pb/206Pb - 1 0.02270 0.84110 0.00006 2.08239 - 2 0.03450 0.84103 0.00013 2.08229 - 3 0.03452 0.84107 0.00014 2.08228 - 4 0.01820 0.84119 0.00010 2.08251 - 5 0.02561 0.83966 0.00009 2.07858 - 6 0.04157 0.83989 0.00012 2.07923 - 7 0.02716 0.83984 0.00009 2.07928 - 8 0.03356 0.84852 0.00007 2.10238 - 9 0.04173 0.84846 0.00007 2.10235 - 10 0.06458 0.84955 0.00007 2.10313 - 11 0.03091 0.84963 0.00012 2.10388 - 12 0.03263 0.84931 0.00007 2.10297 - 13 0.03109 0.84859 0.00007 2.10076 - 14 0.03182 0.84851 0.00007 2.10030 - 208Pb/206Pb_err2SD - 1 0.00017 - 2 0.00033 - 3 0.00033 - 4 0.00025 - 5 0.00023 - 6 0.00032 - 7 0.00023 - 8 0.00017 - 9 0.00018 - 10 0.00026 - 11 0.00022 - 12 0.00022 - 13 0.00018 - 14 0.00024 - ---- - - Code - print(test_input) - Output - ASTR table - Analytical columns: 206Pb/204Pb, Al2O3, SiO2+Al2O3, 204Pb, K2O, d18O, SiO2/FeO, Mn, Zn, SiO2/(FeO+MnO), Sb/As, Sn, K2O+MgO+Na2O - Contextual columns: other, other2 - # A data frame: 1 x 16 - ID `206Pb/204Pb` Al2O3 `SiO2+Al2O3` `204Pb` other other2 K2O d18O - [count/s] [ng/kg] [mg/kg] [wtP] - 1 troet 0.5 3 20 7 troet 27 23 -5.32 - # i 7 more variables: `SiO2/FeO` , Mn [atP], Zn [mg/kg], - # `SiO2/(FeO+MnO)` , `Sb/As` , Sn [µg/g], `K2O+MgO+Na2O` [wtP] - diff --git a/tests/testthat/_snaps/archchem_basic.md b/tests/testthat/_snaps/archchem_basic.md new file mode 100644 index 0000000..3b8c409 --- /dev/null +++ b/tests/testthat/_snaps/archchem_basic.md @@ -0,0 +1,12 @@ +# reading of a basic example table works as expected + + Code + as.data.frame(test_input) + Output + ID 206Pb/204Pb Al2O3_cps SiO2+Al2O3_ppt 204Pb_ppm other other2 K2O_wt% + 1 troet 0.5 3 [count/s] 20 [ppt] 7 [ppm] troet 27 23 [%] + d18O SiO2/FeO Mn_at% Zn_ppm SiO2/(FeO+MnO) Sb/As Sn_µg/g + 1 -5.32 0.5 2.45 [%] 240 [ppm] 0.32 5.69 56 [µg/g] + K2O+MgO+Na2O_wt% + 1 54 [%] + diff --git a/tests/testthat/_snaps/geom_kde2d/kde-astr.svg b/tests/testthat/_snaps/geom_kde2d/kde-astr.svg deleted file mode 100644 index 45e1267..0000000 --- a/tests/testthat/_snaps/geom_kde2d/kde-astr.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -0 -5 -10 - - - - - - -0 -4 -8 -207Pb/206Pb -208Pb/206Pb - -group - - - - - - -A -B -C -KDE_ASTR - - diff --git a/tests/testthat/_snaps/geom_kde2d/kde-df.svg b/tests/testthat/_snaps/geom_kde2d/kde-df.svg deleted file mode 100644 index dafd849..0000000 --- a/tests/testthat/_snaps/geom_kde2d/kde-df.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -0 -4 -8 - - - - - - -0 -4 -8 -x -y - -group - - - - - - -A -B -C -KDE_df - - diff --git a/tests/testthat/_snaps/goem_sk_lines/image.svg b/tests/testthat/_snaps/goem_sk_lines/image.svg deleted file mode 100644 index 996ced9..0000000 --- a/tests/testthat/_snaps/goem_sk_lines/image.svg +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Mu 10 -Mu 10 -T0 -T200 -T400 -T600 -T800 -T1000 -T1200 -T1400 -T1600 -T1800 -T2000 -T2200 -T2400 -T2600 -T2800 -T3000 -T3200 -T3400 -T3600 -Mu 10 -Mu 10 -Geochron - - - -15.5 -15.6 -15.7 -15.8 -15.9 - - - - - - - - - - -17.6 -17.8 -18.0 -18.2 -18.4 -pb64 -pb74 -image - - diff --git a/tests/testthat/setup.R b/tests/testthat/setup.R index a001395..6e5e215 100644 --- a/tests/testthat/setup.R +++ b/tests/testthat/setup.R @@ -2,13 +2,7 @@ # Additional packages to load for testing or setting up the test environment -library(testthat) -library(ASTR) -library(tibble) -library(ggplot2) library(vdiffr) -library(readxl) -library(units) # reference data sets diff --git a/tests/testthat/test-copper_alloy_bb.R b/tests/testthat/test-copper_alloy_bb.R new file mode 100644 index 0000000..1492f2b --- /dev/null +++ b/tests/testthat/test-copper_alloy_bb.R @@ -0,0 +1,25 @@ +test_that("Bayley & Butcher copper alloy classification", { + test_data <- data.frame( + ID = 1:11, + Sn = c(1, 1, 5, 5, 5, 5, 0.5, 5, NA, 5, 5), + Zn = c(2, 5, 2, 4, 8, 15, 2, 8, 2, NA, 8), + Pb = c(0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 9, 6, 0.5, 0.5, NA) + ) + result <- copper_alloy_bb(test_data) + expect_equal( + result$copper_alloy_bb, + c( + "Copper", # ID 1: Zn<3, Sn<3 + "Copper/brass", # ID 2: 3<=Zn<8, Sn<3 + "Bronze/gunmetal", # ID 3: Sn>=3, 0.33*Sn=3, 0.67*Sn=3, 0.67*Sn2.5*Sn, Zn<=4*Sn + "Leaded Copper", # ID 7: Copper + Pb>8 + "(Leaded) Gunmetal", # ID 8: Gunmetal + 4<=Pb<=8 + "Unclassified", # ID 9: NA Sn + "Unclassified", # ID 10: NA Zn + "Unclassified" # ID 11: NA Pb + ) + ) +}) diff --git a/tests/testthat/test_ASTR_basic.R b/tests/testthat/test_ASTR_basic.R deleted file mode 100644 index aba6102..0000000 --- a/tests/testthat/test_ASTR_basic.R +++ /dev/null @@ -1,64 +0,0 @@ -# golden tests - -test_input <- read_ASTR( - system.file("extdata", "input_format.csv", package = "ASTR"), - id_column = "other", - context = c("other", "other2") -) - -test_input_xlsx <- read_ASTR( - system.file("extdata", "input_format.xlsx", package = "ASTR"), - id_column = "other", - context = c("other", "other2") -) - -test_input2 <- suppressWarnings( - read_ASTR( - system.file("extdata", "test_data_input_good.csv", package = "ASTR"), - id_column = "Sample", - context = c("Lab no.", "Site", "latitude", "longitude", "Type", "method_comp") - ) -) - -test_input3 <- readr::read_csv(system.file("extdata", "input_format.csv", package = "ASTR")) -test_input3[2, ] <- test_input3[1, ] -test_input3 <- suppressWarnings( - as_ASTR(test_input3, id_column = "other2", context = "other") -) - -test_that("reading of a basic example table works as expected", { - expect_snapshot({ - # turn to data.frame to render the entire table - as.data.frame(test_input) - }) - expect_equal(test_input_xlsx, test_input) - expect_snapshot({ - # turn to data.frame to render the entire table - as.data.frame(test_input2) - }) - expect_snapshot({ - print(test_input) - }) - # checks that automatic renaming of ID values works - expect_all_equal(test_input3$ID[2], "27_2") -}) - -# parsing throws expected errors - -test_input3 <- readr::read_csv(system.file("extdata", "input_format.csv", package = "ASTR")) -test_input3[2, ] <- test_input3[1, ] - -test_that("archem functions result in expected errors and warnings", { - expect_error( - suppressWarnings(as_ASTR(test_input3, id_column = "other")), - "Column name .* could not be parsed" - ) - expect_warning( - as_ASTR(test_input3, id_column = "other", context = "other2"), - "Detected multiple data rows with the same ID" - ) - expect_error( - validate(2), - "x is not an object of class ASTR" - ) -}) diff --git a/tests/testthat/test_ASTR_column_selection.R b/tests/testthat/test_ASTR_column_selection.R deleted file mode 100644 index 860bfd5..0000000 --- a/tests/testthat/test_ASTR_column_selection.R +++ /dev/null @@ -1,39 +0,0 @@ -# test columns selection function not checked elsewhere - -test_input <- suppressWarnings( - read_ASTR( - system.file("extdata", "test_data_input_good.csv", package = "ASTR"), - id_column = "Sample", - context = c("Lab no.", "Site", "latitude", "longitude", "Type", "method_comp") - ) -) - -test_that("column selection based on ASTR column types", { - expect_all_true( - colnames(get_isotope_columns(test_input)) == - c("ID", "143Nd/144Nd", "d65Cu", "206Pb/204Pb", "207Pb/204Pb", "208Pb/204Pb", - "207Pb/206Pb", "208Pb/206Pb" - ) - ) - expect_all_true( - colnames(get_element_columns(test_input)) == - c("ID", "FeOtot/SiO2", "(Na2O+K2O)/SiO2") - ) - expect_all_true( - colnames(get_ratio_columns(test_input)) == - c("ID", "143Nd/144Nd", "d65Cu", "FeOtot/SiO2", "(Na2O+K2O)/SiO2", "206Pb/204Pb", "207Pb/204Pb", - "208Pb/204Pb", "207Pb/206Pb", "208Pb/206Pb" - ) - ) - expect_all_true( - colnames(get_concentration_columns(test_input)) == - c("ID", "Na2O", "BaO", "Pb", "MgO", "Al2O3", "SiO2", "P2O5", "S", "CaO", "TiO2", - "MnO", "FeOtot", "ZnO", "K2O", "Cu", "As", "LOI", "Ag", "Sn", "Sb", "Te", "Bi", - "U", "V", "Cr", "Co", "Ni", "Sr", "Se" - ) - ) - expect_all_true( - colnames(get_unit_columns(test_input, c("ng/g", "µg/ml", "%"))) == - c("ID", "SiO2_errSD%", "ZnO", "Ag", "Sn") - ) -}) diff --git a/tests/testthat/test_ASTR_unit_manipulation.R b/tests/testthat/test_ASTR_unit_manipulation.R deleted file mode 100644 index a2747d6..0000000 --- a/tests/testthat/test_ASTR_unit_manipulation.R +++ /dev/null @@ -1,56 +0,0 @@ -# test columns selection function not checked elsewhere - -test_input <- suppressWarnings( - read_ASTR( - system.file("extdata", "test_data_input_good.csv", package = "ASTR"), - id_column = "Sample", - context = c("Lab no.", "Site", "latitude", "longitude", "Type", "method_comp") - ) -) - -no_unit <- remove_units(test_input, recover_unit_names = TRUE) - -test_that("units are removed from ASTR objects", { - expect_false(inherits(no_unit$`Co_mg/kg`, "units")) - expect_all_true(c("Te_mg/kg", "As_wt%", "S_at%") %in% colnames(no_unit)) -}) - - -unify_units <- unify_concentration_unit(test_input, "µg/g") - -test_that("concentrations are unified", { - expect_false(units(test_input$Na2O) == units(unify_units$Na2O)) - expect_all_equal(c(deparse_unit(unify_units$Na2O), deparse_unit(unify_units$Sb)), "µg g-1") -}) - - -test_that("concentrations are converted and errors provoked as intended", { - convert_units <- convert_concentration_units( - test_input, values = c("S"), unit_to = "oxP", oxide_preference = "oxidising" - ) - expect_equal(units(convert_units[["SO3"]])[[1]], "wtP") - - convert_units <- convert_concentration_units(test_input, values = c("Na2O", "CaO"), unit_to = "wtP") - expect_equal(units(convert_units[["Ba"]])[[1]], "wtP") - - convert_units <- convert_concentration_units(test_input, values = c("Se", "Te"), unit_to = "atP") - expect_equal(units(convert_units[["Sb"]])[[1]], "atP") - - convert_units <- convert_concentration_units( - test_input, values = c("Se", "Te"), unit_to = "oxP", oxide_preference = "oxidising" - ) - expect_equal(units(convert_units[["Sb2O5"]])[[1]], "wtP") - - convert_units <- convert_concentration_units(test_input, values = c("Na2O", "CaO"), unit_to = "atP") - expect_equal(units(convert_units[["Ba"]])[[1]], "atP") - - expect_error( - convert_concentration_units(test_input, values = c("S", "Na2O"), unit_to = "ppm"), - "Unit conversion failed: Values include oxides and elements.*" - ) - expect_error( - convert_concentration_units(test_input, values = c("S", "Te"), unit_to = "ppm"), - "Unit conversion failed: Units cannot be converted.*" - ) - -}) diff --git a/tests/testthat/test_LI_age_models.R b/tests/testthat/test_LI_age_models.R new file mode 100644 index 0000000..56737b9 --- /dev/null +++ b/tests/testthat/test_LI_age_models.R @@ -0,0 +1,14 @@ +age_model_data <- tibble::tibble( + `206Pb/204Pb` = 18, + `207Pb/204Pb` = 15, + `208Pb/204Pb` = 2 +) + +test_that("Pb isotope age models", { + expect_equal(pb_iso_age_model(age_model_data, model = "SK75")[["model_age_SK75"]], -1166.946) + expect_equal(pb_iso_age_model(age_model_data, model = "CR75")[["mu_CR75"]], 10.478) + expect_equal(pb_iso_age_model(age_model_data, model = "AJ84")[["kappa_AJ84"]], -15.421) + expect_error(pb_iso_age_model(age_model_data, model = 23), "Assertion on*") + expect_error(pb_iso_age_model(age_model_data, model = "23"), "This model is not supported.") + expect_length(pb_iso_age_model(age_model_data, model = "all"), 12) +}) diff --git a/tests/testthat/test_PbIso_age_models.R b/tests/testthat/test_PbIso_age_models.R deleted file mode 100644 index 6f0c71f..0000000 --- a/tests/testthat/test_PbIso_age_models.R +++ /dev/null @@ -1,38 +0,0 @@ -age_model_data <- tibble::tibble( - `206Pb/204Pb` = 18, - `207Pb/204Pb` = 15, - `208Pb/204Pb` = 2 -) - -suppressWarnings( - test_input <- read_ASTR( - system.file("extdata", "test_data_input_good.csv", package = "ASTR"), - id_column = "Sample", - context = 1:7 - ) -) - -age_models_ASTR <- pb_iso_age_model(test_input, model = "all") - -test_that("Pb isotope age models", { - expect_equal(pb_iso_age_model(age_model_data, model = "SK75")[["model_age_SK75"]], -1166.946) - expect_equal(pb_iso_age_model(age_model_data, model = "CR75")[["mu_CR75"]], 10.478) - expect_equal(pb_iso_age_model(age_model_data, model = "AJ84")[["kappa_AJ84"]], -15.421) - expect_error(pb_iso_age_model(age_model_data, model = 23), "'arg' must be.*") - expect_error(pb_iso_age_model(age_model_data, model = "23"), "'arg' should be one of.*") - expect_length(pb_iso_age_model(age_model_data, model = "all"), 12) -}) - -test_that("ASTR objects handled as intended", { - expect_true("ASTR" %in% class(age_models_ASTR)) - expect_equal(get_contextual_columns(age_models_ASTR[1:8]), get_contextual_columns(test_input)) - expect_equal( - attributes(age_models_ASTR[["mu_AJ84"]]), - attributes(test_input[["Sample"]]) - ) - expect_true("ASTR" %in% class(stacey_kramers_1975(test_input))) - expect_equal( - attributes(pb_iso_age_model(test_input, model = "CR75")[["kappa_CR75"]]), - attributes(test_input[["Sample"]]) - ) -}) diff --git a/tests/testthat/test_archchem_basic.R b/tests/testthat/test_archchem_basic.R new file mode 100644 index 0000000..d4a8491 --- /dev/null +++ b/tests/testthat/test_archchem_basic.R @@ -0,0 +1,14 @@ +# golden tests + +test_input <- read_archchem( + system.file("extdata", "input_format.csv", package = "ASTR"), + id_column = "other", + context = c("other", "other2") +) + +test_that("reading of a basic example table works as expected", { + expect_snapshot({ + # turn to data.frame to render the entire table + as.data.frame(test_input) + }) +}) diff --git a/tests/testthat/test_conversion_atomic.R b/tests/testthat/test_conversion_atomic.R deleted file mode 100644 index 14e5abf..0000000 --- a/tests/testthat/test_conversion_atomic.R +++ /dev/null @@ -1,83 +0,0 @@ -# tests/testthat/test_atomic_conversion.R - -df <- data.frame(metadata = "R2D2", Si = 46.74, O = 53.26) -df2 <- data.frame(metadata = "R2D2", Si = 33.33, O = 66.67) - -res <- wt_to_at(df, elements = c("Si", "O")) -res2 <- at_to_wt(df2, elements = c("Si", "O")) - -#element wt% to Atomic wt% -test_that("wt_to_at converts correctly", { - expect_true("Si" %in% names(res)) - expect_equal(res$O, 66.67, tolerance = 0.1) - expect_equal(rowSums(res[2:3]), 100, tolerance = 1e-6) - expect_false("Si_at" %in% names(res)) -}) - -#Atomic wt% to element wt% -test_that("at_to_wt converts correctly", { - expect_true("Si" %in% names(res2)) - expect_equal(res2$O, 53.26, tolerance = 0.1) - expect_equal(rowSums(res2[2:3]), 100, tolerance = 1e-6) - expect_false("Si_at" %in% names(res2)) -}) - -test_that("atomic conversions are reversible", { - at <- wt_to_at(df, elements = c("Si", "O")) - wt <- at_to_wt(at, elements = c("Si", "O")) - expect_equal(wt$Si, df$Si, tolerance = 0.1) - expect_equal(wt$O, df$O, tolerance = 0.1) -}) - -test_that("drop argument behaves correctly", { - res_keep <- wt_to_at(df, elements = c("Si", "O"), drop = FALSE) - expect_true("Si_atP" %in% names(res_keep)) - expect_true("Si" %in% names(res_keep)) - - res2_keep <- at_to_wt(df2, elements = c("Si", "O"), drop = FALSE) - expect_true("Si_wtP" %in% names(res2_keep)) - expect_true("Si" %in% names(res2_keep)) -}) - -test_that("converted values stay within physical bounds", { - expect_true(all(res[2:3] >= 0) & all(res[2:3] <= 100)) - expect_true(all(res2[2:3] >= 0) & all(res2[2:3] <= 100)) -}) - -test_that("functions throw correct errors where intended", { - expect_error(wt_to_at(data.frame(Si = 46.74), elements = c("Si", "O")), - regexp = "The following elements are not present*" - ) - expect_error(wt_to_at(data.frame(Xx = 10), elements = "Xx"), - regexp = "The following elements are not valid*" - ) - expect_error(wt_to_at("test", elements = "Si")) - - expect_error(at_to_wt(data.frame(Si = 46.74), elements = c("Si", "O")), - regexp = "The following elements are not present*" - ) - expect_error(at_to_wt(data.frame(Xx = 10), elements = "Xx"), - regexp = "The following elements are not valid*" - ) - expect_error(wt_to_at("test", elements = "Si")) -}) - -# ASTR objects handled correctly -test_input <- read_ASTR( - system.file("extdata", "input_format.csv", package = "ASTR"), - id_column = "other", - context = c("other", "other2") -) %>% unify_concentration_unit("wtP") - -test_input_atP <- wt_to_at(test_input, drop = FALSE) -test_input_wtP <- at_to_wt(test_input) - -test_that("Conversion handles ASTR objects correctly", { - expect_equal(units(test_input_atP$Sn_atP)[[1]], "atP") - expect_equal(units(test_input_atP$K2O)[[1]], "wtP") - expect_equal(attributes(test_input_atP$Zn)$ASTR_class, attributes(test_input$Zn)$ASTR_class) - - expect_equal(units(test_input_wtP$Mn)[[1]], "wtP") - expect_equal(attributes(test_input_wtP$Mn)$ASTR_class, attributes(test_input$Mn)$ASTR_class) - -}) diff --git a/tests/testthat/test_conversion_oxide.R b/tests/testthat/test_conversion_oxide.R deleted file mode 100644 index 0988da3..0000000 --- a/tests/testthat/test_conversion_oxide.R +++ /dev/null @@ -1,205 +0,0 @@ -# Test for conversion between elemental wt% and oxide wt% - -# Test data -df <- data.frame( - metadata = "Sample1", - Xy = 34, - Ag = c(5, 5), - Fe = c(50, 45), - Si = c(45, 50), - Ac = 0.5, - Sr = c(0.02, 0.5), - Ba = c(0.5, 0.02) -) - -test_that("element_to_oxide: oxide preferences", { - # Oxidising preference - res_ox <- element_to_oxide(df, - elements = c("Ag", "Fe", "Si"), - oxide_preference = "oxidising" - ) - expect_true(all(c("AgO", "Fe2O3", "SiO2") %in% names(res_ox))) - - # Reducing preference - res_red <- element_to_oxide(df, - elements = c("Ag", "Fe", "Si"), - oxide_preference = "reducing" - ) - expect_true(all(c("Ag2O", "FeO", "SiO2") %in% names(res_red))) - - # Named vector preference - res_named <- element_to_oxide(df, - elements = c("Ag", "Fe"), - oxide_preference = c(Ag = "Ag2O", Fe = "FeO") - ) - expect_true(all(c("Ag2O", "FeO") %in% names(res_named))) -}) - -test_that("element_to_oxide: chemical concentration", { - res <- element_to_oxide( - df, - elements = c("Ag", "Fe", "Si", "Sr", "Ba"), - oxide_preference = "reducing", - which_concentrations = "major" - ) - expect_true(all(is.na(res[, c("SrO", "BaO")]))) - - res <- element_to_oxide( - df, - elements = c("Ag", "Fe", "Si", "Sr", "Ba"), - oxide_preference = "reducing", - which_concentrations = "minor" - ) - expect_true(all(is.na(res[, c("Ag2O", "FeO")]))) - - res <- element_to_oxide( - df, - elements = c("Ag", "Fe", "Si", "Sr", "Ba"), - oxide_preference = "reducing", - which_concentrations = "no_trace" - ) - expect_true(all(is.na(res$BaO[2]), is.na(res$SrO[1]))) -}) - -test_that("oxide conversion: errors", { - expect_error( - element_to_oxide(df, elements = c("Ag", "Fe", "Ac"), oxide_preference = "oxidising"), - regexp = "Oxides of one or more.*" - ) - expect_error( - element_to_oxide(df, elements = c("Ag", "Fe", "Lu"), oxide_preference = "oxidising"), - regexp = "The following elements.*" - ) - expect_error( - element_to_oxide(df, elements = c("Ag", "Fe", "Si"), oxide_preference = "surprise"), - regexp = "'oxide_preference' must either.*" - ) - expect_error( - element_to_oxide(df, elements = c("Ag", "Fe", "Si"), oxide_preference = c(Fe = "CuO", Si = "SiO2", Ag = "AgO")), - regexp = "'oxide_preference' includes invalid combinations.*" - ) - expect_error( - element_to_oxide(df, elements = c("Ag", "Fe", "Si"), oxide_preference = c(Fe = "FeO", Si = "SiO", Ag = "AgO")), - regexp = "Invalid oxide names.*" - ) - expect_error( - element_to_oxide(df, elements = c("Ag", "Fe", "Si"), oxide_preference = c(Fe = "CuO", Si = "SiO2", Xy = "AgO")), - regexp = "Invalid element names.*" - ) -}) - -df_ox <- data.frame( - metadata = "Sample2", - Ag2O = c(5, 5), - FeO = c(40, 45), - SiO2 = c(45, 50), - Fe2O3 = c(10, 0) -) - -test_that("oxide_to_element converts back correctly", { - res <- oxide_to_element(df_ox, oxides = c("Ag2O", "FeO", "SiO2")) - expect_true(all(c("Ag", "Fe", "Si") %in% names(res))) - expect_equal(res$Ag[1], 4.65, tolerance = 0.1) - expect_equal(res$Fe[2], 34.97, tolerance = 0.1) - expect_equal(res$Si[1], 21.03, tolerance = 0.1) -}) - -test_that("oxide_to_element: errors", { - expect_error( - oxide_to_element(df_ox, oxides = c("Ag2O", "FeO", "SiO2", "Lu2O3")), - regexp = "The following oxides are not present in df.*" - ) - - # Test for unavailable conversion factors - df_bad <- cbind(df_ox, O4 = 23) - expect_error( - oxide_to_element(df_bad, oxides = c("Ag2O", "FeO", "SiO2", "O4")), - regexp = "Conversion factors for one or more oxides are not available.*" - ) -}) - -test_that("conversion is reversible", { - ox <- element_to_oxide(df, elements = c("Ag", "Fe", "Si"), oxide_preference = "reducing") - el <- oxide_to_element(ox, oxides = c("Ag2O", "FeO", "SiO2")) - - expect_equal(el$Ag, df$Ag, tolerance = 0.01) - expect_equal(el$Fe, df$Fe, tolerance = 0.01) - expect_equal(el$Si, df$Si, tolerance = 0.01) -}) - -test_that("oxide conversion: drop argument", { - res <- element_to_oxide(df, elements = c("Ag", "Fe"), oxide_preference = "reducing", drop = TRUE) - expect_true(all(!c("Ag", "Fe") %in% names(res))) - - res_ox <- oxide_to_element(df_ox, oxides = c("Ag2O", "FeO"), drop = TRUE) - expect_false(any(c("Ag2O", "FeO") %in% names(res_ox))) -}) - -test_that("oxide conversion: normalise argument", { - res <- element_to_oxide(df, elements = c("Ag", "Fe", "Si"), oxide_preference = "reducing", normalise = TRUE) - expect_equal(res$SiO2, c(58.0, 62.8), tolerance = 0.01) - # Check both rows sum to 100 - expect_equal(rowSums(res[, c("Ag2O", "FeO", "SiO2")]), c(100, 100), tolerance = 0.01) - - # Test normalise in oxide_to_element - res_ox <- oxide_to_element(df_ox, oxides = c("Ag2O", "FeO", "SiO2"), normalise = TRUE) - expect_equal(res_ox$Si, c(37.05, 37.1), tolerance = 0.01) - # Both rows should sum to 100 - expect_equal(rowSums(res_ox[, c("Ag", "Fe", "Si")]), c(100, 100), tolerance = 0.01) -}) - -test_that("oxide conversion: duplicated elements summarised", { - res_ox <- oxide_to_element(df_ox, oxides = c("Ag2O", "FeO", "SiO2", "Fe2O3")) - expect_equal(res_ox$Fe, c(38.086, 34.97), tolerance = 0.01) -}) - -df_math <- data.frame( - ID = "feldspar", - O = 48.81, - Na = 8.77, - Al = 10.29, - Si = 32.13 -) - -test_that("Oxide conversion: math is correct and conversions are reversible", { - res <- element_to_oxide( - df_math, - elements = names(df_math)[-2:-1], - oxide_preference = "oxidising", - drop = TRUE - ) - expect_equal(res$Na2O, 11.82, tolerance = 0.01) - - # Test full circle with feldspar data - res_ox <- oxide_to_element( - res, - oxides = c("Na2O", "Al2O3", "SiO2"), - drop = TRUE - ) - - expect_equal(df_math, res_ox, tolerance = 0.01) -}) - -test_that("Additional tests for internal functions", { - df_internal <- data.frame(row.names = 1:5) - expect_equal(sum_duplicates(df_internal), df_internal) - expect_equal(normalise_rows(df_internal), df_internal) -}) - -# ASTR objects handled correctly -test_input <- read_ASTR( - system.file("extdata", "input_format.csv", package = "ASTR"), - id_column = "other", - context = c("other", "other2") -) %>% unify_concentration_unit("wtP") - -test_input_element <- oxide_to_element(test_input, drop = TRUE, normalise = TRUE) -test_input_oxide <- element_to_oxide(test_input, oxide_preference = "reducing", normalise = TRUE) - -test_that("Conversion handles ASTR objects correctly", { - expect_equal(test_input_element$K[[1]], set_units(100, "wtP")) - expect_equal(attributes(test_input_element$K)$ASTR_class, attributes(test_input$K2O)$ASTR_class) - - expect_equal(units(test_input_oxide$ZnO)[[1]], "wtP") - expect_equal(attributes(test_input_oxide$SnO)$ASTR_class, attributes(test_input$Sn)$ASTR_class) -}) diff --git a/tests/testthat/test_copper_alloy_bb.R b/tests/testthat/test_copper_alloy_bb.R index 26376fa..0774a78 100644 --- a/tests/testthat/test_copper_alloy_bb.R +++ b/tests/testthat/test_copper_alloy_bb.R @@ -1,22 +1,27 @@ -test_that("copper_alloy_bb", { +test_that("copper_alloy_bb: basic classification", { test_data <- data.frame( - ID = 1:8, - Tin = c(1, 1, 5, 5, 5, 5, 0.5, 5), - Zn = c(2, 5, 2, 4, 8, 15, 2, 8), - Lead = c(0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 9, 6) + ID = 1:11, + Tin = c(1, 1, 5, 5, 5, 5, 0.5, 5, NA, 5, 5), + Zn = c(2, 5, 2, 4, 8, 15, 2, 8, 2, NA, 8), + Lead = c(0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 9, 6, 0.5, 0.5, NA) ) - expect_equal( - copper_alloy_bb(test_data, elements = c("Sn" = "Tin", "Zn" = "Zn", "Pb" = "Lead"))$copper_alloy_bb, + copper_alloy_bb( + test_data, + elements = c(Sn = "Tin", Zn = "Zn", Pb = "Lead") + )$copper_alloy_bb, c( - "Copper", # ID 1: Copper (Zn<3, Sn<3) - "Copper/brass", # ID 2: Copper/brass (3≤Zn<8, Sn<3) - "Bronze/gunmetal", # ID 3: Bronze (Sn≥3, Zn<3*Sn) - "Gunmetal", # ID 4: Bronze/gunmetal (Sn≥3, 0.332.5*Sn, Zn≤4*Sn) - "Leaded Copper", # ID 7: Leaded Copper (Copper + Pb>8) - "(Leaded) Gunmetal" # ID 8: (Leaded) Gunmetal (Gunmetal + 4≤Pb≤8) + "Copper", # ID 1: Zn<3, Sn<3 + "Copper/brass", # ID 2: 3<=Zn<8, Sn<3 + "Bronze/gunmetal", # ID 3: Sn>=3, 0.33*Sn=3, 0.67*Sn=3, 0.67*Sn2.5*Sn, Zn<=4*Sn + "Leaded Copper", # ID 7: Copper + Pb>8 + "(Leaded) Gunmetal", # ID 8: Gunmetal + 4<=Pb<=8 + "Unclassified", # ID 9: NA Sn + "Unclassified", # ID 10: NA Zn + "Unclassified" # ID 11: NA Pb ) ) }) @@ -24,14 +29,13 @@ test_that("copper_alloy_bb", { test_that("copper_alloy_bb: Handling ASTR object", { test_data_ASTR <- as_ASTR( data.frame( - ID = 1:8, + ID = 1:8, Sn_atP = c(0.5, 0.5, 5, 5, 0.5, 5, 5, 5), Zn_atP = c(0.5, 0.5, 0.5, 0.5, 5, 5, 0.5, 5), Pb_atP = c(0.5, 5, 0.5, 5, 0.5, 0.5, 5, 5) ) ) test_result_ASTR <- copper_alloy_bb(test_data_ASTR) - expect_equal(units(test_result_ASTR[["Zn"]])[[1]], "wtP") expect_equal(attributes(test_result_ASTR[["copper_alloy_bb"]])[[1]], "ASTR_context") expect_true(inherits(test_result_ASTR, "ASTR")) diff --git a/tests/testthat/test_copper_alloy_pollard.R b/tests/testthat/test_copper_alloy_pollard.R index e69437c..1275881 100644 --- a/tests/testthat/test_copper_alloy_pollard.R +++ b/tests/testthat/test_copper_alloy_pollard.R @@ -1,37 +1,36 @@ test_that("copper_alloy_pollard: basic classification", { test_data <- data.frame( - ID = 1:8, - Sn = c(0.5, 0.5, 5, 5, 0.5, 5, 5, 5), - Zn = c(0.5, 0.5, 0.5, 0.5, 5, 5, 0.5, 5), - Pb = c(0.5, 5, 0.5, 5, 0.5, 0.5, 5, 5) + ID = 1:11, + Sn = c(0.5, 0.5, 5, 5, 0.5, 5, 5, 5, NA, 0.5, 5), + Zn = c(0.5, 0.5, 0.5, 0.5, 5, 5, 0.5, 5, 0.5, NA, 0.5), + Pb = c(0.5, 5, 0.5, 5, 0.5, 0.5, 5, 5, 0.5, 0.5, NA) ) - result <- copper_alloy_pollard(test_data) - expect_equal( result$copper_alloy_pollard, c( - "Copper", # All < 1% - "Leaded copper", # Pb ≥ 1% - "Bronze", # Sn ≥ 1% - "Leaded bronze", # Sn, Pb ≥ 1% - "Brass", # Zn ≥ 1% - "Gunmetal", # Zn, Sn ≥ 1% - "Leaded bronze", # Sn, Pb ≥ 1% (same as ID 4) - "Leaded gunmetal" # All ≥ 1% + "Copper", # ID 1: All < 1% + "Leaded copper", # ID 2: Pb >= 1% + "Bronze", # ID 3: Sn >= 1% + "Leaded bronze", # ID 4: Sn, Pb >= 1% + "Brass", # ID 5: Zn >= 1% + "Gunmetal", # ID 6: Zn, Sn >= 1% + "Leaded bronze", # ID 7: Sn, Pb >= 1% + "Leaded gunmetal", # ID 8: All >= 1% + "Unclassified", # ID 9: NA Sn + "Unclassified", # ID 10: NA Zn + "Unclassified" # ID 11: NA Pb ) ) }) test_that("copper_alloy_pollard: function arguments", { df <- data.frame( - ID = 1, - Tin = 8, + ID = 1, + Tin = 8, Lead = 3, Zinc = 0.5 ) - - # "As+Sb" is group 6 in the lookup table expect_equal( copper_alloy_pollard( df, @@ -52,14 +51,13 @@ test_that("copper_alloy_pollard: function arguments", { test_that("copper_alloy_pollard: Handling ASTR object", { test_data_ASTR <- as_ASTR( data.frame( - ID = 1:8, + ID = 1:8, Sn_atP = c(0.5, 0.5, 5, 5, 0.5, 5, 5, 5), Zn_atP = c(0.5, 0.5, 0.5, 0.5, 5, 5, 0.5, 5), Pb_atP = c(0.5, 5, 0.5, 5, 0.5, 0.5, 5, 5) ) ) test_result_ASTR <- copper_alloy_pollard(test_data_ASTR) - expect_equal(units(test_result_ASTR[["Zn"]])[[1]], "wtP") expect_equal(attributes(test_result_ASTR[["copper_alloy_pollard"]])[[1]], "ASTR_context") expect_true(inherits(test_result_ASTR, "ASTR")) diff --git a/tests/testthat/test_copper_group_Bray.R b/tests/testthat/test_copper_group_Bray.R index 9818354..33724ef 100644 --- a/tests/testthat/test_copper_group_Bray.R +++ b/tests/testthat/test_copper_group_Bray.R @@ -1,33 +1,41 @@ test_that("copper_group_bray: basic classification", { df <- data.frame( - ID = 1:4, - As = c(0.2, 0.01, 0.15, 0.00), - Sb = c(0.00, 0.2, 0.00, 0.00), - Ag = c(0.00, 0.00, 0.12, 0.00), - Ni = c(0.00, 0.00, 0.00, 0.20) + ID = 1:7, + As = c(0.2, 0.01, 0.15, 0.00, NA, 0.2, 0.15), + Sb = c(0.00, 0.2, 0.00, 0.00, 0.15, NA, 0.11), + Ag = c(0.00, 0.00, 0.12, 0.00, 0.00, 0.00, NA), + Ni = c(0.00, 0.00, 0.00, 0.20, 0.00, 0.00, 0.20) ) - result <- copper_group_bray(df) # Check column exists expect_true("copper_group_bray" %in% names(result)) # Expected group names - expected <- c("As", "Sb", "As+Ag", "Ni") - - expect_equal(result$copper_group_bray, expected) + expect_equal( + result$copper_group_bray, + c( + "As", # ID 1: As only + "Sb", # ID 2: Sb only + "As+Ag", # ID 3: As and Ag + "Ni", # ID 4: Ni only + "Unclassified", # ID 5: NA As + "Unclassified", # ID 6: NA Sb + "Unclassified" # ID 7: NA Ag + ) + ) }) test_that("copper_group_bray: function arguments", { df <- data.frame( ID = 1, - Arsenic = 0.3, + Arsenic = 0.3, Antimony = 0.2, - Silver = 0.0, - Nickel = 0.0 + Silver = 0.0, + Nickel = 0.0 ) - # "As+Sb" is group 6 in the lookup table + # Custom column names — As+Sb is group 6 expect_equal( copper_group_bray( df, @@ -35,6 +43,8 @@ test_that("copper_group_bray: function arguments", { )$copper_group_bray, "As+Sb" ) + + # group_as_number = TRUE expect_equal( copper_group_bray( df, @@ -43,6 +53,17 @@ test_that("copper_group_bray: function arguments", { )$copper_group_bray, 6 ) + + # NA with group_as_number = TRUE returns NA_integer_ + df_na <- data.frame(ID = 1, Arsenic = NA, Antimony = 0.2, Silver = 0.0, Nickel = 0.0) + expect_equal( + copper_group_bray( + df_na, + elements = c(As = "Arsenic", Sb = "Antimony", Ag = "Silver", Ni = "Nickel"), + group_as_number = TRUE + )$copper_group_bray, + NA_integer_ + ) }) test_that("copper_alloy_pollard: Handling ASTR object", { diff --git a/tests/testthat/test_geom_kde2d.R b/tests/testthat/test_geom_kde2d.R deleted file mode 100644 index acb8d98..0000000 --- a/tests/testthat/test_geom_kde2d.R +++ /dev/null @@ -1,31 +0,0 @@ -# Visual tests ------------------------------------------------------------ - -set.seed(50) -test_KDE_df <- data.frame( - x = c(rnorm(50), rnorm(50, 5), rnorm(2, 10)), - y = c(rnorm(50), rnorm(50, 5), rnorm(2, 10)), - group = rep(c("A", "B", "C"), c(50, 50, 2)) -) - -test_KDE_ASTR <- as_ASTR( - data.frame( - ID = 1:102, - `207Pb/206Pb` = c(rnorm(50), rnorm(50, 5), rnorm(2, 10)), - `208Pb/206Pb` = c(rnorm(50), rnorm(50, 5), rnorm(2, 10)), - group = rep(c("A", "B", "C"), c(50, 50, 2)), - check.names = FALSE - ), - id_column = "ID", - context = "group" -) - -test_that("geom_image", { - expect_doppelganger( - "KDE_df", - ggplot(test_KDE_df, aes(x = x, y = y)) + geom_kde2d(aes(x = x, y = y, colour = group)) - ) - expect_doppelganger( - "KDE_ASTR", - ggplot(test_KDE_ASTR, aes(x = `207Pb/206Pb`, y = `208Pb/206Pb`, colour = group)) + geom_kde2d() - ) -}) diff --git a/tests/testthat/test_goem_sk_lines.R b/tests/testthat/test_goem_sk_lines.R deleted file mode 100644 index c5a48b1..0000000 --- a/tests/testthat/test_goem_sk_lines.R +++ /dev/null @@ -1,24 +0,0 @@ -set.seed(50) -df <- data.frame( - pb64 = rnorm(10, 18, 0.2), - pb74 = rnorm(10, 15.7, 0.1), - pb84 = rnorm(10, 37.5, 0.1) -) - -p <- ggplot(df, aes(x = pb64, y = pb74)) + - geom_point() + - geom_sk_lines(system = "76", show_geochron = FALSE) + - geom_sk_lines(system = "76", show_isochrons = FALSE) + - geom_sk_labels(system = "76", show_geochron = FALSE) + - geom_sk_labels(system = "76", show_isochrons = FALSE) + - coord_cartesian( - xlim = range(df$pb64) * c(.99, 1.01), - ylim = range(df$pb74) * c(.99, 1.01) - ) - -test_that("geom_image", { - expect_s3_class(p, "ggplot") - expect_equal(p$layers[[2]]$stat_params$show_geochron, FALSE) - expect_equal(rlang::as_name(p$mapping$x), "pb64") - expect_doppelganger("image", p) -}) diff --git a/tests/testthat/test_utils.R b/tests/testthat/test_utils.R index fec0ec0..cf6ead7 100644 --- a/tests/testthat/test_utils.R +++ b/tests/testthat/test_utils.R @@ -1,13 +1,3 @@ -test_that("unit notation transformation works", { - expect_equal(transform_notation("wt%"), "wt%") - expect_equal(transform_notation("µg/kg"), "µg kg-1") - expect_equal(transform_notation("g/g2"), "g g-2") - expect_error(transform_notation(c("wt%", "mg/kg", "kg2/m2", "g/l2")), "Assertion on 'unit' failed:.*") - expect_error(transform_notation("kg/m2/s2"), "This unit cannot be converted.*") -}) - - - # Sample tibble for tests df <- tibble::tibble( id = 1:2, diff --git a/vignettes/ASTR.Rmd b/vignettes/ASTR.Rmd new file mode 100644 index 0000000..88cb476 --- /dev/null +++ b/vignettes/ASTR.Rmd @@ -0,0 +1,19 @@ +--- +title: "ASTR" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{ASTR} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} +library(ASTR) +``` diff --git a/vignettes/ASTR.showcase.Rmd b/vignettes/ASTR.showcase.Rmd deleted file mode 100644 index 511eb46..0000000 --- a/vignettes/ASTR.showcase.Rmd +++ /dev/null @@ -1,166 +0,0 @@ ---- -title: "Working with ASTR objects" -csl: apa.csl -link-citations: TRUE -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Working with ASTR objects} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} -bibliography: references.bib ---- - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - - -```{r data-prep, include=FALSE} -set.seed(123) -data <- data.frame( - "Group" = c(rep("A", 5), rep("B", 5)), - "Cu_wt%" = round(runif(10, 85, 95), 1), - "Sn_wt%" = round(runif(10, 5, 10), 1), - "As_wt%" = round(runif(10, 1.5, 2.5), 2), - "Sb_wt%" = round(runif(10, 0.5, 1), 2), - "Ag_ppm" = round(runif(10, 100, 350), 0), - "Ni_ppm" = round(runif(10, 300, 650), 0), - "d65Cu" = c(round(runif(6, -0.5, 0.5), 2), rep("#REF!", 4)), - "206Pb/204Pb" = round(c(rep(NA, 5), runif(5, 18.3, 18.8)), 4), - "206Pb/204Pb_err2SD" = round(c(rep(NA, 5), runif(5, 0.0007, 0.0011)), 5), - "207Pb/204Pb" = round(c(rep(NA, 5), runif(5, 15.6, 15.7)), 4), - "207Pb/204Pb_err2SD" = round(c(rep(NA, 5), runif(5, 0.0006, 0.0009)), 5), - "208Pb/204Pb" = round(c(rep(NA, 5), runif(5, 38.0, 38.5)), 3), - "208Pb/204Pb_err2SD" = round(c(rep(NA, 5), runif(5, 0.001, 0.002)), 4), - check.names = FALSE -) -``` - -To make the most out of the features offered by the ASTR package, input data should be imported into `ASTR` objects. `ASTR` objects represent archaeometric and geochemical data in R in a standardized and semantically rich format, to allow for convenient and safe data analysis. If the input data structure adheres to the conventions set out in the [ASTR schema](VG.ASTRschema.0.0.2.html), then the package can automatically build valid `ASTR` objects from it. When working with the package, many of its functions require only an `ASTR` object, making them convenient to use even for users who consider themselves less experienced with R. This article highlights some of these functionalities. - -Before we start, we want to load the ASTR package: - -```{r setup} -library(ASTR) -``` - -## Data import and inspection -To work with an `ASTR` object, we have to create one. The function `read_ASTR()` imports spreadsheets in a variety of formats, including Excel files. For this article, we use mock-up data: - -```{r echo=FALSE} -data -``` - -Note how the column headers are organised according to the ASTR conventions. This allows the package to _understand_ some of the semantics of the dataset in the `read_ASTR()` process, and correctly represent them in the resulting `ASTR` object. A closer look at the mock-up data also reveals (common) problems with the copper isotope data: it seems that some Excel formulas did not work as intended and left `#REF!` entries. `read_ASTR()` will read these as `NA` values. Finally, every `ASTR` object requires one column that acts as a unique row identifier. In this dataset there is no such column, though, only a `Group` identifier. `read_ASTR()` can automatically turn such a column to a unique identifier. - -We can now perform the reading process. As we are working with mock-up data in an R vignette, we do not read from the file system. We only need to call an essential internal function of `read_ASTR()`: `as_ASTR()`. It turns R data.frames to `ASTR` objects. If we would start from an Excel file we would call `read_ASTR()` instead. - -To do this in practice we not only have to submit our `data` to `as_ASTR()`, but also set two other arguments: 1. We have to define one of the columns as the ID column with `id_column`, and 2. we explicitly have to mark any column providing contextual information with `context` (i.e. no analytical values, cf. [ASTR schema: Implementation](VG.ASTR.Schema.Implementation.html)). - -```{r echo=TRUE} -data <- as_ASTR(data, id_column = "Group", context = c("Group")) -``` - -While ASTR attempts to make data import as easy as possible, it also aims to be transparent about it. Consequently, `as_ASTR()` issues several warnings when confronted with our mock-up data, flagging (potential) issues: - -* The column for the ID did contain non-unique values but ASTR automatically created unique values from it. -* Some values in the column `d65Cu` were replaced with `NA`; when inspecting the data set, it is clear that these were the Excel `#REF!` error messages. In general, ASTR replaces by default common and user-defined indicators for missing values and also for indicators of "below detection limit" during import. -* Across the dataset, 34 values are missing. - -To learn more about the (potential) issues with our dataset, it suggests to run `validate()`: - -```{r echo=TRUE} -validate(data) -``` - -This summary of where to find the missing values comes in handy for large datasets! - -In our case, the dataset is fine. We might want to check on the missing values in the copper isotope data because apparently there was something wrong with the Excel file. In case of the lead isotope data, however, they are intentional (they were not measured for samples from group A). - -Having a closer look on the imported data set shows, that ASTR did one more thing: - -```{r echo=TRUE} -data -``` - -Our relative unit "ppm" was converted into SI-units and the values now have a measurement unit R can understand (note that the unit `wt%` is written as `wtP`)^[The %-sign can not be used in custom units]: - -``` {r} -units(data$Ag[1]) -``` - -When looking into the data structure, we also see that it also labelled the different columns as e.g. concentration or isotope ratio: - -``` {r} -str(data) -``` - -## Subsetting data - -With this much information about our data, it is easy to subset data. Let's say that, for example, we want to check if our data can be differentiated into groups based on the chemical composition by creating biplots of all possible combinations. The `get_ ... _columns()`-family comes in very handy here: - -```{r} -pairs(get_concentration_columns(data)[-1]) -``` - -Note that we have to exclude the first column here, because the first column of `ASTR` objects and their subsets is always the ID column to ensure that data can be clearly assigned to a single sample. Actually, we might only be interested in the main elements of the metal. In this case, we can take advantage that these are the only values in `wtP`: - -```{r} -pairs(get_unit_columns(data, units = "wtP")[-1]) -``` - -### Unit conversions - -While continuing investigating the metal, we may want to estimate its approximate melting temperature and remember that we can get this information from a phase diagram. While our values for copper and tin are in `wt%`, the phase diagram in front of us is in `at%`. Converting from `wt%` to `at%` is probably faster than searching for a version of the phase diagram in `wt%`^[While ASTR fully supports use the native pipe operator `|>`, it maintains backward compatibility to older R versions by using `%>%`]: - -```{r} -library(magrittr) # import of pipe operator `%>%` - -unify_concentration_unit(data, unit = "wtP") %>% - wt_to_at() -``` - -We use a two-step approach here to be more accurate: The actual conversion from `wt%` to `at%` is done by `wt_to_at()`. However, because Ag and Ni are not in `wt%`, they need to be converted first. That's why we run `unify_concentration_unit()` first: it detects values with units that can be converted into the target unit and converts them all into the same unit. While it is nice to be scientifically accurate, we can get only a rough estimate anyway because of the significant amounts of arsenic and antimony in the metal. Therefore, converting only copper and tin would be sufficient: - -```{r} -wt_to_at(data, elements = c("Cu", "Sn")) -``` - - - -## Working with data - -Another task in our investigation of the copper items is to identify the type of copper alloy our metal is made of. A first rough approach could be to use the classification suggested by @Bray2015. Not surprising, we see that they all belong to the group "As+Sb": - -```{r} -copper_group <- copper_group_bray(data) -copper_group -``` - -After we look into the chemical compositions, it is time to turn to the lead isotope data. Before plotting them, we want to calculate their age model parameters because they give us some idea about the geological setting. The model by @stacey1975 is still the most commonly used one. Because we have lead isotope data only for group B, we exclude data from group A: - -```{r warning=FALSE} -data_pb_iso <- data[data$Group == "B", ] -age_model_params <- pb_iso_age_model(data_pb_iso, model = "SK75") -age_model_params -``` - - - -## Data export - -After finishing our analysis of the data, we want to save the copper type and the parameters of the lead isotope model age to our hard drive. For this task, ASTR relies on the functions already provided by R and other R packages (e.g. `readr::write_csv()`). Before export, we have to make sure that the information about the units of the values is preserved by including it back in the column name: - -```{r} -data_unitless <- remove_units(data, recover_unit_names = TRUE) -data_unitless -``` - -## References diff --git a/vignettes/KDE2_vignette.Rmd b/vignettes/KDE2_vignette.Rmd index f118ba7..59bfbfc 100644 --- a/vignettes/KDE2_vignette.Rmd +++ b/vignettes/KDE2_vignette.Rmd @@ -18,6 +18,10 @@ knitr::opts_chunk$set( ) ``` +```{r setup} +library(ASTR) +``` + # Introduction This vignette introduces `geom_kde2()`, which generates a binary plot with kernel density estimation. @@ -56,7 +60,7 @@ $$ \int_{-\infty}^{\infty} \hat{f}(t) \, dt = \frac{1}{n} \sum_{i=1}^{n} \int_{- In other words, the kernel transforms the "*sharp*" (point) location of $x_i$ into an interval centred (symmetrically or not) around $x_i$ [@Weglarczyk2018]. -# Function workflow +## Function workflow `geom_kde2()` calculates the 2D kernel density estimate using `kde()` from the ks package [@Duong2007; @Duong2025], while handling the contours manually (`compute.cont = FALSE`). It then calculates the actual density values (the contour levels) corresponding to the probability levels (probs) using `ks::contourLevels()`. @@ -66,18 +70,14 @@ The original data are then returned with the added type column and are checked f Default aesthetic values are applied if unchanged by the user. -# Examples +## Examples The following examples showcase the different visualisation and density estimate calculations for `geom_kde2d()`. -## Basic biplot +### Basic biplot ```{r, fig.width=7, fig.height=8} - -library(ASTR) - # load example lead isotope data that is included with the package - data(ArgentinaDatabase) library(ggplot2) @@ -106,7 +106,7 @@ ggplot( This example reads in the sample dataset and calculates the kernel density estimates in the function `geom_kde2d()`, colouring by the `Mining site` variable from the dataset. Warning messages appear for each group where the sample size is too small to calculate the estimates: `No density estimate possible for group 'x', plotting points instead: the leading minor of order 1 is not positive`. In those cases, the plotting falls back to plotting individual points from the original dataset. -## Biplot with adjusted quantiles to show deciles +### Biplot with adjusted quantiles to show deciles The default function reverts to 4 quantiles. This examples illustrates the quantiles set to 10 to show deciles. It also sets the transparency to 0.5 (`alpha`). @@ -136,7 +136,7 @@ ggplot( )) ``` -## Biplot with the minimum probability argument added to show only density regions above the median +### Biplot with the minimum probability argument added to show only density regions above the median ```{r, fig.width=7, fig.height=8} ggplot( @@ -164,7 +164,7 @@ ggplot( )) ``` -## Creation of an outline effect around the density region +### Creation of an outline effect around the density region For this effect the fill argument is set to `NA` @@ -195,7 +195,7 @@ ggplot( )) ``` -## Creation of an outline effect around the density region solving clipping issues +### Creation of an outline effect around the density region solving clipping issues In some cases density regions can be clipped by the plot area. The addition of `coord_cartesian()` from the package `ggplot2` expands the plot area so that the full density regions are shown without clipping. The limits are set for the axes using the `xlim` and `ylim` arguments. @@ -231,4 +231,4 @@ ggplot( )) ``` -# References +## References diff --git a/vignettes/VG.ASTR.Conventions.explained.Rmd b/vignettes/VG.ASTR.Conventions.explained.Rmd index 841e936..05d27c2 100644 --- a/vignettes/VG.ASTR.Conventions.explained.Rmd +++ b/vignettes/VG.ASTR.Conventions.explained.Rmd @@ -1,12 +1,13 @@ --- -title: "ASTR schema: Explanation" +title: "Data conventions explained" csl: apa.csl link-citations: TRUE output: html_document vignette: > - %\VignetteIndexEntry{ASTR schema: Explanation} + %\VignetteIndexEntry{ASTR schema explained} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} +date: "2025-10-23" bibliography: references.bib --- @@ -20,9 +21,9 @@ ASTR does not accept isotope, element, or oxide compositions without explicitly ASTR explicitly handles measurement uncertainty for all analytical data. Measurement uncertainty is a parameter encompassing the dispersion of analytical data both random and systematically. It provides a quantitative estimate of the quality of the measurement. -* **Random uncertainty**: The standard deviation (SD) denotes the dispersion or variability of individual data points around the mean value of a statistically normal data set and expresses the precision of the individual data within the statistical sample. A small SD means that the individual data points are close to the mean value (low variability), whereas a high SD means that the individual data points are more widely dispersed (high variability). In a normal distribution, 1 SD covers the range of approximately 68% of all data; 2 SD covers the range in which approximately 95% of the data in the data set is defined. The ratio is expressed in the so-called 68-95-99.7 rule. +- **Random uncertainty**: The standard deviation (SD) denotes the dispersion or variability of individual data points around the mean value of a statistically normal data set and expresses the precision of the individual data within the statistical sample. A small SD means that the individual data points are close to the mean value (low variability), whereas a high SD means that the individual data points are more widely dispersed (high variability). In a normal distribution, 1 SD covers the range of approximately 68% of all data; 2 SD covers the range in which approximately 95% of the data in the data set is defined. The ratio is expressed in the so-called 68-95-99.7 rule. -* **Systematic uncertainty**: The standard error (SE) expresses the variability of the means of measurements (statistical samples) in relation to multiple repetitions (the statistical population). It hence expresses the accuracy of the measurement. The SE becomes smaller as the sample size increases, since higher repetition of measurements provides more reliable information about the true population mean. Confidence intervals are used as for the standard deviation. A 2-fold standard error (2SE) defines the range around the calculated mean that contains the true population mean with ca. 95% probability. +- **Systematic uncertainty**: The standard error (SE) expresses the variability of the means of measurements (statistical samples) in relation to multiple repetitions (the statistical population). It hence expresses the accuracy of the measurement. The SE becomes smaller as the sample size increases, since higher repetition of measurements provides more reliable information about the true population mean. Confidence intervals are used as for the standard deviation. A 2-fold standard error (2SD) defines the range around the calculated mean that contains the true population mean with ca. 95 % probability. ## Limit of detection and limit of quantification @@ -31,3 +32,9 @@ ASTR allows for the intentional and meaningful handling of limits of detection/q The limit of detection, usually expressed as `LOD` (or other indicative notation), is defined as the smallest value that can be reliably detected. The limit of quantification (LOQ) is defined as the smallest amount that can be quantified with acceptable precision. + +In `archchem()`, the limit of detection where indicated by a below detection notation is automatically set to `NA`. Users requesting a more advanced approach by valuing the `LOD` in the ASTR package, e.g. for plotting functions, are requested to implement their own lambda function redefining the `bdl_strategy`. + +Substitution methods could be e.g. dropping the left-censored value by replacing it by `NA` or 0, calculating LOD/2 or LOD/√2, skipping \< of the left-censored value, or using regression models, enhanced censoring calculations, or maximum likelihood estimates [@giskeødegård2022; @helsel2006; @croghan2003f] + +# Bibliography diff --git a/vignettes/VG.ASTR.Schema.0.0.2.Rmd b/vignettes/VG.ASTR.Schema.0.0.2.Rmd deleted file mode 100644 index 0d2e2ee..0000000 --- a/vignettes/VG.ASTR.Schema.0.0.2.Rmd +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: "ASTR schema: Naming conventions" -csl: apa.csl -link-citations: TRUE -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{ASTR schema: Naming conventions} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} -bibliography: references.bib ---- - -The ASTR schema defines a set of naming and data conventions to create data objects that can be easily subset with (almost) no loss of information. Such datasets allow frictionless handling of them and their subsets between software and humans. Creating such datasets requires reduction of implicit information as much as possible (e.g. units of a value being defined in a separate column). Moreover, data objects must be readable for machines while preserving human readability and allow for direct import of spreadsheet-like formats. The conventions defined below are further influenced by considerations related to the analytical data and their quality, which are explained in this [vignette](VG.ASTR.Conventions.explained.html). - -The schema is platform and programming language agnostic. You can learn about the implementation of the schema in the ASTR package in [the dedicated vignette](VG.ASTR.Schema.Implementation.html). - -# Data preparation - -* All variable names are case sensitive. -* Decimals can only be read when indicated by a decimal point (0.5), as opposed to decimal commas (0,5). -* Apostrophes and any other special characters should be avoided in the sample/variable names. - -# Analytical data columns naming - -All columns that contain element and oxide compositions, isotopic values, or ratios derived therefrom as well as analytical uncertainties ("errors") should be named using the following conventions: - -* Only Latin characters can be supported in the column names, i.e. δ and ε will not be identified. -* The names of oxides and trace elements are self-explanatory (e.g. `SiO2` or `Si`). Total iron, if given, should be expressed as: `FeOtot` or `Fe2O3tot`. Loss on ignition, where known, should be expressed as `LOI`. The value "balance" provided by e.g. many pXRF instruments should be expressed as `Bal` or `Balance`. -* Units for values should follow element or oxide, as `_`. Units supported include *all SI units*, as well as *ppm*, *ppb*, *ppt*, *ppq*, *%*, *wt%*, *at%*, *‰*, *counts*, and *cps*, noted as such. -* Where known, specify *wt%* and *at%* instead of using *%*, and make the mixture type of concentrations explicit, e.g. write *ppm(m/m)* instead of *ppm*. For *‘per mille’*, use the symbol *‰*. -* For isotopic ratios, use simple forms such as `206Pb/204Pb`, `87Sr/86Sr`, `147Sm/144Nd`, or `d18O`. For isotope ratios expressed in δ-notation and similar expressions, always provide the mass of the isotope in the numerator (e.g. write `e143Nd` instead of `eNd`). -* If your dataset includes columns with additional information such as geolocation, or values derived from analytial data such as Pb isotope age model parameters, ensure the names do **not** contain a dash (‘-’) or underscore (‘\_’) prior to import and specify these columns as context in the `read_ASTR()` function. -* Analytical precision should be indicated in the column name as: `_err2SD`, `_errSD`, `_errSE`, `_err2SE` without indicating the unit. For absolute analytical uncertainties, the unit will be inferred from the corresponding composition column. Relative analytical uncertainties are indicated by adding a `%` sign, e.g. `_err2SD%`. We strongly recommend that the uncertainty is included in the data table, and properly noted following the conventions described. - -| Components | Accepted formats | -|----|----| -| Oxides and elements | `SiO2` ; `Si` | -| Total iron | `FeOtot` ; `Fe2O3tot` | -| Loss on ignition | `LOI` | -| Isotopic ratios | `206Pb/204Pb` ; `87Sr/86Sr` ; `147Sm/144Nd` ; `d18O` | -| Units for value | `_wt%` ; `_at%` | -| Analytical precision | `_err2SD` ; `_errSD` ; `_errSD%` ; `_errSD%` ; `_errSE` ; `_err2SE` | diff --git a/vignettes/VG.ASTR.Schema.Implementation.Rmd b/vignettes/VG.ASTR.Schema.Implementation.Rmd deleted file mode 100644 index 8804042..0000000 --- a/vignettes/VG.ASTR.Schema.Implementation.Rmd +++ /dev/null @@ -1,76 +0,0 @@ ---- -title: "ASTR schema: Implementation" -csl: apa.csl -link-citations: TRUE -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{ASTR schema: Implementation} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} -bibliography: references.bib ---- - -This vignette outlines how the conventions defined in [the ASTR schema](VG.ASTRschema.0.0.2.html) were implemented in the ASTR package. - -# Naming patterns - -* Elements, oxides, and isotopes in column names are compared to pre-compiled lists. While we aim to be as exhaustive as possible, we cannot guarantee they are complete for oxides and isotopes. For example, only naturally occurring isotopes are currently supported. If you encounter a missing compound or isotope, please reach out to the package maintainers or open an issue in the [ASTR GitHub repo](https://github.com/archaeothommy/ASTR). -* In addition to column names with single isotope, element, or oxide, ratios and sums are also supported. The table below provides some examples and as which type they will be recognized. - -| Column name | Type | Unit | -|----|----|----| -|`143Nd/144Nd` | isotope ratio | unitless | -|`d65Cu` | isotope ratio | unitless | -|`Na2O_wt%` | concentration | wtP | -|`S_at%` | concentration | atP | -|`75As_wt%` | concentration | wtP | -|`FeOtot_wt%` | concentration | wtP | -|`FeOtot_errSD%` | error | % | -|`Ag_ppb` | concentration | ng/g | -|`Ag_err2D` | error | ppb | -|`Te_cps` | concentration | counts/s | -|`Sn_µg/ml` | concentration | µg/ml | -|`206Pb/204Pb_errSE` | error | unitless | -|`Na2O+CaO_ppm` | concentration | mg/kg | -|`FeOtot/SiO2` | elemental ratio | unitless | -|`(Na2O+K2O)/SiO2` | elemental ratio | unitless | -|`(Ti/SiO2)/(Ag2O-Fe)` | elemental ratio | unitless | - -# Data import - -* Columns in a dataset are recognized either as isotope ratio, concentration, elemental ratio (i.e. ratio of concentrations), error (i.e., analytical precision), or contextual information. -* Contextual information is additional information about the analytical values such as sample number, geolocation or a group. Columns with such information must be explicitly declared during import, excluding them from pattern recognition. -* One column must be specified as `ID` column during import to provide a unique identifier for each line in the dataset. To ensure uniqueness of its values, `_1`, `_2`, ... `_n` will be added to non-unique values. The original column is preserved. -* Columns without a column header will be removed during import. -* The following notations will be automatically identified and replaced with `NA`, unless you explicitly define other values in `read_ASTR()`: `NA`, `N.A.`, `N/A`, `na`, `n/a`, `-`, and `n.d.`. Values containing common excel error messages (*#DIV/0!*, *#VALUE!*, *#REF!*, *#NAME?*, *#NUM!*, *#N/A*, and *#NULL!*) are also replaced with `NA` by default. -* Units will be removed from column names because {units} stores them in the column attributes. This allows for clean column names and therefore of e.g. axis labels in plots. They can be "shifted" from the column attributes back to the column names by `remove_units()` with `recover_unit_names = TRUE`. - -# Units - -* The package relies on `{units}`, which uses the [udunits](https://www.unidata.ucar.edu/software/udunits) C library, for handling all SI units (e.g. *µg/ml*) and relative concentration units (e.g. *ppm(m/V)*). If the mixture type is not specified, *m/m* is assumed. Non-SI units *wt%* and *at%* were defined as `wtP` and `atP`, respectively. -* Following the use of relative units being discouraged in current IUPAC recommendations, relative units are converted to absolute units wherever possible. This means that import of data in e.g. *ppm* is possible but they will be converted to *mg/kg* during import. Explicit conversion to *ppm* is still possible. -* As an exception, the relative unit *%* will not be converted to its SI unit equivalent during data import. However, unit conversions will treat it as any other relative unit, essentially handling it the same as *wt%*. -* The unit *wt%* (weight%) is defined as relative unit `wtP` analogous to e.g. *ppm*, meaning it is equivalent to "parts per hundred". The package provides support for conversion between *wt%* for elements and oxides (sometimes referred to as *oxide%*). Because this is a chemical rather than a mathematical conversion, both have the same unit and the distinction is made based on the chemical formula in the column name (e.g., `Fe` vs. `Fe2O3`). This conversion has additional complexity because one element can have multiple oxides. The conversion functions take this into account: Different options are offered to choose the oxide to convert into and if oxides convert into the same element, the columns are summarized into a single column per element. -* Conversion to and from *at%* (`atP`) is restricted to *wt%* (`wtP`). If you want to convert to or from *at%* in another unit, you must convert to *wt%* first. - -**NOTE**: Conversions currently support only concentrations provided as elements or oxides but not as isotopes (e.g. `204Pb`). - -# Limit of detection - -In `as_ASTR()`, the limit of detection where indicated by a below detection limit notation is automatically set to `NA`. Users requesting a more advanced approach by valuing the `LOD` in the ASTR package, e.g. for plotting functions, are requested to implement their own lambda function redefining the `bdl_strategy`. - -Substitution methods could be e.g. dropping the left-censored value by replacing it by `NA` or 0, calculating LOD/2 or LOD/√2, skipping \< of the left-censored value, or using regression models, enhanced censoring calculations, or maximum likelihood estimates [@giskeødegård2022; @helsel2006; @croghan2003f] - -# Output - -* Values derived by calculations, such as age model parameters of lead isotope data, are returned as an ASTR object together with the ID column, contextual columns and the input used for the calculation (after unit conversion), but without analytical values not used in the calculation. This avoids datasets growing unwieldingly complex and large. Unless the result is clearly another valid analytical value that can be classified according to the ASTR schema, they are classified as contextual information. - -# Export - -* ASTR does not provide a dedicated function to save ASTR objects as e.g. csv file. Instead, use the functions already available in R and its packages. Don't forget to "shift" the units from the column attributes back into the column names with `remove_units(df, recover_unit_names = TRUE)` before export. - -# ASTR vs. non-ASTR objects - -We do not want to make following the ASTR schema mandatory for using the functions in this package. Therefore, many of the functions not dedicated to the ASTR schema and its implementation support also non-ASTR objects. However, default values of functions are defined for ASTR objects and other convenient features, such as on-the-fly unit conversion, are restricted to ASTR objects. Read more about how to work with ASTR objects [in this vignette](ASTR.html). - -# References diff --git a/vignettes/VG.ASTRschema.0.0.2.Rmd b/vignettes/VG.ASTRschema.0.0.2.Rmd new file mode 100644 index 0000000..bc4f461 --- /dev/null +++ b/vignettes/VG.ASTRschema.0.0.2.Rmd @@ -0,0 +1,50 @@ +--- +title: "ASTR schema: Naming conventions" +csl: apa.csl +link-citations: TRUE +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{ASTR schema} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +bibliography: references.bib +--- + +ASTR follows the following naming and data conventions, which are described in detail in this vignette. + +## Data preparation + +- All variable names are case sensitive. +- Decimals can only be read when indicated by a decimal point (0.5), as opposed to decimal commas (0,5). +- Apostrophes and any other special characters should be avoided in the sample/variable names. + +## Analytical Data columns naming + +All columns that contain element and oxide compositions and analytical errors, isotopic values, or ratios derived therefrom should be named using the following conventions. + +- Only Latin characters can be supported in the column names, (i.e. δ and ε will not be identified). + +- The names of oxides and trace elements are self-explanatory (e.g. `SiO2` or `Si`). Total iron, if given, should be expressed as: `FeOtot` or `Fe2O3tot`. Loss on ignition, where known, should be expressed as `LOI`. + +- Units for values should follow element or oxide, as `_`. Units supported include *all SI units*, as well as *ppm*, *ppb*, *ppt*, *%*, *wt%*, *at%*, *w/w%*, *‰*, *counts*, and *cps*, noted as such. + +- Where known, specify *wt%* and *at%* instead of using *%*. For *‘per mille’*, use the symbol *‰*. + +- For isotopic ratios, use simple forms such as `206Pb/204Pb`, `87Sr/86Sr`, `147Sm/144Nd`, `eNd` or `d18O`. + +- If you have columns with Pb isotope model calculations in your dataset prior to importing data, ensure the names do **not** contain a dash (‘-’) or underscore (‘\_’) and specify these columns as context in the `read_archem()` function. The function `pb_iso_age_model()` can calculate model ages, µ (^238^U/^204^Pb), and κ (^232^Th/^238^U) values using the @stacey1975, @cumming1975, and @albarede1984 systems within ASTR. + +- The following notations will be automatically identified and replaced with `NA`, unless you explicitly define other values in `read_archem()`: *‘NA’*, *‘N.A.’*, *‘N/A’*, *‘na’*, *‘n/a’*, *‘-’*, and *‘n.d.’*. Values containing common excel error messages (*#DIV/0!*, *#VALUE!*, *#REF!*, *#NAME?*, *#NUM!*, *#N/A*, and *#NULL!*) are also replaced by `NA` automatically. + +- Analytical precision should be indicated in the column name as: `_err2SD`, `_errSD`, `_err2SD%`, `_errSD%`, `_errSE`, `_err2SE` without indicating the unit. The unit will be inferred from the corresponding composition column. SD, 2SD, SE, and 2SE can be expressed in absolute or relative values. We strongly recommend that the uncertainty is included in the data table, and properly noted following the conventions described. + +| Components | Accepted formats | +|----|----| +| Oxides and elements | `SiO2` ; `Si` | +| Total iron | `FeOtot` ; `Fe2O3tot` | +| Loss on ignition | `LOI` | +| Isotopic ratios | `206Pb/204Pb` ; `87Sr/86Sr` ; `147Sm/144Nd` ; `d18O` | +| Units for value | `_wt%` ; `_at%` | +| Analytical precision | `_err2SD` ; `_errSD` ; `_errSD%` ; `_errSD%` ; `_errSE` ; `_err2SE` | + +## References diff --git a/vignettes/references.bib b/vignettes/references.bib index bf21685..286b4d9 100644 --- a/vignettes/references.bib +++ b/vignettes/references.bib @@ -1,18 +1,3 @@ -@article{Bray2015, -title = {Form and flow: the ‘karmic cycle’ of copper}, -journal = {Journal of Archaeological Science}, -volume = {56}, -pages = {202-209}, -year = {2015}, -note = {Scoping the Future of Archaeological Science: Papers in Honour of Richard Klein}, -issn = {0305-4403}, -doi = {https://doi.org/10.1016/j.jas.2014.12.013}, -url = {https://www.sciencedirect.com/science/article/pii/S0305440314004749}, -author = {P. Bray and A. Cuénod and C. Gosden and P. Hommel and R. Liu and A.M. Pollard}, -keywords = {Copper, Recycling, Provenance, Typology}, -abstract = {The analysis and interpretation of the chemical composition of copper-alloys is one of the longest ongoing research projects within archaeological science. Beginning in the late 18th century these data have been consistently used to try and link objects with distinct metal sources. This paper argues the traditional provenance model for copper alloys is fatally flawed. Through pursuing a ‘pure’ source signal, chemical and isotopic datasets have been removed from their context and history. Social engagement with metal through processes such as reuse, recycling, and curation were rarely considered important by analysts. We offer an alternative model that unites the available legacy scientific datasets with process-metallurgy, archaeological and geographical context, and new conceptual approaches. Rather than provenance, we offer an empirical model of metal flow. Here objects are seen as snapshots of a wider metal stream; their final scientific characterisation including echoes of their previous forms and contexts. Through a series of case studies we highlight how the reinterpretation of existing datasets can disentangle the complex life histories of units of copper.} -} - @Article{DeCeuster2025, author="De Ceuster, Sarah and Hoogewerff, Jurian and Degryse, Patrick", title="Provenancing ancient materials with lead isotopes: overlap uncovered",