From 000b1781d6c85d41a95cabdce4e79ebd52458179 Mon Sep 17 00:00:00 2001 From: Mia Pras-Raves Date: Fri, 3 Oct 2025 16:39:18 +0200 Subject: [PATCH 01/10] added extra output on QC of SST sample to DIMS/GenerateQCOutput --- DIMS/GenerateQCOutput.R | 7 +++++++ DIMS/GenerateQCOutput.nf | 1 + 2 files changed, 8 insertions(+) diff --git a/DIMS/GenerateQCOutput.R b/DIMS/GenerateQCOutput.R index 4e3394d0..af63962f 100644 --- a/DIMS/GenerateQCOutput.R +++ b/DIMS/GenerateQCOutput.R @@ -356,6 +356,13 @@ xlsx_name <- paste0(outdir, "/", project, "_IS_SST.xlsx") openxlsx::saveWorkbook(wb, xlsx_name, overwrite = TRUE) rm(wb) +# generate text file for workflow completed mail for components with Z-score < 2 +if (grepl("Zscore", colnames(sst_list_intensities))) { + zscore_column <- grep("_Zscore", colnames(sst_list_intensities) + sst_list_intensities_qc <- sst_list_intensities[sst_list_intensities[, zscore_column] < 2, ] + write.table(sst_list_intensities_qc, file = paste(outdir, "sst_qc.txt", sep = "/")) +} + ### MISSING M/Z CHECK # check the outlist_identified_(negative/positive).RData files for missing m/z values and save to file diff --git a/DIMS/GenerateQCOutput.nf b/DIMS/GenerateQCOutput.nf index eb17301f..bee440a5 100644 --- a/DIMS/GenerateQCOutput.nf +++ b/DIMS/GenerateQCOutput.nf @@ -17,6 +17,7 @@ process GenerateQCOutput { tuple path('*_IS_SST.xlsx'), path('*_positive_control.xlsx'), optional: true path('plots/IS_*.png'), emit: plot_files path('Check_number_of_controls.txt'), optional: true + path('sst_qc.txt'), optional: true script: """ From 17b6d50f2d1c0929eaaea6badd310cdf5a53a0c7 Mon Sep 17 00:00:00 2001 From: Mia Pras-Raves Date: Mon, 15 Dec 2025 13:44:34 +0100 Subject: [PATCH 02/10] added output for QC on internal standards to include in mail --- DIMS/GenerateQCOutput.R | 90 +++++++++++++++++++++++++++++++++------- DIMS/GenerateQCOutput.nf | 1 + 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/DIMS/GenerateQCOutput.R b/DIMS/GenerateQCOutput.R index af63962f..aa1cdae9 100644 --- a/DIMS/GenerateQCOutput.R +++ b/DIMS/GenerateQCOutput.R @@ -136,40 +136,52 @@ is_sum_selection <- c( "2H3-Glutamate (IS)", "2H4_13C5-Arginine (IS)", "13C6-Tyrosine (IS)" ) +all_is_names <- list(neg = is_neg_selection, pos = is_pos_selection, sum = is_sum_selection) + +# define threshold for acceptance of selected internal standards +threshold_is_dbs_neg <- c(15000, 200000, 130000, 18000, 50000) +threshold_is_dbs_pos <- c(150000, 3300000, 1750000, 150000, 270000) +threshold_is_dbs_sum <- c(1300000, 2500000, 500000, 1800000, 1400000) +threshold_is_pl_neg <- c(70000, 700000, 700000, 65000, 350000) +threshold_is_pl_pos <- c(1500000, 9000000, 3000000, 400000, 700000) +threshold_is_pl_sum <- c(8000000, 12500000, 2500000, 3000000, 4000000) +all_is_thresholds_dbs <- list(neg = threshold_is_dbs_neg, pos = threshold_is_dbs_pos, sum = threshold_is_dbs_sum) +all_is_thresholds_pl <- list(neg = threshold_is_pl_neg, pos = threshold_is_pl_pos, sum = threshold_is_pl_sum) +all_is_thresholds <- list(names = all_is_names, plasma = all_is_thresholds_pl, dbs = all_is_thresholds_dbs) # add minimal intensity lines based on matrix (DBS or Plasma) and machine mode (neg, pos, sum) if (dims_matrix == "DBS") { add_min_intens_lines <- TRUE hline_data_neg <- data.frame( - int_line = c(15000, 200000, 130000, 18000, 50000), + int_line = threshold_is_dbs_neg, HMDB_name = is_neg_selection ) hline_data_pos <- data.frame( - int_line = c(150000, 3300000, 1750000, 150000, 270000), + int_line = threshold_is_dbs_pos, HMDB_name = is_pos_selection ) hline_data_sum <- data.frame( - int_line = c(1300000, 2500000, 500000, 1800000, 1400000), + int_line = threshold_is_dbs_sum, HMDB_name = is_sum_selection ) } else if (dims_matrix == "Plasma") { add_min_intens_lines <- TRUE hline_data_neg <- data.frame( - int_line = c(70000, 700000, 700000, 65000, 350000), + int_line = threshold_is_pl_neg, HMDB_name = is_neg_selection ) hline_data_pos <- data.frame( - int_line = c(1500000, 9000000, 3000000, 400000, 700000), + int_line = threshold_is_pl_pos, HMDB_name = is_pos_selection ) hline_data_sum <- data.frame( - int_line = c(8000000, 12500000, 2500000, 3000000, 4000000), + int_line = threshold_is_pl_sum, HMDB_name = is_sum_selection ) } else { @@ -180,9 +192,60 @@ if (dims_matrix == "DBS") { plot_width <- 8 + 0.2 * sample_count plot_height <- plot_width / 2.5 -is_neg_selection <- subset(is_neg, HMDB_name %in% is_neg_selection) -is_pos_selection <- subset(is_pos, HMDB_name %in% is_pos_selection) -is_sum_selection <- subset(is_summed, HMDB_name %in% is_sum_selection) +is_neg_selection_subset <- subset(is_neg, HMDB_name %in% is_neg_selection) +is_pos_selection_subset <- subset(is_pos, HMDB_name %in% is_pos_selection) +is_sum_selection_subset <- subset(is_summed, HMDB_name %in% is_sum_selection) + +# export txt file with samples with internal standard level below threshold +is_below_threshold <- is_pos_selection_subset[0, ] +scanmode_is <- c() +if (dims_matrix == "Plasma") { + # pos + for (line_index in seq_len(nrow(is_pos_selection_subset))) { + is_selected <- is_pos_selection_subset$HMDB_name[line_index] + thresh_selected <- all_is_thresholds$plasma$pos[which(all_is_thresholds$names$pos == is_selected)] + if (is_pos_selection_subset$Intensity[line_index] < thresh_selected) { + is_below_threshold <- rbind(is_below_threshold, is_pos_selection_subset[line_index, ]) + scanmode_is <- c(scanmode_is, "pos") + } + } + # neg + for (line_index in seq_len(nrow(is_neg_selection_subset))) { + is_selected <- is_neg_selection_subset$HMDB_name[line_index] + thresh_selected <- all_is_thresholds$plasma$neg[which(all_is_thresholds$names$neg == is_selected)] + if (is_neg_selection_subset$Intensity[line_index] < thresh_selected) { + is_below_threshold <- rbind(is_below_threshold, is_neg_selection_subset[line_index, ]) + scanmode_is <- c(scanmode_is, "neg") + } + } +} else if (dims_matrix == "DBS") { + # pos + for (line_index in seq_len(nrow(is_pos_selection_subset))) { + is_selected <- is_pos_selection_subset$HMDB_name[line_index] + thresh_selected <- all_is_thresholds$dbs$pos[which(all_is_thresholds$names$pos == is_selected)] + if (is_pos_selection_subset$Intensity[line_index] < thresh_selected) { + is_below_threshold <- rbind(is_below_threshold, is_pos_selection_subset[line_index, ]) + scanmode_is <- c(scanmode_is, "pos") + } + } + # neg + for (line_index in seq_len(nrow(is_neg_selection_subset))) { + is_selected <- is_neg_selection_subset$HMDB_name[line_index] + thresh_selected <- all_is_thresholds$dbs$neg[which(all_is_thresholds$names$neg == is_selected)] + if (is_neg_selection_subset$Intensity[line_index] < thresh_selected) { + is_below_threshold <- rbind(is_below_threshold, is_neg_selection_subset[line_index, ]) + scanmode_is <- c(scanmode_is, "neg") + } + } +} +if (nrow(is_below_threshold) > 0) { + write.table(cbind(is_below_threshold, scanmode = scanmode_is), file = "internal_standards_below_threshold.txt", sep = "\t") +} else { + write.table("no internal standards are below threshold", + file = "internal_standards_below_threshold.txt" + row.names = FALSE, col.names = FALSE + ) +} # bar plot either with or without minimal intensity lines if (add_min_intens_lines) { @@ -325,10 +388,12 @@ if (length(sst_colnrs) > 0) { control_list_intensities <- sst_list[, control_col_ids] control_list_cv <- calc_coefficient_of_variation(control_list_intensities) sst_list_intensities <- cbind(sst_list_intensities, CV_controls = control_list_cv[, "CV_perc"]) + sst_list_intensities <- as.data.frame(sst_list_intensities) } else { sst_list_intensities <- sst_list[, intensity_col_ids] } for (col_nr in seq_len(ncol(sst_list_intensities))) { + sst_list_intensities <- as.data.frame(sst_list_intensities) sst_list_intensities[, col_nr] <- as.numeric(sst_list_intensities[, col_nr]) if (grepl("Zscore", colnames(sst_list_intensities)[col_nr])) { sst_list_intensities[, col_nr] <- round(sst_list_intensities[, col_nr], 2) @@ -356,13 +421,6 @@ xlsx_name <- paste0(outdir, "/", project, "_IS_SST.xlsx") openxlsx::saveWorkbook(wb, xlsx_name, overwrite = TRUE) rm(wb) -# generate text file for workflow completed mail for components with Z-score < 2 -if (grepl("Zscore", colnames(sst_list_intensities))) { - zscore_column <- grep("_Zscore", colnames(sst_list_intensities) - sst_list_intensities_qc <- sst_list_intensities[sst_list_intensities[, zscore_column] < 2, ] - write.table(sst_list_intensities_qc, file = paste(outdir, "sst_qc.txt", sep = "/")) -} - ### MISSING M/Z CHECK # check the outlist_identified_(negative/positive).RData files for missing m/z values and save to file diff --git a/DIMS/GenerateQCOutput.nf b/DIMS/GenerateQCOutput.nf index bee440a5..be2eac37 100644 --- a/DIMS/GenerateQCOutput.nf +++ b/DIMS/GenerateQCOutput.nf @@ -18,6 +18,7 @@ process GenerateQCOutput { path('plots/IS_*.png'), emit: plot_files path('Check_number_of_controls.txt'), optional: true path('sst_qc.txt'), optional: true + path('internal_standards_below_threshold.txt'), optional: true script: """ From af62a0ed8277dca812c08cca190d49c4b34b5bf0 Mon Sep 17 00:00:00 2001 From: Mia Pras-Raves Date: Fri, 9 Jan 2026 17:13:26 +0100 Subject: [PATCH 03/10] modified DIMS AverageTechReplicates for QC info in mail --- DIMS/AverageTechReplicates.R | 6 ++++++ DIMS/AverageTechReplicates.nf | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/DIMS/AverageTechReplicates.R b/DIMS/AverageTechReplicates.R index 1c727d10..2235e47c 100644 --- a/DIMS/AverageTechReplicates.R +++ b/DIMS/AverageTechReplicates.R @@ -112,6 +112,9 @@ for (sample_nr in 1:length(repl_pattern)) { pattern_list <- remove_from_repl_pattern(remove_neg, repl_pattern, nr_replicates) repl_pattern_filtered <- pattern_list$pattern save(repl_pattern_filtered, file = "negative_repl_pattern.RData") +if (is.null(remove_neg)) { + remove_neg <- "none" +} write.table( remove_neg, file = "miss_infusions_negative.txt", @@ -123,6 +126,9 @@ write.table( pattern_list <- remove_from_repl_pattern(remove_pos, repl_pattern, nr_replicates) repl_pattern_filtered <- pattern_list$pattern save(repl_pattern_filtered, file = "positive_repl_pattern.RData") +if (is.null(remove_pos)) { + remove_pos <- "none" +} write.table( remove_pos, file = "miss_infusions_positive.txt", diff --git a/DIMS/AverageTechReplicates.nf b/DIMS/AverageTechReplicates.nf index f03d553c..8dafde45 100644 --- a/DIMS/AverageTechReplicates.nf +++ b/DIMS/AverageTechReplicates.nf @@ -17,8 +17,8 @@ process AverageTechReplicates { output: path('*_repl_pattern.RData'), emit: pattern_files path('*_avg.RData'), emit: binned_files - path('miss_infusions_negative.txt') - path('miss_infusions_positive.txt') + path('miss_infusions_negative.txt'), emit: qc_miss_neg + path('miss_infusions_positive.txt'), emit: qc_miss_pos path('*_TICplots.pdf'), emit: tic_plots_pdf script: From 7c349cea048b7ad7f244d8e6ad0c212e1e44828f Mon Sep 17 00:00:00 2001 From: Mia Pras-Raves Date: Fri, 9 Jan 2026 17:28:18 +0100 Subject: [PATCH 04/10] modified DIMS GenerateQCOutput for QC info in mail --- DIMS/GenerateQCOutput.R | 28 +++++++++++++++++++++------- DIMS/GenerateQCOutput.nf | 2 +- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/DIMS/GenerateQCOutput.R b/DIMS/GenerateQCOutput.R index aa1cdae9..988c059b 100644 --- a/DIMS/GenerateQCOutput.R +++ b/DIMS/GenerateQCOutput.R @@ -48,14 +48,16 @@ if (z_score == 1) { is_list <- outlist[grep("Internal standard", outlist[, "relevance"], fixed = TRUE), ] is_codes <- rownames(is_list) -# check if there is data present for all the samples that the pipeline started with, -# if not write sample name to a log file. +# check if there is data present for all the samples that the pipeline started with sample_names_nodata <- setdiff(names(repl_pattern), names(is_list)) +if (length(sample_names_nodata) == 0) { + sample_names_nodata <- "none" +} +write.table(sample_names_nodata, + file = paste(outdir, "sample_names_nodata.txt", sep = "/"), + row.names = FALSE, col.names = FALSE, quote = FALSE +) if (!is.null(sample_names_nodata)) { - write.table(sample_names_nodata, - file = paste(outdir, "sample_names_nodata.txt", sep = "/"), - row.names = FALSE, col.names = FALSE, quote = FALSE - ) for (sample_name in sample_names_nodata) { repl_pattern[[sample_name]] <- NULL } @@ -238,8 +240,11 @@ if (dims_matrix == "Plasma") { } } } +is_below_threshold <- select(is_below_threshold, -c("Matrix", "Rundata", "Sample_level")) if (nrow(is_below_threshold) > 0) { - write.table(cbind(is_below_threshold, scanmode = scanmode_is), file = "internal_standards_below_threshold.txt", sep = "\t") + write.table(cbind(is_below_threshold, scanmode = scanmode_is), + file = "internal_standards_below_threshold.txt", + row.names = FALSE, sep = "\t") } else { write.table("no internal standards are below threshold", file = "internal_standards_below_threshold.txt" @@ -421,6 +426,15 @@ xlsx_name <- paste0(outdir, "/", project, "_IS_SST.xlsx") openxlsx::saveWorkbook(wb, xlsx_name, overwrite = TRUE) rm(wb) +# generate text file for workflow completed mail for components with Z-score < 2 +if (sum(grepl("P1001", colnames(sst_list_intensities))) > 0) { + zscore_column <- grep("_Zscore", colnames(sst_list_intensities))[1] + sst_list_intensities_qc <- sst_list_intensities[sst_list_intensities[, zscore_column] < 2, ] + sst_list_intensities_qc <- select(sst_list_intensities_qc, -c("CV_controls")) + write.table(sst_list_intensities_qc, file = paste(outdir, "sst_qc.txt", sep = "/"), row.names = FALSE, sep = "\t") +} else { + write.table("no SST sample present", file = paste(outdir, "sst_qc.txt", sep = "/"), row.names = FALSE, col.names = FALSE) +} ### MISSING M/Z CHECK # check the outlist_identified_(negative/positive).RData files for missing m/z values and save to file diff --git a/DIMS/GenerateQCOutput.nf b/DIMS/GenerateQCOutput.nf index be2eac37..6a4f6135 100644 --- a/DIMS/GenerateQCOutput.nf +++ b/DIMS/GenerateQCOutput.nf @@ -16,7 +16,7 @@ process GenerateQCOutput { tuple path('positive_controls_warning.txt'), path('missing_mz_warning.txt'), path('sample_names_nodata.txt'), optional: true tuple path('*_IS_SST.xlsx'), path('*_positive_control.xlsx'), optional: true path('plots/IS_*.png'), emit: plot_files - path('Check_number_of_controls.txt'), optional: true + path('check_number_of_controls.txt'), optional: true path('sst_qc.txt'), optional: true path('internal_standards_below_threshold.txt'), optional: true From 76baae9dfbfcaecd94122484e8d9749e81245dc9 Mon Sep 17 00:00:00 2001 From: Mia Pras-Raves Date: Thu, 22 Jan 2026 12:14:00 +0100 Subject: [PATCH 05/10] moved generation of list of internal standards below threshold to function --- DIMS/GenerateQCOutput.R | 55 +++++----------------- DIMS/export/generate_qc_output_functions.R | 26 ++++++++++ 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/DIMS/GenerateQCOutput.R b/DIMS/GenerateQCOutput.R index 988c059b..936ef25a 100644 --- a/DIMS/GenerateQCOutput.R +++ b/DIMS/GenerateQCOutput.R @@ -138,7 +138,6 @@ is_sum_selection <- c( "2H3-Glutamate (IS)", "2H4_13C5-Arginine (IS)", "13C6-Tyrosine (IS)" ) -all_is_names <- list(neg = is_neg_selection, pos = is_pos_selection, sum = is_sum_selection) # define threshold for acceptance of selected internal standards threshold_is_dbs_neg <- c(15000, 200000, 130000, 18000, 50000) @@ -147,9 +146,6 @@ threshold_is_dbs_sum <- c(1300000, 2500000, 500000, 1800000, 1400000) threshold_is_pl_neg <- c(70000, 700000, 700000, 65000, 350000) threshold_is_pl_pos <- c(1500000, 9000000, 3000000, 400000, 700000) threshold_is_pl_sum <- c(8000000, 12500000, 2500000, 3000000, 4000000) -all_is_thresholds_dbs <- list(neg = threshold_is_dbs_neg, pos = threshold_is_dbs_pos, sum = threshold_is_dbs_sum) -all_is_thresholds_pl <- list(neg = threshold_is_pl_neg, pos = threshold_is_pl_pos, sum = threshold_is_pl_sum) -all_is_thresholds <- list(names = all_is_names, plasma = all_is_thresholds_pl, dbs = all_is_thresholds_dbs) # add minimal intensity lines based on matrix (DBS or Plasma) and machine mode (neg, pos, sum) if (dims_matrix == "DBS") { @@ -199,48 +195,21 @@ is_pos_selection_subset <- subset(is_pos, HMDB_name %in% is_pos_selection) is_sum_selection_subset <- subset(is_summed, HMDB_name %in% is_sum_selection) # export txt file with samples with internal standard level below threshold -is_below_threshold <- is_pos_selection_subset[0, ] -scanmode_is <- c() if (dims_matrix == "Plasma") { - # pos - for (line_index in seq_len(nrow(is_pos_selection_subset))) { - is_selected <- is_pos_selection_subset$HMDB_name[line_index] - thresh_selected <- all_is_thresholds$plasma$pos[which(all_is_thresholds$names$pos == is_selected)] - if (is_pos_selection_subset$Intensity[line_index] < thresh_selected) { - is_below_threshold <- rbind(is_below_threshold, is_pos_selection_subset[line_index, ]) - scanmode_is <- c(scanmode_is, "pos") - } - } - # neg - for (line_index in seq_len(nrow(is_neg_selection_subset))) { - is_selected <- is_neg_selection_subset$HMDB_name[line_index] - thresh_selected <- all_is_thresholds$plasma$neg[which(all_is_thresholds$names$neg == is_selected)] - if (is_neg_selection_subset$Intensity[line_index] < thresh_selected) { - is_below_threshold <- rbind(is_below_threshold, is_neg_selection_subset[line_index, ]) - scanmode_is <- c(scanmode_is, "neg") - } - } + is_below_threshold_neg <- find_is_below_threshold(is_neg_selection_subset, threshold_is_pl_neg, is_neg_selection, "neg") + is_below_threshold_pos <- find_is_below_threshold(is_pos_selection_subset, threshold_is_pl_pos, is_pos_selection, "pos") + is_below_threshold_sum <- find_is_below_threshold(is_sum_selection_subset, threshold_is_pl_sum, is_sum_selection, "sum") + is_below_threshold <- rbind(is_below_threshold_pos, is_below_threshold_neg, is_below_threshold_sum) } else if (dims_matrix == "DBS") { - # pos - for (line_index in seq_len(nrow(is_pos_selection_subset))) { - is_selected <- is_pos_selection_subset$HMDB_name[line_index] - thresh_selected <- all_is_thresholds$dbs$pos[which(all_is_thresholds$names$pos == is_selected)] - if (is_pos_selection_subset$Intensity[line_index] < thresh_selected) { - is_below_threshold <- rbind(is_below_threshold, is_pos_selection_subset[line_index, ]) - scanmode_is <- c(scanmode_is, "pos") - } - } - # neg - for (line_index in seq_len(nrow(is_neg_selection_subset))) { - is_selected <- is_neg_selection_subset$HMDB_name[line_index] - thresh_selected <- all_is_thresholds$dbs$neg[which(all_is_thresholds$names$neg == is_selected)] - if (is_neg_selection_subset$Intensity[line_index] < thresh_selected) { - is_below_threshold <- rbind(is_below_threshold, is_neg_selection_subset[line_index, ]) - scanmode_is <- c(scanmode_is, "neg") - } - } + is_below_threshold_neg <- find_is_below_threshold(is_neg_selection_subset, threshold_is_dbs_neg, is_neg_selection, "neg") + is_below_threshold_pos <- find_is_below_threshold(is_pos_selection_subset, threshold_is_dbs_pos, is_pos_selection, "pos") + is_below_threshold_sum <- find_is_below_threshold(is_sum_selection_subset, threshold_is_dbs_sum, is_neg_selection, "sum") + is_below_threshold <- rbind(is_below_threshold_pos, is_below_threshold_neg, is_below_threshold_sum) +} else { + # generate empty table + is_below_threshold <- is_neg_selection_subset[0, ] } -is_below_threshold <- select(is_below_threshold, -c("Matrix", "Rundata", "Sample_level")) + if (nrow(is_below_threshold) > 0) { write.table(cbind(is_below_threshold, scanmode = scanmode_is), file = "internal_standards_below_threshold.txt", diff --git a/DIMS/export/generate_qc_output_functions.R b/DIMS/export/generate_qc_output_functions.R index 23c81d06..9f672adb 100644 --- a/DIMS/export/generate_qc_output_functions.R +++ b/DIMS/export/generate_qc_output_functions.R @@ -217,3 +217,29 @@ check_missing_mz <- function(mzmed_pgrp_ident, scanmode) { } return(results_mz_missing) } + +find_is_below_threshold <- function(is_selection_subset, thresholds, is_names, scanmode) { + #' Create a list of all internal standards with intensity below a threshold value + #' + #' @param is_selection_subset: Matrix with intensities for each internal standard in each sample + #' @param thresholds: Threshold values for a given scan mode and matrix + #' @param is_names: Array of names of internal standards for a given scan mode + #' @param scanmode: string indicating scan mode to include in output + #' + #' @return is_below_threshold: Matrix listing all samples for which internal standard intensity is below threshold + + # initialize; get the headers of the matrix + is_below_threshold <- is_selection_subset[0, ] + # for every line, check if intensity is below the appropriate threshold + for (line_index in seq_len(nrow(is_selection_subset))) { + is_selected <- is_selection_subset$HMDB_name[line_index] + thresh_selected <- thresholds[which(is_names == is_selected)] + if (is_selection_subset$Intensity[line_index] < thresh_selected) { + is_below_threshold <- rbind(is_below_threshold, is_selection_subset[line_index, ]) + } + } + # add information on scan mode + is_below_threshold <- cbind(is_below_threshold, scanmode = rep(scanmode, nrow(is_below_threshold))) + return(is_below_threshold) +} + From 22140fb4c4b10471460ecd00f14eb4d354720945 Mon Sep 17 00:00:00 2001 From: Mia Pras-Raves Date: Thu, 22 Jan 2026 14:08:21 +0100 Subject: [PATCH 06/10] added unit test for function find_is_below_threshold --- DIMS/tests/testthat/test_generate_qc_output.R | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/DIMS/tests/testthat/test_generate_qc_output.R b/DIMS/tests/testthat/test_generate_qc_output.R index 2bb953aa..0586799f 100644 --- a/DIMS/tests/testthat/test_generate_qc_output.R +++ b/DIMS/tests/testthat/test_generate_qc_output.R @@ -201,3 +201,22 @@ testthat::test_that("Check missing mz values", { expect_identical(check_missing_mz(test_mz_pgrp, "Test")$`1`, c(550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560)) }) + +testthat:: testthat("list of internal standards below threshold is correctly created", { + test_is <- read.delim(test_path("fixtures", "test_internal_standards.txt")) + # select columns + test_is_wide <- test_is[ , c("HMDB_code", "HMDB_name", "C101.1", "C102.1", "P2.1", "P3.1")] + # melt into long format + test_is_long <- melt(setDT(test_is_wide), id.vars = c("HMDB_name","HMDB_code")) + colnames(test_is_long)[4] <- "Intensity" + + test_is_names <- c("metab_1 (IS)", "metab_2 (IS)", "metab_3 (IS)", "metab_4 (IS)") + test_thresholds <- rep(300, 4) + + # 8 rows have intensity below threshold + expect_equal(nrow(find_is_below_threshold(test_is_long, test_thresholds, test_is_names, "test")), 8) + # the maximum intensity in the output should be less than threshold + expect_lt(max(find_is_below_threshold(test_is_long, test_thresholds, test_is_names, "test")$Intensity), 300) + # if all values are above threshold, the result should be an empty data table + expect_equal(nrow(find_is_below_threshold(test_is_long, test_thresholds / 3, test_is_names, "test")), 0) +}) From 4501fd95434f1b27f37625795bde42c01af99419 Mon Sep 17 00:00:00 2001 From: Mia Pras-Raves Date: Fri, 23 Jan 2026 11:19:36 +0100 Subject: [PATCH 07/10] removed erroneous space --- DIMS/tests/testthat/test_generate_qc_output.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DIMS/tests/testthat/test_generate_qc_output.R b/DIMS/tests/testthat/test_generate_qc_output.R index 0586799f..b411034e 100644 --- a/DIMS/tests/testthat/test_generate_qc_output.R +++ b/DIMS/tests/testthat/test_generate_qc_output.R @@ -202,7 +202,7 @@ testthat::test_that("Check missing mz values", { c(550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560)) }) -testthat:: testthat("list of internal standards below threshold is correctly created", { +testthat::testthat("list of internal standards below threshold is correctly created", { test_is <- read.delim(test_path("fixtures", "test_internal_standards.txt")) # select columns test_is_wide <- test_is[ , c("HMDB_code", "HMDB_name", "C101.1", "C102.1", "P2.1", "P3.1")] From 5f32d2f620a3869c85038b45b7b213ea811eb8b8 Mon Sep 17 00:00:00 2001 From: Mia Pras-Raves Date: Fri, 23 Jan 2026 11:32:59 +0100 Subject: [PATCH 08/10] corrected typo --- DIMS/tests/testthat/test_generate_qc_output.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DIMS/tests/testthat/test_generate_qc_output.R b/DIMS/tests/testthat/test_generate_qc_output.R index b411034e..81b74c17 100644 --- a/DIMS/tests/testthat/test_generate_qc_output.R +++ b/DIMS/tests/testthat/test_generate_qc_output.R @@ -202,7 +202,7 @@ testthat::test_that("Check missing mz values", { c(550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560)) }) -testthat::testthat("list of internal standards below threshold is correctly created", { +testthat::test_that("list of internal standards below threshold is correctly created", { test_is <- read.delim(test_path("fixtures", "test_internal_standards.txt")) # select columns test_is_wide <- test_is[ , c("HMDB_code", "HMDB_name", "C101.1", "C102.1", "P2.1", "P3.1")] From 534002e8f81d34b9f07654223ee0db6c2dc904ac Mon Sep 17 00:00:00 2001 From: Mia Pras-Raves Date: Fri, 23 Jan 2026 11:39:12 +0100 Subject: [PATCH 09/10] added library data.table --- DIMS/tests/testthat/test_generate_qc_output.R | 1 + 1 file changed, 1 insertion(+) diff --git a/DIMS/tests/testthat/test_generate_qc_output.R b/DIMS/tests/testthat/test_generate_qc_output.R index 81b74c17..f355a021 100644 --- a/DIMS/tests/testthat/test_generate_qc_output.R +++ b/DIMS/tests/testthat/test_generate_qc_output.R @@ -4,6 +4,7 @@ # get_is_intensities, calc_coefficient_of_variation, # check_missing_mz library(ggplot2) +library(data.table) suppressMessages(library("dplyr")) source("../../export/generate_qc_output_functions.R") From 7c0d0563a19a79f4e67b5f511c3341d1230864fa Mon Sep 17 00:00:00 2001 From: Mia Pras-Raves Date: Fri, 23 Jan 2026 11:49:55 +0100 Subject: [PATCH 10/10] replaced library data.table with reshape2 --- DIMS/tests/testthat/test_generate_qc_output.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DIMS/tests/testthat/test_generate_qc_output.R b/DIMS/tests/testthat/test_generate_qc_output.R index f355a021..07be0178 100644 --- a/DIMS/tests/testthat/test_generate_qc_output.R +++ b/DIMS/tests/testthat/test_generate_qc_output.R @@ -4,7 +4,7 @@ # get_is_intensities, calc_coefficient_of_variation, # check_missing_mz library(ggplot2) -library(data.table) +library(reshape2) suppressMessages(library("dplyr")) source("../../export/generate_qc_output_functions.R") @@ -208,7 +208,7 @@ testthat::test_that("list of internal standards below threshold is correctly cre # select columns test_is_wide <- test_is[ , c("HMDB_code", "HMDB_name", "C101.1", "C102.1", "P2.1", "P3.1")] # melt into long format - test_is_long <- melt(setDT(test_is_wide), id.vars = c("HMDB_name","HMDB_code")) + test_is_long <- reshape2::melt(test_is_wide, id.vars = c("HMDB_name","HMDB_code")) colnames(test_is_long)[4] <- "Intensity" test_is_names <- c("metab_1 (IS)", "metab_2 (IS)", "metab_3 (IS)", "metab_4 (IS)")