From 818de681ddacdf3be06fd292f965a3cca858118e Mon Sep 17 00:00:00 2001 From: Anil Tellbuescher Date: Sat, 16 Nov 2024 13:34:09 +0100 Subject: add linearity tests for calibration data --- R/linearity.R | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 R/linearity.R (limited to 'R') diff --git a/R/linearity.R b/R/linearity.R new file mode 100644 index 0000000..6230d04 --- /dev/null +++ b/R/linearity.R @@ -0,0 +1,113 @@ +#' Assess the linearity of a calibration curve +#' +#' A function to create diagnostic plots for the assessment of the linearity of +#' calibration data based on their point-to-point slope or the curvature. +#' The underlying methods follow ISO 84 66-1:2021 and DIN 32 402-51:2017 +#' (German Industrial Norm). +#' +#' The point-to-point slope method is based on the assumption that the slope +#' between two points should not vary greatly within the linear range. +#' +#' The curvature method is similar to the point-to-point slope method. Here, +#' the ratio between the instrument signal and the concentration of the +#' calibration standard is assumed not to vary greatly within the linear range. +#' +#' The use of the Mandel test is discouraged due to its limitations in the +#' identification of non-linear behaviour of calibration courves (Andrade and +#' Gomes-Carracedo, 2013). +#' +#' @param x numeric vector of independent values (usually concentrations). +#' @param y numeric vector of dependent values (usually the signal of the +#' analytical device). +#' @param method character string. Supported methods are "slope" and +#' "curvature". +#' @param tolerance numeric value describing the acceptable deviation from the +#' median of the slopes or the signal-to-concentration ratio. The default +#' tolerance is 10%. +#' @return returns a diagnostic plot +#' +#' @author Anil Axel Tellbüscher +#' +#' @importFrom graphics abline +#' @importFrom stats median +#' +#' @examples +#' # Point-to-point slope plot +#' linearity(din32645$x, din32645$y, method = "slope") +#' +#' # Curvature plot +#' linearity(din32645$x, din32645$y, method = "curvature", tolerance = 0.2) +#' +#' @references ISO 8466-1:2021. Water quality — Calibration and evaluation of +#' analytical methods — Part 1: Linear calibration function +#' +#' J. M. Andrade and M. P. Gomez-Carracedo (2013) Notes on the use of +#' Mandel's test to check for nonlinearity in laboratory calibrations. +#' Analytical Methods 5(5), 1145 - 1149. +#' +#' @export +# Function to assess linearity of data using either slope or curvature method +linearity <- function(x, y, method = NULL, tolerance = 0.1) { + + # Check data integrity + # Ensure that x and y vectors have the same length + stopifnot("x and y must have the same length!" = length(x) == length(y)) + + # Ensure that a method has been specified + stopifnot("Method must be defined!\n + Select either 'slope' for the point-to-point slope or 'curvature' + for the empirical curvature test" = + !is.null(method)) + + # Validate that the method is either 'slope' or 'curvature' + stopifnot("Invalid input!\n + Select either 'slope' for the point-to-point slope or 'curvature' + for the empirical curvature test" = + method %in% c("slope", "curvature")) + + # Calculate the 'result' based on the chosen method + if (method == "slope") { + # For the 'slope' method, calculate the difference between consecutive points + x_diff = diff(x) # Difference in x values + y_diff = diff(y) # Difference in y values + result = y_diff / x_diff # Point-to-point slope (rate of change) + } else if (method == "curvature") { + # For the 'curvature' method, calculate the signal-to-concentration ratio + result = y / x # Element-wise division of y by x + } + + # Calculate the median of the results for tolerance check + result_median <- median(result) + + # Define upper and lower tolerance boundaries + upper_tolerance <- result_median + tolerance * result_median + lower_tolerance <- result_median - tolerance * result_median + + # Create a data frame to store the result and corresponding indices + df <- data.frame(result = result, index = 1:length(result)) + + # Identify points that fall outside the tolerance range + outside_tolerance <- rbind( + subset(df, result > upper_tolerance), # Points above the upper tolerance + subset(df, result < lower_tolerance) # Points below the lower tolerance + ) + + # Basic scatter plot of the result against the index + plot(result ~ index, data = df, + main = "linearity assessment", ylab = method, + pch = 16) + + # Draw a line connecting all the points to visualize the trend + lines(df$index, df$result, col = "blue") # Blue line connecting points + + # Highlight points that are outside the tolerance range in red + points(x = outside_tolerance$index, y = outside_tolerance$result, + pch = 16, col = "red") + + # Add a horizontal line at the median value of the result + abline(h = result_median, col = "red") + + # Add dashed horizontal lines at the upper and lower tolerance limits + abline(h = upper_tolerance, col = "red", lty = 3) # Upper tolerance + abline(h = lower_tolerance, col = "red", lty = 3) # Lower tolerance +} -- cgit v1.2.1 From 1dc4318a30b34ebbf21472d29dbe341f22bc3ea2 Mon Sep 17 00:00:00 2001 From: Johannes Ranke Date: Sun, 17 Nov 2024 14:57:04 +0100 Subject: Use match.arg for checking method argument --- R/linearity.R | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'R') diff --git a/R/linearity.R b/R/linearity.R index 6230d04..759b288 100644 --- a/R/linearity.R +++ b/R/linearity.R @@ -13,7 +13,7 @@ #' calibration standard is assumed not to vary greatly within the linear range. #' #' The use of the Mandel test is discouraged due to its limitations in the -#' identification of non-linear behaviour of calibration courves (Andrade and +#' identification of non-linear behaviour of calibration curves (Andrade and #' Gomes-Carracedo, 2013). #' #' @param x numeric vector of independent values (usually concentrations). @@ -21,9 +21,9 @@ #' analytical device). #' @param method character string. Supported methods are "slope" and #' "curvature". -#' @param tolerance numeric value describing the acceptable deviation from the -#' median of the slopes or the signal-to-concentration ratio. The default -#' tolerance is 10%. +#' @param tolerance numeric value between 0 and 1, describing the acceptable +#' deviation from the median of the slopes or the signal-to-concentration +#' ratio. The default tolerance is 10%. #' @return returns a diagnostic plot #' #' @author Anil Axel Tellbüscher @@ -32,6 +32,7 @@ #' @importFrom stats median #' #' @examples +#' data(din32645) #' # Point-to-point slope plot #' linearity(din32645$x, din32645$y, method = "slope") #' @@ -47,23 +48,13 @@ #' #' @export # Function to assess linearity of data using either slope or curvature method -linearity <- function(x, y, method = NULL, tolerance = 0.1) { +linearity <- function(x, y, method = c("slope", "curvature"), tolerance = 0.1) { # Check data integrity # Ensure that x and y vectors have the same length stopifnot("x and y must have the same length!" = length(x) == length(y)) - # Ensure that a method has been specified - stopifnot("Method must be defined!\n - Select either 'slope' for the point-to-point slope or 'curvature' - for the empirical curvature test" = - !is.null(method)) - - # Validate that the method is either 'slope' or 'curvature' - stopifnot("Invalid input!\n - Select either 'slope' for the point-to-point slope or 'curvature' - for the empirical curvature test" = - method %in% c("slope", "curvature")) + method <- match.arg(method) # Calculate the 'result' based on the chosen method if (method == "slope") { -- cgit v1.2.1 From a2cc5039c5c4df712d2a80d0c5e87acb4b243616 Mon Sep 17 00:00:00 2001 From: Anil Tellbuescher Date: Sat, 11 Jan 2025 13:38:07 +0100 Subject: import graphics::lines --- R/linearity.R | 1 + 1 file changed, 1 insertion(+) (limited to 'R') diff --git a/R/linearity.R b/R/linearity.R index 759b288..8970fe7 100644 --- a/R/linearity.R +++ b/R/linearity.R @@ -29,6 +29,7 @@ #' @author Anil Axel Tellbüscher #' #' @importFrom graphics abline +#' @importFrom graphics lines #' @importFrom stats median #' #' @examples -- cgit v1.2.1 From 0e44aa36a796c7f2952000f2df7d02bb249f4e9c Mon Sep 17 00:00:00 2001 From: Anil Tellbuescher Date: Sat, 11 Jan 2025 13:40:33 +0100 Subject: add example calibration data from DIN 38402 --- R/chemCal-package.R | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'R') diff --git a/R/chemCal-package.R b/R/chemCal-package.R index 8cc8c76..08c2ebc 100644 --- a/R/chemCal-package.R +++ b/R/chemCal-package.R @@ -192,3 +192,77 @@ NULL + + +#' Nitrite calibration data +#' +#' Example dataset B.1 from DIN 38402 with concentrations in µg/L and the extinction +#' as response measured using continuous flow analysis (CFA) according to +#' ISO 13395. +#' +#' @name din38402b1 +#' @docType data +#' @format A tibble containing 12 concentration levels with the respective +#' instrument response values. +#' @references DIN 38402-51:2017-05, Beuth Verlag, Berlin. +#' https://dx.doi.org/10.31030/2657448 +#' @keywords datasets +NULL + + + + + +#' Copper calibration data +#' +#' Example dataset B.3 from DIN 38402. Cu was measured according to ISO 11885, +#' using ICP-OES. The concentration are reported in mg/L and the response as +#' counts/s, describing the count of photons that are detected by the +#' photomultiplier detector of the device. +#' +#' @name din38402b3 +#' @docType data +#' @format A tibble containing 13 concentration levels and the respective +#' instrument response values. +#' @references DIN 38402-51:2017-05, Beuth Verlag, Berlin. +#' https://dx.doi.org/10.31030/2657448 +#' @keywords datasets +NULL + + + + + +#' Carbamazepin calibration data +#' +#' Example dataset B.6 from DIN 38402 measured using LC-MS/MS. The +#' concentrations are reported in in µg/L and the response in arbitrary +#' units (AU). +#' +#' @name din38402b6 +#' @docType data +#' @format A tibble containing 12 concentration levels and the respective +#' instrument response values. +#' @references DIN 38402-51:2017-05, Beuth Verlag, Berlin. +#' https://dx.doi.org/10.31030/2657448 +#' @keywords datasets +NULL + + + + + +#' Iron calibration data +#' +#' Example dataset C.3 from DIN 38402 determined by ion chromatography. +#' Concentrations are reported in mg/L and the extinction as response. +#' +#' @name din38402c3 +#' @docType data +#' @format A tibble containing 10 concentration levels and the respective +#' response values. +#' @references DIN 38402-51:2017-05, Beuth Verlag, Berlin. +#' https://dx.doi.org/10.31030/2657448 +#' @keywords datasets +NULL + -- cgit v1.2.1 From cfcd58348dc8cbf7010231bfe902867bb30a8b3f Mon Sep 17 00:00:00 2001 From: Anil Tellbuescher Date: Sat, 11 Jan 2025 13:56:17 +0100 Subject: replace din32645 data by data from din38402b1 --- R/linearity.R | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'R') diff --git a/R/linearity.R b/R/linearity.R index 8970fe7..8a4f09b 100644 --- a/R/linearity.R +++ b/R/linearity.R @@ -26,19 +26,21 @@ #' ratio. The default tolerance is 10%. #' @return returns a diagnostic plot #' -#' @author Anil Axel Tellbüscher +#' @author Anıl Axel Tellbüscher #' #' @importFrom graphics abline #' @importFrom graphics lines #' @importFrom stats median #' #' @examples -#' data(din32645) +#' # Continuous Flow Analysis (CFA) data +#' data(din38402b1) +#' #' # Point-to-point slope plot -#' linearity(din32645$x, din32645$y, method = "slope") +#' linearity(din38402b1$conc, din38402b1$ext, method = "slope") #' #' # Curvature plot -#' linearity(din32645$x, din32645$y, method = "curvature", tolerance = 0.2) +#' linearity(din38402b1$conc, din38402b1$ext, method = "curvature") #' #' @references ISO 8466-1:2021. Water quality — Calibration and evaluation of #' analytical methods — Part 1: Linear calibration function -- cgit v1.2.1 From c7b841c93dc2f3228dfe65ebd3bdd7a7f546fb96 Mon Sep 17 00:00:00 2001 From: Johannes Ranke Date: Wed, 22 Jan 2025 17:14:04 +0100 Subject: Satisfy R CMD check - Depend on R >= 3.5.0, because the format used for the data is not known to earlier R versions - Rename the datasets from `test` to their proper name --- R/chemCal-package.R | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'R') diff --git a/R/chemCal-package.R b/R/chemCal-package.R index 08c2ebc..54ab190 100644 --- a/R/chemCal-package.R +++ b/R/chemCal-package.R @@ -54,7 +54,7 @@ #' # LQ = 3.04 * LC (Currie 1999, p. 120) #' 3.04 * lod(m, alpha = 0.01, beta = 0.5)$x #' -NULL +"din32645" @@ -72,7 +72,7 @@ NULL #' Lewi, P.J., Smeyers-Verbeke, J. (1997) Handbook of Chemometrics and #' Qualimetrics: Part A, Chapter 8. #' @keywords datasets -NULL +"massart97ex1" @@ -128,7 +128,7 @@ NULL #' # of 15, but the graphical procedure of Massart (p. 201) to derive the #' # variances on which the weights are based is quite inaccurate anyway. #' -NULL +"massart97ex3" @@ -147,7 +147,7 @@ NULL #' @source Rocke, David M. und Lorenzato, Stefan (1995) A two-component model #' for measurement error in analytical chemistry. Technometrics 37(2), 176-184. #' @keywords datasets -NULL +"rl95_cadmium" @@ -167,7 +167,7 @@ NULL #' @source Rocke, David M. und Lorenzato, Stefan (1995) A two-component model #' for measurement error in analytical chemistry. Technometrics 37(2), 176-184. #' @keywords datasets -NULL +"rl95_toluene" @@ -188,7 +188,7 @@ NULL #' Toronto. #' \url{https://sites.chem.utoronto.ca/chemistry/coursenotes/analsci/stats/index.html} #' @keywords datasets -NULL +"utstats14" @@ -207,7 +207,7 @@ NULL #' @references DIN 38402-51:2017-05, Beuth Verlag, Berlin. #' https://dx.doi.org/10.31030/2657448 #' @keywords datasets -NULL +"din38402b1" @@ -227,7 +227,7 @@ NULL #' @references DIN 38402-51:2017-05, Beuth Verlag, Berlin. #' https://dx.doi.org/10.31030/2657448 #' @keywords datasets -NULL +"din38402b3" @@ -246,7 +246,7 @@ NULL #' @references DIN 38402-51:2017-05, Beuth Verlag, Berlin. #' https://dx.doi.org/10.31030/2657448 #' @keywords datasets -NULL +"din38402b6" @@ -264,5 +264,5 @@ NULL #' @references DIN 38402-51:2017-05, Beuth Verlag, Berlin. #' https://dx.doi.org/10.31030/2657448 #' @keywords datasets -NULL +"din38402c3" -- cgit v1.2.1