From 92d19916db69262a99ba9f233925774bc39f0709 Mon Sep 17 00:00:00 2001 From: abagna123 Date: Mon, 2 Mar 2026 14:42:43 +0100 Subject: [PATCH 01/14] add normalisation internal data --- R/sysdata.rda | Bin 1412 -> 516 bytes data-raw/spidegram_data.R | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 data-raw/spidegram_data.R diff --git a/R/sysdata.rda b/R/sysdata.rda index 9420ba2ed20f5ad39afff752f7bdef981c9e8eac..f00656f1f900ebb792269bb4301ca7f54a4f8a1c 100644 GIT binary patch literal 516 zcmV+f0{i_!T4*^jL0KkKS>gB=n*afyfB*mUc=v~5sKfv7|8&3S{~#hDiV%xt5Jx*P zP@)RxVwtc3cuJtsMya(ANr-4^kN`9Q8U~tZXfy$%K+pp~^g)x;B+-o~L>VvwU;rin z0003nOaM#(0WmND0WmQE$fk;EgwSZv001-q0000DG&BGJ00006;JDLe*pPm}&;%Bm ze9#KTR6_hO^gEc3*c*h(#Qu0pa=Q%zL1>^0PQkf6*dPMpVdY|}&{Ljam&K7xnQ+ap z<{7NRc;c9O(S_-bn3WGF;2?ktXiV@Vlpqu+h5C^4$x#R(?4SbS2p|lQh0;1=jX;aO zib*GZHHke|O+rK-n1Dtp!tYuQ5m=CyL%0l)cjp0!g&n%7mVJP7U>`v8bo8f6UU$Qx ztonQ$#fSEPZGxVv2HGD8NCx&@ z<8?>}#6=)9e>T$AD; z9*N0p9pv&MCK(M1dLvSJiRqNun2#vQnt|v~G^5lar?D^vN&o-=000008lFN^O{x!2 z(X}*a41fR|Pyhj^sS_HRB_5HZX_V7UnE*5m88iR{g(ilOX-AV$p^zE}s0|Go0iY`A z7>NmGlt6%2F?9pD;c!L>Nb2MLaWFsxKt&V)B0QY0)K*-U-YNDzj_zCiuzb>ezKO$* z7wmTu!gH-C7vcV6JfLhuy|T$I-`~U`lFFmW`}e-$oJ#ZbGdoIo=tP#{&02dGQI)hg zp_#<OIX7LEd|>y<3Q{^0mM_?n*GGT~^ub+v?ru-O0r@(LPT!bIjIk?C+0(e0HAR_nyf*yK5*q&j_3?gY)$%TD|&p zXa+G_i&%_+7L&llSK335-6lRAI0|)^K3q-Gk zD^$-r;?W)2RZzTE@tul0y)%s&w6ZjD-2jFF1Oh2lT*=NS6TT&dDbpy#)xbg+VFt7s z4G<>Co^%ouG*ocu0AUNgs)+A!wZW@e000010s)Nem6dR#EK=8jQxlWNT=0Yf0000G z07exd@nL6jZ%NwrSt{bRq@`ztlDHuNfd~Wu0T&|qQdfm>iB=Xg?}EKimw<>Z*rfnL zN5r=XRc|pg)*=I96jwN@pw*eZ(x{rl8#6JoHf%2oG+~e`Xog_sDfTS*v}GvG9)!CJ zWO5)k(wJK0M2vUh-eV+k@kZoI$jxU`eaUO6^D7i+lSC&qtwW4XbFy-&Z;BAY)f6S2 zHe#!^l4lYE&5$`8nQV~dQkmhK8IOU+tb}zVDzgi`Vly?}gs63{GFzwQ5!R1AJk-)&i9EcBw@t(EO!M+gk&eEHPDEC^`vTO#-O8CZySi8GARMYBO(HqIM5$OujE zDlwEkzlcQ6GiOO5YA){WaTvl}hJGkekki}ddb+=^hj-8B^8k_u1O)(Ha5IGL@sjLS zU#}(p#t`A&Qh*^dhaV}3(58Rgbx1pHiY0Ionu>e#uTM@n>D7fvRd`t!isV_bu~;l# zJ4`Oa2Jpe(?EG|Z>EBxD&nA}VwwmI&xh4v-G)V-kI(0cL5I{78xn_|M Date: Mon, 2 Mar 2026 14:51:22 +0100 Subject: [PATCH 02/14] add spidergram normalisation function --- R/normalise_spider.R | 97 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 R/normalise_spider.R diff --git a/R/normalise_spider.R b/R/normalise_spider.R new file mode 100644 index 0000000..d027251 --- /dev/null +++ b/R/normalise_spider.R @@ -0,0 +1,97 @@ +#' Normalise spidergram data +#' +#' Normalises selected elemental concentrations to a reference +#' composition such as chondrite or MORB. +#' +#' @param df A data frame in wide format. +#' @param elements Character vector of element names to normalise. +#' @param reference Character. One of "chondrite" or "MORB". +#' +#' @return A data frame with selected elements normalised. +#' +#' @details +#' Reference compositions are from Sun and McDonough 1989 +#' (Geological Society, London, Special Publications 42, 313 to 345). +#' MORB values correspond to N MORB. +#' All reference values are in ppm. +#' +#'#' @examples +#' df <- data.frame( +#' Sample = c("A", "B"), +#' La = c(10, 5), +#' Ce = c(20, 8) +#' ) +#' +#' normalise_spider( +#' df, +#' elements = c("La", "Ce"), +#' reference = "chondrite" +#' ) +#' +#' @export +normalise_spider <- function(df, + elements, + reference = c("chondrite", "MORB")) { + + reference <- match.arg(reference) + + # Basic checks + + if (!is.data.frame(df)) { + stop("`df` must be a data frame.") + } + + if (missing(elements) || length(elements) == 0) { + stop("`elements` must be provided.") + } + + if (!is.character(elements)) { + stop("`elements` must be a character vector.") + } + + # Check elements exist in data + + missing_cols <- elements[!elements %in% names(df)] + if (length(missing_cols) > 0) { + stop( + paste0( + "The following elements are not in `df`: ", + paste(missing_cols, collapse = ", ") + ) + ) + } + + # Get reference values + + ref_values <- spider_references[[reference]] + + if (is.null(ref_values)) { + stop("Reference not found in internal spider_references.") + } + + missing_ref <- elements[!elements %in% names(ref_values)] + if (length(missing_ref) > 0) { + stop( + paste0( + "Reference '", reference, + "' does not contain values for: ", + paste(missing_ref, collapse = ", ") + ) + ) + } + + # Normalisation + + out <- df + + for (el in elements) { + + if (!is.numeric(out[[el]])) { + stop(paste0("Column '", el, "' must be numeric.")) + } + + out[[el]] <- out[[el]] / ref_values[[el]] + } + + return(out) +} From 6b01c4d7e9989b8f1528b74fb1b8679daa7567c0 Mon Sep 17 00:00:00 2001 From: abagna123 Date: Mon, 9 Mar 2026 13:24:31 +0100 Subject: [PATCH 03/14] add normalise_spider() with checkmate validation and safe loop --- R/normalise_spider.R | 84 +++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 55 deletions(-) diff --git a/R/normalise_spider.R b/R/normalise_spider.R index d027251..e89b09c 100644 --- a/R/normalise_spider.R +++ b/R/normalise_spider.R @@ -4,27 +4,29 @@ #' composition such as chondrite or MORB. #' #' @param df A data frame in wide format. -#' @param elements Character vector of element names to normalise. +#' @param elements Character vector of element names. #' @param reference Character. One of "chondrite" or "MORB". #' #' @return A data frame with selected elements normalised. #' +#' @references +#' Sun, S.-s. & McDonough, W.F. (1989). Chemical and isotopic systematics +#' of oceanic basalts. Geological Society, London, Special Publications 42, +#' 313-345. Table 1, page 318. +#' #' @details -#' Reference compositions are from Sun and McDonough 1989 -#' (Geological Society, London, Special Publications 42, 313 to 345). -#' MORB values correspond to N MORB. -#' All reference values are in ppm. +#' MORB values correspond to N MORB. All reference values are in ppm. #' -#'#' @examples +#' @examples #' df <- data.frame( -#' Sample = c("A", "B"), -#' La = c(10, 5), -#' Ce = c(20, 8) +#' Sample = c("A","B"), +#' La = c(10,5), +#' Ce = c(20,8) #' ) #' #' normalise_spider( #' df, -#' elements = c("La", "Ce"), +#' elements = c("La","Ce"), #' reference = "chondrite" #' ) #' @@ -36,60 +38,32 @@ normalise_spider <- function(df, reference <- match.arg(reference) # Basic checks + checkmate::assert_data_frame(df) + checkmate::assert_character(elements, + min.len = 1, + any.missing = FALSE + ) - if (!is.data.frame(df)) { - stop("`df` must be a data frame.") - } - - if (missing(elements) || length(elements) == 0) { - stop("`elements` must be provided.") - } - - if (!is.character(elements)) { - stop("`elements` must be a character vector.") - } - - # Check elements exist in data - - missing_cols <- elements[!elements %in% names(df)] - if (length(missing_cols) > 0) { - stop( - paste0( - "The following elements are not in `df`: ", - paste(missing_cols, collapse = ", ") - ) - ) - } - - # Get reference values + checkmate::assert_subset( + elements, + choices = names(df) + ) ref_values <- spider_references[[reference]] - if (is.null(ref_values)) { - stop("Reference not found in internal spider_references.") - } + checkmate::assert_subset( + elements, + choices = names(ref_values) + ) - missing_ref <- elements[!elements %in% names(ref_values)] - if (length(missing_ref) > 0) { - stop( - paste0( - "Reference '", reference, - "' does not contain values for: ", - paste(missing_ref, collapse = ", ") - ) - ) - } + checkmate::assert_numeric( + unlist(df[elements]), + any.missing = TRUE + ) # Normalisation - out <- df - for (el in elements) { - - if (!is.numeric(out[[el]])) { - stop(paste0("Column '", el, "' must be numeric.")) - } - out[[el]] <- out[[el]] / ref_values[[el]] } From d79e7d64a5bede0a209e1a9478df84f5c802427f Mon Sep 17 00:00:00 2001 From: abagna123 Date: Fri, 20 Mar 2026 13:45:04 +0100 Subject: [PATCH 04/14] add geom_spider and GeomSpider ggproto, needs help debugging missing elements error --- R/GeomSpider.R | 47 ++++++++++++++++++ R/geom_spider.R | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 R/GeomSpider.R create mode 100644 R/geom_spider.R diff --git a/R/GeomSpider.R b/R/GeomSpider.R new file mode 100644 index 0000000..c2239c7 --- /dev/null +++ b/R/GeomSpider.R @@ -0,0 +1,47 @@ +#' Spidergram geom for ggplot2 +#' +#' @param mapping Aesthetic mappings (optional) +#' @param data Data frame in wide format containing element concentrations +#' @param elements Character vector of elements or a predefined group ("REE", "HFSE", "LILE") +#' @param reference Normalisation reference: "chondrite" or "MORB" +#' @param sample_id Column name for grouping samples (optional) +#' @param na.rm Logical: remove NA values +#' @param show.legend Logical: show legend +#' @param inherit.aes Logical: inherit aesthetics from ggplot call +#' @param ... Additional arguments passed to ggplot2::layer +#' +#' @export +geom_spider <- function(data, + elements, + reference = "chondrite", + sample_id = NULL, + na.rm = FALSE, + show.legend = NA, + inherit.aes = FALSE, + ...) { + + # Check required arguments + if (missing(data) || is.null(data)) { + cli::cli_abort("You must supply a data frame to geom_spider(data = ...).") + } + if (missing(elements) || is.null(elements)) { + cli::cli_abort("You must supply `elements` to geom_spider().") + } + + ggplot2::layer( + geom = GeomSpider, + mapping = ggplot2::aes(), # empty mapping keeps raw columns + data = data, + stat = "identity", + position = "identity", + show.legend = show.legend, + inherit.aes = inherit.aes, + params = list( + elements = elements, + reference = reference, + sample_id = sample_id, + na.rm = na.rm, + ... + ) + ) +} diff --git a/R/geom_spider.R b/R/geom_spider.R new file mode 100644 index 0000000..24847ce --- /dev/null +++ b/R/geom_spider.R @@ -0,0 +1,123 @@ +#' GeomSpider ggproto +#' +GeomSpider <- ggplot2::ggproto( + "GeomSpider", + ggplot2::Geom, + + required_aes = character(0), + + default_aes = ggplot2::aes( + colour = "black", + linewidth = 0.6, + linetype = 1, + alpha = NA + ), + + extra_params = c("na.rm", "elements", "reference", "sample_id"), + + draw_key = ggplot2::draw_key_path, + + setup_data = function(data, params) { + + if (!inherits(data, "data.frame")) { + cli::cli_abort("geom_spider: data must be a data frame") + } + + elements <- params$elements + # Resolve predefined element groups + if (length(elements) == 1 && elements %in% names(element_groups)) { + elements <- element_groups[[elements]] + } + + # Check elements exist + missing_elements <- setdiff(elements, names(data)) + if (length(missing_elements) > 0) { + cli::cli_abort(c( + "Elements not found in data: {.val {missing_elements}}", + "i" = "Available columns: {.val {names(data)}}" + )) + } + + # Normalize + norm_data <- normalise_spider( + df = data, + elements = elements, + reference = params$reference + ) + + # Pivot wide -> long + data_long <- tidyr::pivot_longer( + norm_data, + cols = dplyr::all_of(elements), + names_to = "element", + values_to = "value" + ) + + # Maintain order of elements + data_long$element <- factor(data_long$element, levels = elements) + + # Numeric x + data_long$x <- as.numeric(data_long$element) + data_long$y <- data_long$value + + # Grouping + if (!is.null(params$sample_id) && params$sample_id %in% names(data_long)) { + data_long$group <- data_long[[params$sample_id]] + } else { + data_long$group <- seq_len(nrow(norm_data)) + } + + data_long + }, + + draw_group = function(data, panel_params, coord) { + # Handle missing values by breaking lines + if (any(is.na(data$y))) { + not_na <- !is.na(data$y) + rle_not_na <- rle(not_na) + ends <- cumsum(rle_not_na$lengths) + starts <- c(1, ends[-length(ends)] + 1) + grobs <- list() + + for (i in seq_along(rle_not_na$lengths)) { + if (rle_not_na$values[i]) { + idx <- starts[i]:ends[i] + segment <- data[idx, , drop = FALSE] + if (nrow(segment) >= 2) { + coords <- coord$transform(segment, panel_params) + grobs[[length(grobs) + 1]] <- grid::polylineGrob( + coords$x, coords$y, + gp = grid::gpar( + col = coords$colour[1], + lwd = coords$linewidth[1] * .pt, + lty = coords$linetype[1], + alpha = coords$alpha[1] + ) + ) + } + } + } + + if (length(grobs) == 0) { + return(grid::nullGrob()) + } + return(do.call(grid::grobTree, grobs)) + } + + # No missing values + if (nrow(data) < 2) { + return(grid::nullGrob()) + } + + coords <- coord$transform(data, panel_params) + grid::polylineGrob( + coords$x, coords$y, id = coords$group, + gp = grid::gpar( + col = coords$colour, + lwd = coords$linewidth * .pt, + lty = coords$linetype, + alpha = coords$alpha + ) + ) + } +) From 24e2efa5ee99597b0cd6384a9dc6f5aae084499d Mon Sep 17 00:00:00 2001 From: Thomas Rose Date: Mon, 23 Mar 2026 18:42:03 -0400 Subject: [PATCH 05/14] revise normalisation function, properly include data objects and update file, clean-up geom_spider and add some note regarding implementation [skip ci] --- NAMESPACE | 2 + R/GeomSpider.R | 47 --------- R/data.R | 94 +++++++++++------- R/geom_spider.R | 93 ++++++++++++----- R/normalise_geochem.R | 58 +++++++++++ R/normalise_spider.R | 71 ------------- R/sysdata.rda | Bin 516 -> 0 bytes R/zzz.R | 21 +++- ...degram_data.R => geochem_reference_data.R} | 19 ++-- data/references_geochem.rda | Bin 0 -> 443 bytes data/standard_groups.rda | Bin 0 -> 211 bytes man/ASTR-package.Rd | 46 ++++----- man/archchem.Rd | 12 +-- man/geom_spider.Rd | 61 ++++++++++++ man/normalise_geochem.Rd | 43 ++++++++ man/references_geochem.Rd | 19 ++++ 16 files changed, 360 insertions(+), 226 deletions(-) delete mode 100644 R/GeomSpider.R create mode 100644 R/normalise_geochem.R delete mode 100644 R/normalise_spider.R delete mode 100644 R/sysdata.rda rename data-raw/{spidegram_data.R => geochem_reference_data.R} (67%) create mode 100644 data/references_geochem.rda create mode 100644 data/standard_groups.rda create mode 100644 man/geom_spider.Rd create mode 100644 man/normalise_geochem.Rd create mode 100644 man/references_geochem.Rd diff --git a/NAMESPACE b/NAMESPACE index ae379f9..918c433 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -21,12 +21,14 @@ export(copper_alloy_pollard) export(copper_group_bray) export(cumming_richards_1975) export(geom_kde2d) +export(geom_spider) 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(normalise_geochem) export(pb_iso_age_model) export(pointcloud_distribution) export(read_archchem) diff --git a/R/GeomSpider.R b/R/GeomSpider.R deleted file mode 100644 index c2239c7..0000000 --- a/R/GeomSpider.R +++ /dev/null @@ -1,47 +0,0 @@ -#' Spidergram geom for ggplot2 -#' -#' @param mapping Aesthetic mappings (optional) -#' @param data Data frame in wide format containing element concentrations -#' @param elements Character vector of elements or a predefined group ("REE", "HFSE", "LILE") -#' @param reference Normalisation reference: "chondrite" or "MORB" -#' @param sample_id Column name for grouping samples (optional) -#' @param na.rm Logical: remove NA values -#' @param show.legend Logical: show legend -#' @param inherit.aes Logical: inherit aesthetics from ggplot call -#' @param ... Additional arguments passed to ggplot2::layer -#' -#' @export -geom_spider <- function(data, - elements, - reference = "chondrite", - sample_id = NULL, - na.rm = FALSE, - show.legend = NA, - inherit.aes = FALSE, - ...) { - - # Check required arguments - if (missing(data) || is.null(data)) { - cli::cli_abort("You must supply a data frame to geom_spider(data = ...).") - } - if (missing(elements) || is.null(elements)) { - cli::cli_abort("You must supply `elements` to geom_spider().") - } - - ggplot2::layer( - geom = GeomSpider, - mapping = ggplot2::aes(), # empty mapping keeps raw columns - data = data, - stat = "identity", - position = "identity", - show.legend = show.legend, - inherit.aes = inherit.aes, - params = list( - elements = elements, - reference = reference, - sample_id = sample_id, - na.rm = na.rm, - ... - ) - ) -} diff --git a/R/data.R b/R/data.R index 7a5ecaa..5b1670c 100644 --- a/R/data.R +++ b/R/data.R @@ -5,19 +5,28 @@ #' @format a vector #' #' @family chemical_reference_data -#' @name elements -"elements" +#' @name elements_data +"elements_data" #' Oxides #' -#' List of oxides, retrieved from https://www.wikidoc.org/index.php/Oxide, -#' sorted according to alphabet +#' List of oxides, sorted according to alphabet. #' #' @format a vector #' #' @family chemical_reference_data -#' @name oxides -"oxides" +#' @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 #' @@ -27,37 +36,26 @@ #' @format a vector #' #' @family chemical_reference_data -#' @name isotopes -"isotopes" +#' @name isotopes_data +"isotopes_data" -#' 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" +#' Conversion factors from oxides to elements +#' +#' @format A data frame with 106 rows and 7 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" #' ArgentinaDatabase #' @@ -70,3 +68,27 @@ #' @source #' @name ArgentinaDatabase "ArgentinaDatabase" + +#' Geochemical reference compositions +#' +#' List with reference values for common geochemical normalisation such as +#' chondrite or MORB. All values in ppm. See the dataset for a list of available +#' reference compositions. +#' +#' @references Chondrite: Table 1 in Sun, S.-S. and McDonough, W. F. (1989) +#' Chemical and isotopic systematics of oceanic basalts. Geological Society, +#' London, Special Publications 42, +#' 313-345. ( +#' +#' MORB: values for NMORB. +#' +"references_geochem" + +#' Geochemical reference compositions +#' +#' Lists with chemical symbols of typical element and oxide sets used in +#' geochemistry and archaeometry, such as REE. They allow more convenient and +#' reproducible subsetting of datasets. See the dataset for a list of available +#' sets. +#' +"standard_groups" diff --git a/R/geom_spider.R b/R/geom_spider.R index 24847ce..840db05 100644 --- a/R/geom_spider.R +++ b/R/geom_spider.R @@ -1,10 +1,71 @@ -#' GeomSpider ggproto +#' Spidergram geom for ggplot2 #' +#' Descriptions goes here ################### +#' #### This will likely only work with ASTR objects or similarly wide data frame!? +#' #### Or is there a way to identify short vs. long form!? +#' #### e.g. single value to x and col content = character: long format, x = character vector length > 1 and column content of x = numeric: wide format +#' #### y = single value and numeric: long format, concentration, y is not provided: wide format +#' #### long format values do not need to be transformed (but normalised!?), wide format must be transformed to long format +#' +#' Normalisation is done with [normalise_geochem()]. If data are geochemically +#' normalised, only normalised elements are plotted. Otherwise, all elements +#' are plotted. +#' +#' @inheritParams ggplot2::layer +#' @param reference `NULL`, the default, if data should not be normalised or +#' name of the geochemical reference composition to which data should be +#' normalised. See [references_geochem] for a list of names. +#' @param na.rm Logical: remove NA values +#' @param ... 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`. +#' +#' @export +#' +#' @examples +#' # include example with data[[standard_groups$REE]] +#' +#' library(ggplot2) +#' +#' test <- data.frame( +#' Sample = c("A","B"), +#' Yb = c(8,9), +#' La = c(10,5), +#' Ce = c(20,8) +#' ) +#' +#' ggplot(test) + geom_spider(mapping = aes(x = standard_groups$REE, color = Sample)) +#' +geom_spider <- function(mapping = NULL, + data = NULL, + inherit.aes = TRUE, + reference = NULL, + na.rm = FALSE, + show.legend = NA, + ...) { + + # Check required arguments + ggplot2::layer( + geom = GeomSpider, + mapping = mapping, # empty mapping keeps raw columns + data = data, + stat = "identity", + position = "identity", + show.legend = show.legend, + inherit.aes = inherit.aes, + params = list( + reference = reference, + na.rm = na.rm, + ... + ) + ) +} + GeomSpider <- ggplot2::ggproto( "GeomSpider", ggplot2::Geom, - required_aes = character(0), + required_aes = character(0), # one grouping aes (group, colour, ...) default_aes = ggplot2::aes( colour = "black", @@ -13,37 +74,17 @@ GeomSpider <- ggplot2::ggproto( alpha = NA ), - extra_params = c("na.rm", "elements", "reference", "sample_id"), + extra_params = c("na.rm", "reference"), draw_key = ggplot2::draw_key_path, setup_data = function(data, params) { - if (!inherits(data, "data.frame")) { - cli::cli_abort("geom_spider: data must be a data frame") - } - - elements <- params$elements - # Resolve predefined element groups - if (length(elements) == 1 && elements %in% names(element_groups)) { - elements <- element_groups[[elements]] + # Normalisation + if (!is.null(params$reference)) { + data <- normalise_geochem(data, reference = params$reference) } - # Check elements exist - missing_elements <- setdiff(elements, names(data)) - if (length(missing_elements) > 0) { - cli::cli_abort(c( - "Elements not found in data: {.val {missing_elements}}", - "i" = "Available columns: {.val {names(data)}}" - )) - } - - # Normalize - norm_data <- normalise_spider( - df = data, - elements = elements, - reference = params$reference - ) # Pivot wide -> long data_long <- tidyr::pivot_longer( diff --git a/R/normalise_geochem.R b/R/normalise_geochem.R new file mode 100644 index 0000000..45156d4 --- /dev/null +++ b/R/normalise_geochem.R @@ -0,0 +1,58 @@ +#' Geochemical normalisation of data +#' +#' Normalises selected elemental concentrations to a reference composition such +#' as chondrite or MORB. +#' +#' See [references_geochem] for supported geochemical reference compositions and +#' which elements are covered by which reference composition. The function +#' converts all elements in the dataframe for which a reference composition is +#' available. A warning informs if not all elements in the reference composition +#' are included in the data frame, and an error if none is included. +#' +#' @param df A data frame in wide format. +#' @param reference Character string with the normalisation. See Details for +#' further information. +#' +#' @return The data frame with the selected elements normalised. +#' +#' @references Sun, S.-s. & McDonough, W.F. (1989). Chemical and isotopic +#' systematics of oceanic basalts. Geological Society, London, Special +#' Publications 42, 313-345. Table 1, page 318. +#' +#' @examples +#' df <- data.frame( +#' Sample = c("A","B"), +#' La = c(10,5), +#' Ce = c(20,8) +#' ) +#' +#' normalise_spider( +#' df, +#' elements = c("La","Ce"), +#' reference = "chondrite" +#' ) +#' +#' @export +normalise_geochem <- function(df, reference = names(references_geochem)) { + + reference <- match.arg(reference) + + # Basic checks + checkmate::assert_data_frame(df) + + elements <- intersect(colnames(df), names(references_geochem[[reference]])) + + if (length(elements) < length(references_geochem[[reference]])) { + if (length(elements) == 0) { + stop("Dataset does not include any element of the reference data.") + } else { + warning("Dataset does not include all elements of the reference data.") + } + } + + print(references_geochem[[reference]][elements]) + # Normalisation + df[elements] <- t(t(df[elements]) / references_geochem[[reference]][elements]) + + return(df) +} diff --git a/R/normalise_spider.R b/R/normalise_spider.R deleted file mode 100644 index e89b09c..0000000 --- a/R/normalise_spider.R +++ /dev/null @@ -1,71 +0,0 @@ -#' Normalise spidergram data -#' -#' Normalises selected elemental concentrations to a reference -#' composition such as chondrite or MORB. -#' -#' @param df A data frame in wide format. -#' @param elements Character vector of element names. -#' @param reference Character. One of "chondrite" or "MORB". -#' -#' @return A data frame with selected elements normalised. -#' -#' @references -#' Sun, S.-s. & McDonough, W.F. (1989). Chemical and isotopic systematics -#' of oceanic basalts. Geological Society, London, Special Publications 42, -#' 313-345. Table 1, page 318. -#' -#' @details -#' MORB values correspond to N MORB. All reference values are in ppm. -#' -#' @examples -#' df <- data.frame( -#' Sample = c("A","B"), -#' La = c(10,5), -#' Ce = c(20,8) -#' ) -#' -#' normalise_spider( -#' df, -#' elements = c("La","Ce"), -#' reference = "chondrite" -#' ) -#' -#' @export -normalise_spider <- function(df, - elements, - reference = c("chondrite", "MORB")) { - - reference <- match.arg(reference) - - # Basic checks - checkmate::assert_data_frame(df) - checkmate::assert_character(elements, - min.len = 1, - any.missing = FALSE - ) - - checkmate::assert_subset( - elements, - choices = names(df) - ) - - ref_values <- spider_references[[reference]] - - checkmate::assert_subset( - elements, - choices = names(ref_values) - ) - - checkmate::assert_numeric( - unlist(df[elements]), - any.missing = TRUE - ) - - # Normalisation - out <- df - for (el in elements) { - out[[el]] <- out[[el]] / ref_values[[el]] - } - - return(out) -} diff --git a/R/sysdata.rda b/R/sysdata.rda deleted file mode 100644 index f00656f1f900ebb792269bb4301ca7f54a4f8a1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 516 zcmV+f0{i_!T4*^jL0KkKS>gB=n*afyfB*mUc=v~5sKfv7|8&3S{~#hDiV%xt5Jx*P zP@)RxVwtc3cuJtsMya(ANr-4^kN`9Q8U~tZXfy$%K+pp~^g)x;B+-o~L>VvwU;rin z0003nOaM#(0WmND0WmQE$fk;EgwSZv001-q0000DG&BGJ00006;JDLe*pPm}&;%Bm ze9#KTR6_hO^gEc3*c*h(#Qu0pa=Q%zL1>^0PQkf6*dPMpVdY|}&{Ljam&K7xnQ+ap z<{7NRc;c9O(S_-bn3WGF;2?ktXiV@Vlpqu+h5C^4$x#R(?4SbS2p|lQh0;1=jX;aO zib*GZHHke|O+rK-n1Dtp!tYuQ5m=CyL%0l)cjp0!g&n%7mVJP7U>`v8bo8f6UU$Qx ztonQ$#fSEPZGxVv2HGD8NCx&@ z<8?>}#6=)9e>T$AD%" #' @importFrom rlang .data diff --git a/data-raw/spidegram_data.R b/data-raw/geochem_reference_data.R similarity index 67% rename from data-raw/spidegram_data.R rename to data-raw/geochem_reference_data.R index fdc5adf..5a92b9c 100644 --- a/data-raw/spidegram_data.R +++ b/data-raw/geochem_reference_data.R @@ -5,20 +5,16 @@ # REE retrieved from https://en.wikipedia.org/wiki/Rare-earth_element, # HFSE & LILE retrieved from https://en.wikipedia.org/wiki/Incompatible_element -element_groups <- list( +standard_groups <- list( REE = c("La", "Ce", "Pr", "Nd", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu"), HFSE = c("Nb", "Ta", "Zr", "Hf", "Ti", "Th", "U"), LILE = c("Rb", "Ba", "K", "Sr", "Cs") ) -# Normalisation standards - -# Source: Sun, S.-s. & McDonough, W.F. (1989). Chemical and isotopic systematics -# of oceanic basalts. Geological Society, London, Special Publications 42, -# 313-345. Table 1, page 318. MORB values are NMORB. - -spider_references <- list( +# Geochemical reference compositions +# units: ppm +references_geochem <- list( chondrite = c( La = 0.237, Ce = 0.612, Pr = 0.095, Nd = 0.467, Sm = 0.153, Eu = 0.058, Gd = 0.2055, Tb = 0.0374, Dy = 0.2540, Ho = 0.0566, @@ -33,8 +29,7 @@ spider_references <- list( ) # Save as internal data -usethis::use_data(element_groups, spider_references, - internal = TRUE, +usethis::use_data(standard_groups, + references_geochem, + internal = FALSE, overwrite = TRUE) - -# Units: ppm diff --git a/data/references_geochem.rda b/data/references_geochem.rda new file mode 100644 index 0000000000000000000000000000000000000000..2c9d2c7ecd825633af1615f36e1aac1435c8edb4 GIT binary patch literal 443 zcmV;s0Yv^nT4*^jL0KkKS=?f%(f|PdfB*mUSoeowsKfuy|75@8{~#hDiV%xt5Jx*P zP@)RxVwtc3IDjQhDt@CSNVEQzxWqZ%rxX z5NU~k0000000000001KhzyJUMltncjqaz>#KmY&$0017NKmY&$000dfmyBzKC@mlY zB!aOgP@+Mw8VG2r$tz>9>&)`Xw4qP#8AbO- zoBt(#?I%K1J9Ex~ou@A58lIl(-FGBR>RP$B7*M&VO=XHSo7OEs(1HDAdckNaFFL|H z22B-`5bec4{A;j#p<$olZEqq0*r?Km?Fpjd@JuC)lsOr+Z-0Tc@S&jF2B0=sA4{fL z^oy^PN@|-r&vQ}`a((Fpz@lLekA&xx+)TOSf>2k6Wh!peXniOKRX51|)MhHRPd+TD ln==)w*us#K(5mB~;9*rND@Vsw(Da}2cO+AV2@S?7jUZJqza; Date: Mon, 30 Mar 2026 14:35:31 +0200 Subject: [PATCH 06/14] Add comma after 'ArgentinaDatabase' to fix parse error --- R/zzz.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/zzz.R b/R/zzz.R index 28efeb9..080a969 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -11,7 +11,7 @@ utils::globalVariables( "oxides_data", "special_oxide_states", "conversion_oxides", - "ArgentinaDatabase" + "ArgentinaDatabase", "standard_groups", "references_geochem" ) From a679ff0300c903f71ea0859b66ac7a5edb756b20 Mon Sep 17 00:00:00 2001 From: abagna123 Date: Mon, 30 Mar 2026 14:36:43 +0200 Subject: [PATCH 07/14] add normalise_geochem tests --- tests/testthat/test_normalise_geochem.R | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 tests/testthat/test_normalise_geochem.R diff --git a/tests/testthat/test_normalise_geochem.R b/tests/testthat/test_normalise_geochem.R new file mode 100644 index 0000000..f39de94 --- /dev/null +++ b/tests/testthat/test_normalise_geochem.R @@ -0,0 +1,49 @@ +# tests/testthat/test-normalise_geochem.R + +test_that("normalise_geochem handles all cases", { + + df <- data.frame( + Sample = c("A", "B", "C", "D"), + La = c(10, NA, 5, 20), + Ce = c(20, 8, NA, 40), + Nd = c(15, 6, 3, 30), + X = c(1, 2, 3, 4) + ) + + # Run normalisation using internal reference data + result <- normalise_geochem(df, reference = "chondrite") + + # Check normalization math (using real reference values) + ref <- references_geochem$chondrite + + expect_equal(result$La, df$La / ref["La"]) + expect_equal(result$Ce, df$Ce / ref["Ce"]) + expect_equal(result$Nd, df$Nd / ref["Nd"]) + + # Check non-element columns unchanged + expect_equal(result$X, df$X) + expect_equal(result$Sample, df$Sample) + + # Check NA values preserved + expect_true(is.na(result$La[2])) + expect_true(is.na(result$Ce[3])) + + # Warning when some elements missing + df_partial <- df[, c("Sample", "La")] + expect_warning( + normalise_geochem(df_partial, reference = "chondrite"), + regexp = "does not include all elements" + ) + + # Error when no matching elements + df_none <- data.frame(Sample = c("A", "B"), X = c(1, 2)) + expect_error( + normalise_geochem(df_none, reference = "chondrite"), + regexp = "does not include any element" + ) + + # Structure checks + expect_s3_class(result, "data.frame") + expect_equal(nrow(result), nrow(df)) + expect_equal(names(result), names(df)) +}) From 7b2ae52c3fcbdbf3739a358290f6363777dee34f Mon Sep 17 00:00:00 2001 From: Thomas Rose Date: Tue, 7 Apr 2026 09:01:16 -0400 Subject: [PATCH 08/14] mute warnings --- tests/testthat/test_normalise_geochem.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test_normalise_geochem.R b/tests/testthat/test_normalise_geochem.R index f39de94..2e9ff0f 100644 --- a/tests/testthat/test_normalise_geochem.R +++ b/tests/testthat/test_normalise_geochem.R @@ -11,7 +11,9 @@ test_that("normalise_geochem handles all cases", { ) # Run normalisation using internal reference data - result <- normalise_geochem(df, reference = "chondrite") + result <- suppressWarnings( + normalise_geochem(df, reference = "chondrite") + ) # Check normalization math (using real reference values) ref <- references_geochem$chondrite From 958bff549addad101162b73b021e7f08af999905 Mon Sep 17 00:00:00 2001 From: Thomas Rose Date: Sun, 12 Apr 2026 16:56:17 -0400 Subject: [PATCH 09/14] * add function to turn wide/ASTR format into long format * implements how geom handles wide format as intended --- DESCRIPTION | 1 + R/ASTR_utils.R | 22 ++++++++++++++++++++++ R/geom_spider.R | 18 +++++++----------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index b582709..155253a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -56,6 +56,7 @@ Imports: stats, tibble, tidyselect, + tidyr, units, vctrs, ggplot2, diff --git a/R/ASTR_utils.R b/R/ASTR_utils.R index 7bf5198..f39e0fe 100644 --- a/R/ASTR_utils.R +++ b/R/ASTR_utils.R @@ -87,3 +87,25 @@ transform_notation <- function(unit) { } unit } + +#' Transforms ASTR format into long format for plotting with ggplot2 +#' +#' The function expects that a data frame is passed as aesthetic to ggplot, +#' resulting in a tibble with a nested dataframe with the name of the aesthtic. +#' +#' @param df the data frame to be transformed into long format +#' @param aesthetic the aesthetic that contains the values from ASTR +#' @param value the name of the column with the values after transformation into +#' long format +#' @keywords internal +#' +ASTR_to_long <- function(df, aesthetic, value) { + colnames(df[[aesthetic]]) <- paste(aesthetic, colnames(df[[aesthetic]]), sep = ".") + tidyr::unnest(df, tidyselect::all_of(aesthetic)) %>% + tidyr::pivot_longer( + cols = tidyselect::starts_with(aesthetic), + names_to = aesthetic, + values_to = value, + names_prefix = paste0(aesthetic, ".") + ) +} diff --git a/R/geom_spider.R b/R/geom_spider.R index 840db05..d23bbe2 100644 --- a/R/geom_spider.R +++ b/R/geom_spider.R @@ -65,7 +65,7 @@ GeomSpider <- ggplot2::ggproto( "GeomSpider", ggplot2::Geom, - required_aes = character(0), # one grouping aes (group, colour, ...) + required_aes = c("elements"), # one grouping aes (group, colour, ...) default_aes = ggplot2::aes( colour = "black", @@ -82,23 +82,19 @@ GeomSpider <- ggplot2::ggproto( # Normalisation if (!is.null(params$reference)) { - data <- normalise_geochem(data, reference = params$reference) + data[["elements"]] <- normalise_geochem(data[["elements"]], reference = params$reference) } - # Pivot wide -> long - data_long <- tidyr::pivot_longer( - norm_data, - cols = dplyr::all_of(elements), - names_to = "element", - values_to = "value" - ) + data_long <- ASTR_to_long(data, "elements", "value") + + str(data_long) # Maintain order of elements - data_long$element <- factor(data_long$element, levels = elements) + data_long$elements <- factor(data_long$elements, levels = elements) # Numeric x - data_long$x <- as.numeric(data_long$element) + data_long$x <- as.numeric(data_long$elements) data_long$y <- data_long$value # Grouping From 2dc2fc8947d490a4367aba87516fa33110309cd4 Mon Sep 17 00:00:00 2001 From: abagna123 Date: Tue, 28 Apr 2026 16:18:34 +0200 Subject: [PATCH 10/14] update geom_spider() with wide-to-long transformation and NA line breaks. --- R/geom_spider.R | 195 ++++++++++++++++++++++++++---------------------- 1 file changed, 106 insertions(+), 89 deletions(-) diff --git a/R/geom_spider.R b/R/geom_spider.R index d23bbe2..fcf9abf 100644 --- a/R/geom_spider.R +++ b/R/geom_spider.R @@ -39,25 +39,68 @@ geom_spider <- function(mapping = NULL, data = NULL, inherit.aes = TRUE, + elements = NULL, reference = NULL, na.rm = FALSE, show.legend = NA, ...) { - # Check required arguments - ggplot2::layer( - geom = GeomSpider, - mapping = mapping, # empty mapping keeps raw columns - data = data, - stat = "identity", - position = "identity", - show.legend = show.legend, - inherit.aes = inherit.aes, - params = list( - reference = reference, - na.rm = na.rm, - ... - ) + .data <- data + .elements <- elements + .reference <- reference + + mapping <- utils::modifyList( + ggplot2::aes(x = x, y = y), + if (!is.null(mapping)) mapping else ggplot2::aes() + ) + + list( + suppressWarnings( + ggplot2::layer( + geom = GeomSpider, + mapping = mapping, + data = function(x) { + d <- if (!is.null(.data)) .data else x + + if (!is.null(.reference)) { + d <- normalise_geochem(d, reference = .reference) + } + + elements_present <- intersect(.elements, colnames(d)) + if (length(elements_present) == 0) { + stop("None of the requested elements are present as columns in the data.") + } + if (length(elements_present) < length(.elements)) { + warning("Some requested elements are absent and will be skipped: ", + paste(setdiff(.elements, elements_present), collapse = ", ")) + } + + meta_cols <- setdiff(colnames(d), elements_present) + + data_long <- do.call(rbind, lapply(elements_present, function(el) { + row <- d[meta_cols] + row$elements <- el + row$y <- d[[el]] + row + })) + + data_long$elements <- factor(data_long$elements, levels = elements_present) + data_long$x <- as.numeric(data_long$elements) + + data_long + }, + stat = "identity", + position = "identity", + show.legend = show.legend, + inherit.aes = inherit.aes, + params = list(na.rm = na.rm, ...) + ) + ), + ggplot2::scale_x_continuous( + breaks = seq_along(.elements), + labels = .elements + ), + ggplot2::labs(x = NULL, y = "Concentration") ) } @@ -65,96 +108,70 @@ GeomSpider <- ggplot2::ggproto( "GeomSpider", ggplot2::Geom, - required_aes = c("elements"), # one grouping aes (group, colour, ...) + required_aes = character(0), default_aes = ggplot2::aes( - colour = "black", + colour = "black", linewidth = 0.6, - linetype = 1, - alpha = NA + linetype = 1, + alpha = NA ), - extra_params = c("na.rm", "reference"), + extra_params = c("na.rm"), draw_key = ggplot2::draw_key_path, setup_data = function(data, params) { - - # Normalisation - if (!is.null(params$reference)) { - data[["elements"]] <- normalise_geochem(data[["elements"]], reference = params$reference) - } - - # Pivot wide -> long - data_long <- ASTR_to_long(data, "elements", "value") - - str(data_long) - - # Maintain order of elements - data_long$elements <- factor(data_long$elements, levels = elements) - - # Numeric x - data_long$x <- as.numeric(data_long$elements) - data_long$y <- data_long$value - - # Grouping - if (!is.null(params$sample_id) && params$sample_id %in% names(data_long)) { - data_long$group <- data_long[[params$sample_id]] - } else { - data_long$group <- seq_len(nrow(norm_data)) - } - - data_long + data }, draw_group = function(data, panel_params, coord) { - # Handle missing values by breaking lines - if (any(is.na(data$y))) { - not_na <- !is.na(data$y) - rle_not_na <- rle(not_na) - ends <- cumsum(rle_not_na$lengths) - starts <- c(1, ends[-length(ends)] + 1) - grobs <- list() - - for (i in seq_along(rle_not_na$lengths)) { - if (rle_not_na$values[i]) { - idx <- starts[i]:ends[i] - segment <- data[idx, , drop = FALSE] - if (nrow(segment) >= 2) { - coords <- coord$transform(segment, panel_params) - grobs[[length(grobs) + 1]] <- grid::polylineGrob( - coords$x, coords$y, - gp = grid::gpar( - col = coords$colour[1], - lwd = coords$linewidth[1] * .pt, - lty = coords$linetype[1], - alpha = coords$alpha[1] - ) - ) - } - } - } - - if (length(grobs) == 0) { - return(grid::nullGrob()) - } - return(do.call(grid::grobTree, grobs)) - } - # No missing values - if (nrow(data) < 2) { - return(grid::nullGrob()) + if (nrow(data) < 2) return(grid::nullGrob()) + + # Replace NA alpha with 1 + data$alpha[is.na(data$alpha)] <- 1 + + data <- data[order(data$x), ] + + # Fast path — no NAs + if (!any(is.na(data$y))) { + coords <- coord$transform(data, panel_params) + return( + grid::polylineGrob( + coords$x, coords$y, + gp = grid::gpar( + col = coords$colour[1], + lwd = coords$linewidth[1] * ggplot2::.pt, + lty = coords$linetype[1], + alpha = coords$alpha[1] + ) + ) + ) } - coords <- coord$transform(data, panel_params) - grid::polylineGrob( - coords$x, coords$y, id = coords$group, - gp = grid::gpar( - col = coords$colour, - lwd = coords$linewidth * .pt, - lty = coords$linetype, - alpha = coords$alpha + # NA handling — breaks in line at missing elements + not_na <- !is.na(data$y) + run_ids <- cumsum(c(TRUE, diff(not_na) != 0)) + + grobs <- lapply(unique(run_ids[not_na]), function(run) { + segment <- data[not_na & run_ids == run, , drop = FALSE] + if (nrow(segment) < 2) return(NULL) + + coords <- coord$transform(segment, panel_params) + grid::polylineGrob( + coords$x, coords$y, + gp = grid::gpar( + col = coords$colour[1], + lwd = coords$linewidth[1] * ggplot2::.pt, + lty = coords$linetype[1], + alpha = coords$alpha[1] + ) ) - ) + }) + + grobs <- Filter(Negate(is.null), grobs) + if (length(grobs) == 0) return(grid::nullGrob()) + do.call(grid::grobTree, grobs) } ) From 38f550e79fb8a450e63ec3ffa7353882d55759b8 Mon Sep 17 00:00:00 2001 From: abagna123 Date: Tue, 28 Apr 2026 16:52:51 +0200 Subject: [PATCH 11/14] fix lint, pkgdown, and CRAN check issues --- R/geom_spider.R | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/R/geom_spider.R b/R/geom_spider.R index fcf9abf..8cc4862 100644 --- a/R/geom_spider.R +++ b/R/geom_spider.R @@ -1,11 +1,13 @@ #' Spidergram geom for ggplot2 #' -#' Descriptions goes here ################### +#'Descriptions goes here ################### #' #### This will likely only work with ASTR objects or similarly wide data frame!? #' #### Or is there a way to identify short vs. long form!? -#' #### e.g. single value to x and col content = character: long format, x = character vector length > 1 and column content of x = numeric: wide format +#' #### e.g. single value to x and col content = character: long format, +#' x = character vector length > 1 and column content of x = numeric: wide format #' #### y = single value and numeric: long format, concentration, y is not provided: wide format -#' #### long format values do not need to be transformed (but normalised!?), wide format must be transformed to long format +#' #### long format values do not need to be transformed (but normalised!?), +#' wide format must be transformed to long format #' #' Normalisation is done with [normalise_geochem()]. If data are geochemically #' normalised, only normalised elements are plotted. Otherwise, all elements @@ -50,7 +52,7 @@ geom_spider <- function(mapping = NULL, .reference <- reference mapping <- utils::modifyList( - ggplot2::aes(x = x, y = y), + ggplot2::aes(x = .data$x, y = .data$y), if (!is.null(mapping)) mapping else ggplot2::aes() ) From 74f1607d5d8c50b5265320b6b7f128a4fac8df28 Mon Sep 17 00:00:00 2001 From: Thomas Rose Date: Mon, 25 May 2026 20:11:55 -0400 Subject: [PATCH 12/14] document data objects and add additional compositions and units to data objects --- R/ASTR_data.R | 49 ++++++++++++++++++ data-raw/geochem_reference_data.R | 80 ++++++++++++++++++++++++------ data/references_geochem.rda | Bin 443 -> 1392 bytes data/standard_groups.rda | Bin 211 -> 207 bytes man/references_geochem.Rd | 37 ++++++++++++++ man/standard_groups.Rd | 32 ++++++++++++ 6 files changed, 182 insertions(+), 16 deletions(-) create mode 100644 man/references_geochem.Rd create mode 100644 man/standard_groups.Rd diff --git a/R/ASTR_data.R b/R/ASTR_data.R index bd0fe3f..e95503f 100644 --- a/R/ASTR_data.R +++ b/R/ASTR_data.R @@ -69,3 +69,52 @@ #' @source #' @name ArgentinaDatabase "ArgentinaDatabase" + +#' Geochemical and other standard groups of elements, oxides, or isotopes +#' @format A list of sets of elements, oxides, or isotopes that represent +#' geochemical groups or other commonly used groups. To retrieve the full list +#' of e.g. the HFSE elements, run `standard_groups$HFSE`. +#' \describe{ +#' \item{REE}{Rare Earth Elements, taken from Periodic table of elements} +#' \item{HFSE}{High field-strength elements as listed in Salters (1998)} +#' \item{LILE}{Large-ion lithophile elements, as listed in Rudnick (1998)} +#' } +#' +#' @references Salters, V.J.M. (1998). Elements: High field strength. In: +#' Geochemistry. Encyclopedia of Earth Science. Springer, Dordrecht. +#' https://doi.org/10.1007/1-4020-4496-8_101 +#' +#' Rudnick, R.L. (1998). Elements: Large-ion lithophile. In: Geochemistry. +#' Encyclopedia of Earth Science. Springer, Dordrecht. +#' https://doi.org/10.1007/1-4020-4496-8_104 +#' +#' @name standard_groups +"standard_groups" + +#' Reference compositions +#' +#' @format A list including sets of chemical compositions often used as +#' reference composition for e.g. normalisation. Values are stored as named +#' vectors of their concentration with assigned units (using +#' \link[units]{set_units}). To retrieve the list of elements and their +#' concentrations for e.g. the PM, run `references_geochem$PM`. +#' \describe{ +#' \item{chondrite}{CI chondrite composition in ppm, as defined by Sun & +#' McDonough (1989)} +#' \item{PM}{Primitive mantle composition in ppm, as defined by Sun & +#' McDonough (1989)} +#' \item{NMORB}{Normal Mid-ocean ridge basalt composition in ppm, as defined +#' by Sun & McDonough (1989)} +#' \item{EMORB}{Enhanced Mid-Ocean Ridge Basalt composition in ppm, as +#' defined by Sun & McDonough (1989)} +#' \item{OIB}{Ocean Island Basalt composition in ppm, as defined by Sun & +#' McDonough (1989)} +#' } +#' +#' @references Sun, S.-S. & McDonough, W.F. (1989). Chemical and isotopic +#' systematics of oceanic basalts. Geological Society, London, Special +#' Publications 42, pp.313-345. Table 1, page 318. +#' . +#' +#' @name references_geochem +"references_geochem" diff --git a/data-raw/geochem_reference_data.R b/data-raw/geochem_reference_data.R index 5a92b9c..b704d92 100644 --- a/data-raw/geochem_reference_data.R +++ b/data-raw/geochem_reference_data.R @@ -3,33 +3,81 @@ # Element groups # REE retrieved from https://en.wikipedia.org/wiki/Rare-earth_element, -# HFSE & LILE retrieved from https://en.wikipedia.org/wiki/Incompatible_element +# HFSE retrieved from https://link.springer.com/rwe/10.1007/1-4020-4496-8_101 +# LILE retrieved from https://link.springer.com/rwe/10.1007/1-4020-4496-8_104 standard_groups <- list( - REE = c("La", "Ce", "Pr", "Nd", "Sm", "Eu", "Gd", "Tb", "Dy", - "Ho", "Er", "Tm", "Yb", "Lu"), - HFSE = c("Nb", "Ta", "Zr", "Hf", "Ti", "Th", "U"), + REE = c( + "La", "Ce", "Pr", "Nd", "Sm", "Eu", "Gd", "Tb", "Dy", + "Ho", "Er", "Tm", "Yb", "Lu" + ), + HFSE = c("Nb", "Ta", "Zr", "Hf", "Ti"), LILE = c("Rb", "Ba", "K", "Sr", "Cs") ) # Geochemical reference compositions # units: ppm references_geochem <- list( - chondrite = c( - La = 0.237, Ce = 0.612, Pr = 0.095, Nd = 0.467, Sm = 0.153, - Eu = 0.058, Gd = 0.2055, Tb = 0.0374, Dy = 0.2540, Ho = 0.0566, - Er = 0.1655, Tm = 0.0255, Yb = 0.170, Lu = 0.0254 + chondrite = units::set_units( + value = "mg/kg", + x = c( + Cs = 0.188, TI = 0.14, Rb = 2.32, Ba = 2.41, W = 0.095, Th = 0.029, + U = 0.008, Nb = 0.246, Ta = 0.014, K = 545, La = 0.237, Ce = 0.612, + Pb = 2.47, Pr = 0.095, Mo = 0.92, Sr = 7.26, P = 1220, Nd = 0.467, + F = 60.7, Sm = 0.153, Zr = 3.87, Hf = 0.1066, Eu = 0.058, Sn = 1.72, + Sb = 0.16, Ti = 445, Gd = 0.2055, Tb = 0.0374, Dy = 0.254, Li = 1.57, + Y = 1.57, Ho = 0.0566, Er = 0.1655, Tm = 0.0255, Yb = 0.17, Lu = 0.0254 + ) ), - - MORB = c( - La = 2.50, Ce = 7.50, Pr = 1.32, Nd = 7.30, Sm = 2.63, - Eu = 1.02, Gd = 3.68, Tb = 0.67, Dy = 4.55, Ho = 1.01, - Er = 2.97, Tm = 0.456, Yb = 3.05, Lu = 0.455 + PM = units::set_units( + value = "mg/kg", + x = c( + Cs = 0.032, TI = 0.005, Rb = 0.635, Ba = 6.989, W = 0.02, Th = 0.085, + U = 0.021, Nb = 0.713, Ta = 0.041, K = 250, La = 0.687, Ce = 1.775, + Pb = 0.185, Pr = 0.276, Mo = 0.063, Sr = 21.1, P = 95, Nd = 1.354, F = 26, + Sm = 0.444, Zr = 11.2, Hf = 0.309, Eu = 0.168, Sn = 0.17, Sb = 0.005, + Ti = 1300, Gd = 0.596, Tb = 0.108, Dy = 0.737, Li = 1.6, Y = 4.55, + Ho = 0.164, Er = 0.48, Tm = 0.074, Yb = 0.493, Lu = 0.074 + ) + ), + NMORB = units::set_units( + value = "mg/kg", + x = c( + Cs = 0.007, TI = 0.0014, Rb = 0.56, Ba = 6.3, W = 0.01, Th = 0.12, + U = 0.047, Nb = 2.33, Ta = 0.132, K = 600, La = 2.5, Ce = 7.5, Pb = 0.3, + Pr = 1.32, Mo = 0.31, Sr = 90, P = 510, Nd = 7.3, F = 210, Sm = 2.63, + Zr = 74, Hf = 2.05, Eu = 1.02, Sn = 1.1, Sb = 0.01, Ti = 7600, Gd = 3.68, + Tb = 0.67, Dy = 4.55, Li = 4.3, Y = 28, Ho = 1.01, Er = 2.97, Tm = 0.456, + Yb = 3.05, Lu = 0.455 + ) + ), + EMORB = units::set_units( + value = "mg/kg", + x = c( + Cs = 0.063, TI = 0.013, Rb = 5.04, Ba = 57, W = 0.092, Th = 0.6, U = 0.18, + Nb = 8.3, Ta = 0.47, K = 2100, La = 6.3, Ce = 15, Pb = 0.6, Pr = 2.05, + Mo = 0.47, Sr = 155, P = 620, Nd = 9, F = 250, Sm = 2.6, Zr = 73, + Hf = 2.03, Eu = 0.91, Sn = 0.8, Sb = 0.01, Ti = 6000, Gd = 2.97, Tb = 0.53, + Dy = 3.55, Li = 3.5, Y = 22, Ho = 0.79, Er = 2.31, Tm = 0.356, Yb = 2.37, + Lu = 0.354 + ) + ), + OIB = units::set_units( + value = "mg/kg", + x = c( + Cs = 0.387, TI = 0.077, Rb = 31, Ba = 350, W = 0.56, Th = 4, U = 1.02, + Nb = 48, Ta = 2.7, K = 12000, La = 37, Ce = 80, Pb = 3.2, Pr = 9.7, + Mo = 2.4, Sr = 660, P = 2700, Nd = 38.5, F = 1150, Sm = 10, Zr = 280, + Hf = 7.8, Eu = 3, Sn = 2.7, Sb = 0.03, Ti = 17200, Gd = 7.62, Tb = 1.05, + Dy = 5.6, Li = 5.6, Y = 29, Ho = 1.06, Er = 2.62, Tm = 0.35, Yb = 2.16, + Lu = 0.3 + ) ) ) # Save as internal data usethis::use_data(standard_groups, - references_geochem, - internal = FALSE, - overwrite = TRUE) + references_geochem, + internal = FALSE, + overwrite = TRUE +) diff --git a/data/references_geochem.rda b/data/references_geochem.rda index 2c9d2c7ecd825633af1615f36e1aac1435c8edb4..6c7061ed09c400767cb8c6be1f62f27e4bda5e6b 100644 GIT binary patch literal 1392 zcmV-$1&{hdT4*^jL0KkKS=Wv8zW@eDfB*mgegEHMtN;K1|MdU=|2_Ubue4FCYp00000000000000000000 z003n_Nu^TajB&z*5F)PO z1=AJ#+*FXj82c3V66P4mG9H>Ch)GohnyJr#zS`iZe_k$4n&HQrRz3vSrgql1oI)37!)& zbCLr!c$JcYyHUJ>OZ60BMcv-yk|0VDWVzB|LO{HnAt94{D2O45BuJ4cl%i6Ilu3v{ z6H{CyC8Pr)A_5^%Tt-BYvx3TrDF<4aQY9HIO#oQae4fpX6#!da*(H-|m`w>rrX;Il z+VQ63>uXe(bn1;^2*~<5+O|26X)wZz$P9;B{r@>qn3TXrC`Pxck#rHJA~(Ffsp2&* zq73=FBZ@0PIr9<$yPyEQ*vwuSOrr~!i)svY3}2i~uACr~xF7|az7M`5`po0TW_r?5DJ4bX9`*j8ahgq$0hv-m5}ZgX&1!e@vR za%Uvw;7^&gPY-39YmE&%%>r14kt-*a^;b>=rCR+rld771`*>W}n3nw+?Y`}*Ql;8q zWki9h46)eONx&wFlp1;kYD;g&vn%9MlG`(w6H1d}(~?XPdhbm)Sp7|;h=} zZlg?VvGRQa(KTtS%xy_A7C3&Aq zxd{qq&j$G|h(?HnWHS(uucBQ@gbHLv2miViYmeej045MnssE(HQm0eC^IYn7kOxE5 ziz!-LKu^G~JcOH!rRvsOkb@ZnC=u9?((!Mtc*zD&g?WD!N8HCT2qjK&3M5f}v`TM? zi((!)s)`{13VhDmoa=OTu2LM$&!`GYYKGknaLu6x6@e*ID-nZ25%qwFV<2Qb)oTj` z&2QKeHZR~G7JiSo%uRHaa*?h{&)8W7kzs@iB7y3w?CKA%h!tFCzW}^@i4GeH*+>@Z znB0(r(?cKuT>()b7(TKP3F4dz^*Z>CSNVEQzxWqZ%rxX z5NU~k0000000000001KhzyJUMltncjqaz>#KmY&$0017NKmY&$000dfmyBzKC@mlY zB!aOgP@+Mw8VG2r$tz>9>&)`Xw4qP#8AbO- zoBt(#?I%K1J9Ex~ou@A58lIl(-FGBR>RP$B7*M&VO=XHSo7OEs(1HDAdckNaFFL|H z22B-`5bec4{A;j#p<$olZEqq0*r?Km?Fpjd@JuC)lsOr+Z-0Tc@S&jF2B0=sA4{fL z^oy^PN@|-r&vQ}`a((Fpz@lLekA&xx+)TOSf>2k6Wh!peXniOKRX51|)MhHRPd+TD ln==)w*us#K(5mB~;9*rND@Vsw(Da}2cO+AV2@S?7jUZJqza;GD(s?N7Tq!;L0Omr zL>H-*jrO>{-7;r=O;>0&a$k-dqhQ7yf!aYRkb)o>phylu$dYN|!0+n*PBX7j_V Date: Mon, 25 May 2026 20:13:37 -0400 Subject: [PATCH 13/14] implement handling of ASTR objects, incl. correct conversion of objects with units --- R/ASTR_normalise_geochem.R | 108 ++++++++++++++++++++++++ R/normalise_geochem.R | 58 ------------- man/normalise_geochem.Rd | 24 +++--- tests/testthat/test_normalise_geochem.R | 46 ++++++---- 4 files changed, 148 insertions(+), 88 deletions(-) create mode 100644 R/ASTR_normalise_geochem.R delete mode 100644 R/normalise_geochem.R diff --git a/R/ASTR_normalise_geochem.R b/R/ASTR_normalise_geochem.R new file mode 100644 index 0000000..f61bc6e --- /dev/null +++ b/R/ASTR_normalise_geochem.R @@ -0,0 +1,108 @@ +#' Geochemical normalisation of data +#' +#' Normalises selected elemental concentrations to a reference composition such +#' as chondrite or MORB. +#' +#' See [references_geochem] for the supported reference compositions. +#' Normalisation to other reference compositions is possible by adding them as +#' named vectors, see examples. They will not be stored permanently in the +#' package and must be exported and reloaded (or their definition included in +#' the script). If you would like to include a new reference composition in +#' ASTR, please reach out to the package maintainers or create a pull request in +#' the [package's GitHub repo](https://github.com/archaeothommy/ASTR) with the +#' values to be included and a literature reference. +#' +#' The function converts all elements in the dataframe for which a reference +#' composition is available. For [ASTR objects][ASTR], unit conversion is +#' handled by the function. For all other objects, the user must ensure that +#' values and reference composition have the same unit. +#' +#' @param df A data frame in wide format. +#' @param reference Character string with the normalisation. See Details for +#' further information. +#' +#' @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 +#' compositional data that was normalised, and the normalised values of the +#' respective elements. In all other cases, the data frame provided as input +#' with columns added for the calculated age model parameters. +#' +#' The used reference composition is indicated in the column names of the +#' output by the value of `reference`. +#' +#' @examples +#' df <- data.frame( +#' Sample = c("A","B"), +#' La = c(10,5), +#' Ce = c(20,8) +#' ) +#' +#' normalise_geochem( +#' df, +#' elements = c("La","Ce"), +#' reference = "chondrite" +#' ) +#' +#' For ASTR objects, units and oxides are automatically converted +#' test_file <- system.file("extdata", "test_data_input_good.csv", package = "ASTR") +#' arch <- read_ASTR(test_file, id_column = "Sample", context = 1:7) +#' +#' arch_norm <- normalise_geochem(arch, "chondrite") +#' +#' # adding reference composition for 31X 7835.8A of the CHARM Set +#' references_geochem$"31X 7835.8A" <- units::set_units( +#' value = "%", +#' x = c(P = 0.122, Mn = 0.093, Fe = 0.1, Co = 0.313, Ni = 0.158, Cu = 69.93, +#' Zn = 24.83, As = 0.143, Ag = 0.463, Cd = 0.087, Sn = 0.516, Sb = 0.115, +#' Pb = 3.15, Bi = 0.112 +#' ) +#' ) +#' +#' references_geochem$"31X 7835.8A" +#' +#' @export +#' +normalise_geochem <- function(df, reference = names(references_geochem)) { + + reference <- match.arg(reference) + + # Basic checks + checkmate::assert_data_frame(df) + + elements <- intersect(colnames(df), names(references_geochem[[reference]])) + + if (length(elements) == 0) { + stop("Dataset does not include any element of the reference data.") + } + + # Normalisation + df_norm <- as.data.frame( + mapply(function(x) { + t(t(df[[x]]) / references_geochem[[reference]][x]) + }, + elements + ) + ) + + # rename column names + colnames(df_norm) <- paste0(elements, "_", reference) + + if (inherits(df, "ASTR")) { + df_norm <- cbind(df["ID"], df_norm) + + df_norm <- suppressWarnings( + as_ASTR( + df_norm, + context = colnames(df_norm)[-1] + ) + ) + + df_norm <- cbind(get_contextual_columns(df), df[elements], df_norm[-1]) + df_norm <- preserve_ASTR_attrs(df_norm, df) + + } else { + df_norm <- cbind(df, df_norm) + } + + return(df_norm) +} diff --git a/R/normalise_geochem.R b/R/normalise_geochem.R deleted file mode 100644 index 45156d4..0000000 --- a/R/normalise_geochem.R +++ /dev/null @@ -1,58 +0,0 @@ -#' Geochemical normalisation of data -#' -#' Normalises selected elemental concentrations to a reference composition such -#' as chondrite or MORB. -#' -#' See [references_geochem] for supported geochemical reference compositions and -#' which elements are covered by which reference composition. The function -#' converts all elements in the dataframe for which a reference composition is -#' available. A warning informs if not all elements in the reference composition -#' are included in the data frame, and an error if none is included. -#' -#' @param df A data frame in wide format. -#' @param reference Character string with the normalisation. See Details for -#' further information. -#' -#' @return The data frame with the selected elements normalised. -#' -#' @references Sun, S.-s. & McDonough, W.F. (1989). Chemical and isotopic -#' systematics of oceanic basalts. Geological Society, London, Special -#' Publications 42, 313-345. Table 1, page 318. -#' -#' @examples -#' df <- data.frame( -#' Sample = c("A","B"), -#' La = c(10,5), -#' Ce = c(20,8) -#' ) -#' -#' normalise_spider( -#' df, -#' elements = c("La","Ce"), -#' reference = "chondrite" -#' ) -#' -#' @export -normalise_geochem <- function(df, reference = names(references_geochem)) { - - reference <- match.arg(reference) - - # Basic checks - checkmate::assert_data_frame(df) - - elements <- intersect(colnames(df), names(references_geochem[[reference]])) - - if (length(elements) < length(references_geochem[[reference]])) { - if (length(elements) == 0) { - stop("Dataset does not include any element of the reference data.") - } else { - warning("Dataset does not include all elements of the reference data.") - } - } - - print(references_geochem[[reference]][elements]) - # Normalisation - df[elements] <- t(t(df[elements]) / references_geochem[[reference]][elements]) - - return(df) -} diff --git a/man/normalise_geochem.Rd b/man/normalise_geochem.Rd index 0a50673..5a6fa55 100644 --- a/man/normalise_geochem.Rd +++ b/man/normalise_geochem.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/normalise_geochem.R +% Please edit documentation in R/ASTR_normalise_geochem.R \name{normalise_geochem} \alias{normalise_geochem} \title{Geochemical normalisation of data} @@ -20,11 +20,16 @@ Normalises selected elemental concentrations to a reference composition such as chondrite or MORB. } \details{ -See \link{references_geochem} for supported geochemical reference compositions and -which elements are covered by which reference composition. The function -converts all elements in the dataframe for which a reference composition is -available. A warning informs if not all elements in the reference composition -are included in the data frame, and an error if none is included. +See \link{references_geochem} for the supported reference compositions. Additional +reference compositions can be added as named vectors, see examples. They +won't be stored permanently in the package. If you would like to include a +new reference composition, , 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. + +The function converts all elements in the dataframe for which a reference +composition is available. A warning informs if not all elements in the +reference composition are included in the data frame, and an error if none is +included. } \examples{ df <- data.frame( @@ -33,15 +38,10 @@ df <- data.frame( Ce = c(20,8) ) -normalise_spider( +normalise_geochem( df, elements = c("La","Ce"), reference = "chondrite" ) } -\references{ -Sun, S.-s. & McDonough, W.F. (1989). Chemical and isotopic -systematics of oceanic basalts. Geological Society, London, Special -Publications 42, 313-345. Table 1, page 318. -} diff --git a/tests/testthat/test_normalise_geochem.R b/tests/testthat/test_normalise_geochem.R index 2e9ff0f..a6cc7d1 100644 --- a/tests/testthat/test_normalise_geochem.R +++ b/tests/testthat/test_normalise_geochem.R @@ -1,5 +1,3 @@ -# tests/testthat/test-normalise_geochem.R - test_that("normalise_geochem handles all cases", { df <- data.frame( @@ -11,16 +9,12 @@ test_that("normalise_geochem handles all cases", { ) # Run normalisation using internal reference data - result <- suppressWarnings( - normalise_geochem(df, reference = "chondrite") - ) + result <- normalise_geochem(df, reference = "chondrite") # Check normalization math (using real reference values) - ref <- references_geochem$chondrite - - expect_equal(result$La, df$La / ref["La"]) - expect_equal(result$Ce, df$Ce / ref["Ce"]) - expect_equal(result$Nd, df$Nd / ref["Nd"]) + expect_equal(result$La_chondrite, units::drop_units(df$La / references_geochem$chondrite["La"])) + expect_equal(result$Ce_chondrite, units::drop_units(df$Ce / references_geochem$chondrite["Ce"])) + expect_equal(result$Nd_chondrite, units::drop_units(df$Nd / references_geochem$chondrite["Nd"])) # Check non-element columns unchanged expect_equal(result$X, df$X) @@ -30,13 +24,6 @@ test_that("normalise_geochem handles all cases", { expect_true(is.na(result$La[2])) expect_true(is.na(result$Ce[3])) - # Warning when some elements missing - df_partial <- df[, c("Sample", "La")] - expect_warning( - normalise_geochem(df_partial, reference = "chondrite"), - regexp = "does not include all elements" - ) - # Error when no matching elements df_none <- data.frame(Sample = c("A", "B"), X = c(1, 2)) expect_error( @@ -47,5 +34,28 @@ test_that("normalise_geochem handles all cases", { # Structure checks expect_s3_class(result, "data.frame") expect_equal(nrow(result), nrow(df)) - expect_equal(names(result), names(df)) + expect_equal(names(result), c(names(df), "La_chondrite", "Ce_chondrite", "Nd_chondrite")) }) + +test_that("ASTR objects handled as intended", { + + suppressWarnings( + test_input <- read_ASTR( + system.file("extdata", "test_data_input_good.csv", package = "ASTR"), + id_column = "Sample", + context = 1:7 + ) + ) + + normalised <- normalise_geochem(test_input, "chondrite") + + expect_true("ASTR" %in% class(normalised)) + expect_equal(get_contextual_columns(normalised[1:8]), get_contextual_columns(test_input)) + expect_equal( + attributes(normalised[["Sb_chondrite"]]), + attributes(test_input[["Sample"]]) + ) + +}) + + From 6ef33053fbf3920470f865fdad23a2dae9b241f3 Mon Sep 17 00:00:00 2001 From: Thomas Rose Date: Mon, 25 May 2026 20:25:19 -0400 Subject: [PATCH 14/14] fixed from package checks [skip ci] --- R/ASTR_normalise_geochem.R | 4 ++-- _pkgdown.yml | 3 +++ man/normalise_geochem.Rd | 49 +++++++++++++++++++++++++++++--------- man/references_geochem.Rd | 7 +++--- 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/R/ASTR_normalise_geochem.R b/R/ASTR_normalise_geochem.R index f61bc6e..32b04c6 100644 --- a/R/ASTR_normalise_geochem.R +++ b/R/ASTR_normalise_geochem.R @@ -12,7 +12,7 @@ #' the [package's GitHub repo](https://github.com/archaeothommy/ASTR) with the #' values to be included and a literature reference. #' -#' The function converts all elements in the dataframe for which a reference +#' The function converts all elements in the data frame for which a reference #' composition is available. For [ASTR objects][ASTR], unit conversion is #' handled by the function. For all other objects, the user must ensure that #' values and reference composition have the same unit. @@ -43,7 +43,7 @@ #' reference = "chondrite" #' ) #' -#' For ASTR objects, units and oxides are automatically converted +#' # For ASTR objects, units are automatically converted #' test_file <- system.file("extdata", "test_data_input_good.csv", package = "ASTR") #' arch <- read_ASTR(test_file, id_column = "Sample", context = 1:7) #' diff --git a/_pkgdown.yml b/_pkgdown.yml index f99197d..ce20679 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -31,6 +31,8 @@ reference: - elements_data - oxides_data - special_oxide_states + - standard_groups + - references_geochem - title: Unit conversions desc: > Functions and data tables for conversions between untis not covered in @@ -43,6 +45,7 @@ reference: desc: > Functions for data transformation contents: + - normalise_geochem - copper_alloy_bb - copper_alloy_pollard - copper_group_bray diff --git a/man/normalise_geochem.Rd b/man/normalise_geochem.Rd index 5a6fa55..de37bc4 100644 --- a/man/normalise_geochem.Rd +++ b/man/normalise_geochem.Rd @@ -13,23 +13,33 @@ normalise_geochem(df, reference = names(references_geochem)) further information.} } \value{ -The data frame with the selected elements normalised. +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 +compositional data that was normalised, and the normalised values of the +respective elements. In all other cases, the data frame provided as input +with columns added for the calculated age model parameters. + +The used reference composition is indicated in the column names of the +output by the value of \code{reference}. } \description{ Normalises selected elemental concentrations to a reference composition such as chondrite or MORB. } \details{ -See \link{references_geochem} for the supported reference compositions. Additional -reference compositions can be added as named vectors, see examples. They -won't be stored permanently in the package. If you would like to include a -new reference composition, , 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. - -The function converts all elements in the dataframe for which a reference -composition is available. A warning informs if not all elements in the -reference composition are included in the data frame, and an error if none is -included. +See \link{references_geochem} for the supported reference compositions. +Normalisation to other reference compositions is possible by adding them as +named vectors, see examples. They will not be stored permanently in the +package and must be exported and reloaded (or their definition included in +the script). If you would like to include a new reference composition in +ASTR, please reach out to the package maintainers or create a pull request in +the \href{https://github.com/archaeothommy/ASTR}{package's GitHub repo} with the +values to be included and a literature reference. + +The function converts all elements in the data frame for which a reference +composition is available. For \link[=ASTR]{ASTR objects}, unit conversion is +handled by the function. For all other objects, the user must ensure that +values and reference composition have the same unit. } \examples{ df <- data.frame( @@ -44,4 +54,21 @@ normalise_geochem( reference = "chondrite" ) +# For ASTR objects, units are automatically converted +test_file <- system.file("extdata", "test_data_input_good.csv", package = "ASTR") +arch <- read_ASTR(test_file, id_column = "Sample", context = 1:7) + +arch_norm <- normalise_geochem(arch, "chondrite") + +# adding reference composition for 31X 7835.8A of the CHARM Set +references_geochem$"31X 7835.8A" <- units::set_units( + value = "\%", + x = c(P = 0.122, Mn = 0.093, Fe = 0.1, Co = 0.313, Ni = 0.158, Cu = 69.93, + Zn = 24.83, As = 0.143, Ag = 0.463, Cd = 0.087, Sn = 0.516, Sb = 0.115, + Pb = 3.15, Bi = 0.112 + ) +) + +references_geochem$"31X 7835.8A" + } diff --git a/man/references_geochem.Rd b/man/references_geochem.Rd index 373c025..79c6c44 100644 --- a/man/references_geochem.Rd +++ b/man/references_geochem.Rd @@ -6,9 +6,10 @@ \title{Reference compositions} \format{ A list including sets of chemical compositions often used as -reference composition for e.g. normalisation. Values are stored as names -vectors. To retrieve the list of elements and their concentrations for -e.g. the PM, run \code{references_geochem$PM}. +reference composition for e.g. normalisation. Values are stored as named +vectors of their concentration with assigned units (using +\link[units]{set_units}). To retrieve the list of elements and their +concentrations for e.g. the PM, run \code{references_geochem$PM}. \describe{ \item{chondrite}{CI chondrite composition in ppm, as defined by Sun & McDonough (1989)}