diff options
author | Anil Tellbuescher <anil@tellbuescher.online> | 2024-11-16 13:34:09 +0100 |
---|---|---|
committer | Anil Tellbuescher <anil@tellbuescher.online> | 2024-11-16 13:34:09 +0100 |
commit | 818de681ddacdf3be06fd292f965a3cca858118e (patch) | |
tree | fe4bd85e7f7904d86cb80948f8279b365b5a2477 | |
parent | d202b127909669c484bc74bb87d629f9e3bea299 (diff) |
add linearity tests for calibration data
-rw-r--r-- | R/linearity.R | 113 |
1 files changed, 113 insertions, 0 deletions
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 +} |