From e8d0a7f1aea50bd06442ad0e579ead446f5a87d8 Mon Sep 17 00:00:00 2001 From: ALuesink Date: Thu, 7 Aug 2025 17:00:53 +0200 Subject: [PATCH 01/14] Refactored code GenerateViolinPlots --- DIMS/GenerateViolinPlots.R | 649 +++++------------- DIMS/GenerateViolinPlots.nf | 5 +- DIMS/export/generate_violin_plots_functions.R | 572 +++++++++++++++ 3 files changed, 763 insertions(+), 463 deletions(-) create mode 100644 DIMS/export/generate_violin_plots_functions.R diff --git a/DIMS/GenerateViolinPlots.R b/DIMS/GenerateViolinPlots.R index 263c7201..2e6cb885 100644 --- a/DIMS/GenerateViolinPlots.R +++ b/DIMS/GenerateViolinPlots.R @@ -1,14 +1,3 @@ -# For untargeted metabolomics, this tool calculates probability scores for -# metabolic disorders. In addition, it provides visual support with violin plots -# of the DIMS measurements for the lab specialists. -# Input needed: -# 1. Excel file in which metabolites are listed with their intensities for -# controls (with C in samplename) and patients (with P in samplename) and their -# corresponding Z-scores. -# 2. All files from github: https://github.com/UMCUGenetics/DIMS - -## adapted from 15-dIEM_violin.R - # load packages suppressPackageStartupMessages(library("dplyr")) library(reshape2) @@ -21,462 +10,202 @@ library(stringr) cmd_args <- commandArgs(trailingOnly = TRUE) run_name <- cmd_args[1] -scripts_dir <- cmd_args[2] -z_score <- as.numeric(cmd_args[3]) -path_metabolite_groups <- cmd_args[4] -file_ratios_metabolites <- cmd_args[5] -file_expected_biomarkers_iem <- cmd_args[6] -file_explanation <- cmd_args[7] -file_isomers <- cmd_args[8] - -if (z_score == 1){ - # path: output folder for dIEM and violin plots - output_dir <- "./" - - file.copy(file_isomers, output_dir) - - # load functions - source(paste0(scripts_dir, "check_same_samplename.R")) - source(paste0(scripts_dir, "prepare_data.R")) - source(paste0(scripts_dir, "prepare_data_perpage.R")) - source(paste0(scripts_dir, "prepare_toplist.R")) - source(paste0(scripts_dir, "create_violin_plots.R")) - source(paste0(scripts_dir, "prepare_alarmvalues.R")) - source(paste0(scripts_dir, "output_helix.R")) - source(paste0(scripts_dir, "get_patient_data_to_helix.R")) - source(paste0(scripts_dir, "add_lab_id_and_onderzoeksnummer.R")) - source(paste0(scripts_dir, "is_diagnostic_patient.R")) - - # number of diseases that score highest in algorithm to plot - top_nr_iem <- 5 - # probability score cut-off for plotting the top diseases - threshold_iem <- 5 - # z-score cutoff of axis on the left for top diseases - ratios_cutoff <- -5 - # number of violin plots per page in PDF - nr_plots_perpage <- 20 - - # binary variable: run function, yes(1) or no(0) - if (z_score == 1) { - algorithm <- ratios <- violin <- 1 - } else { - algorithm <- ratios <- violin <- 0 - } - # are the sample names headers on row 1 or row 2 in the DIMS excel? (default 1) - header_row <- 1 - # column name where the data starts (default B) - col_start <- "B" - zscore_cutoff <- 5 - xaxis_cutoff <- 20 - protocol_name <- "DIMS_PL_DIAG" - - #### STEP 1: Preparation #### - # in: run_name, path_dims_file, header_row ||| out: output_dir, DIMS - - # load outlist instead of excel file - load("outlist.RData") - - # save outlist as dims_xls, will be changed during refactor - dims_xls <- outlist - rm(outlist) - - #### STEP 2: Edit DIMS data ##### - # in: dims_xls ||| out: Data, nr_contr, nr_pat - # Input: the xlsx file that comes out of the pipeline with format: - # [plots] [C] [P] [summary columns] [C_Zscore] [P_Zscore] - # Output: "_CSV.csv" file that is suited for the algorithm in shiny. - - # Determine the number of Contols and Patients in column names: - nr_contr <- length(grep("C", names(dims_xls))) / 2 - nr_pat <- length(grep("P", names(dims_xls))) / 2 - # total number of samples - nrsamples <- nr_contr + nr_pat - # check whether the number of intensity columns equals the number of Zscore columns - if (nr_contr + nr_pat != length(grep("_Zscore", names(dims_xls)))) { - cat("\n**** Error: there aren't as many intensities listed as Zscores") - } - cat(paste0("\n\n------------\n", nr_contr, " controls \n", nr_pat, " patients\n------------\n\n")) - - # Move the columns HMDB_code and HMDB_name to the beginning. - hmdb_info_cols <- c(which(colnames(dims_xls) == "HMDB_code"), which(colnames(dims_xls) == "HMDB_name")) - other_cols <- seq_along(1:ncol(dims_xls))[-hmdb_info_cols] - dims_xls_copy <- dims_xls[, c(hmdb_info_cols, other_cols)] - # Remove the columns from 'name' to 'pathway' - from_col <- which(colnames(dims_xls_copy) == "name") - to_col <- which(colnames(dims_xls_copy) == "pathway") - dims_xls_copy <- dims_xls_copy[, -c(from_col:to_col)] - # in case the excel had an empty "plots" column, remove it - if ("plots" %in% colnames(dims_xls_copy)) { - dims_xls_copy <- dims_xls_copy[, -grep("plots", colnames(dims_xls_copy))] - } - # Rename columns - names(dims_xls_copy) <- gsub("avg.ctrls", "Mean_controls", names(dims_xls_copy)) - names(dims_xls_copy) <- gsub("sd.ctrls", "SD_controls", names(dims_xls_copy)) - names(dims_xls_copy) <- gsub("HMDB_code", "HMDB.code", names(dims_xls_copy)) - names(dims_xls_copy) <- gsub("HMDB_name", "HMDB.name", names(dims_xls_copy)) - - # intensity columns and mean and standard deviation of controls - numeric_cols <- c(3:ncol(dims_xls_copy)) - # make sure all values are numeric - dims_xls_copy[, numeric_cols] <- sapply(dims_xls_copy[, numeric_cols], as.numeric) - - if (exists("dims_xls_copy") & (length(dims_xls_copy) < length(dims_xls))) { - cat("\n### Step 2 # Edit dims data is done.\n") - } else { - cat("\n**** Error: Could not execute step 2 \n") - } - - #### STEP 3: Calculate ratios of intensities for metabolites #### - # in: ratios, file_ratios_metabolites, dims_xls_copy, nr_contr, nr_pat ||| out: Zscore (+file) - # This script loads the file with Ratios (file_ratios_metabolites) and calculates - # the ratios of the intensities of the given metabolites. It also calculates - # Zs-cores based on the avg and sd of the ratios of the controls. - - # Input: dataframe with intenstities and Zscores of controls and patients: - # [HMDB.code] [HMDB.name] [C] [P] [Mean_controls] [SD_controls] [C_Zscore] [P_Zscore] - - # Output: "_CSV.csv" file that is suited for the algorithm, with format: - # "_Ratios_CSV.csv" file, same file as above, but with ratio rows added. - - if (ratios == 1) { - cat(paste0("\nloading ratios file:\n -> ", file_ratios_metabolites, "\n")) - ratio_input <- read.csv(file_ratios_metabolites, sep = ";", stringsAsFactors = FALSE) - - # Prepare empty data frame to fill with ratios - ratio_list <- setNames(data.frame(matrix( - ncol = ncol(dims_xls_copy), - nrow = nrow(ratio_input) - )), colnames(dims_xls_copy)) - ratio_list <- as.data.frame(ratio_list) - - # put HMDB info into first two columns of ratio_list - ratio_list[, 1:2] <- ratio_input[, 1:2] - - # look for intensity columns (exclude Zscore columns) - control_cols <- grep("C", colnames(ratio_list)[1:which(colnames(ratio_list) == "Mean_controls")]) - patient_cols <- grep("P", colnames(ratio_list)[1:which(colnames(ratio_list) == "Mean_controls")]) - intensity_cols <- c(control_cols, patient_cols) - # calculate each of the ratios of intensities - for (ratio_index in 1:nrow(ratio_input)) { - ratio_numerator <- ratio_input[ratio_index, "HMDB_numerator"] - ratio_numerator <- strsplit(ratio_numerator, "plus")[[1]] - ratio_denominator <- ratio_input[ratio_index, "HMDB_denominator"] - ratio_denominator <- strsplit(ratio_denominator, "plus")[[1]] - # find these HMDB IDs in dataset. Could be a sum of multiple metabolites - sel_denominator <- sel_numerator <- c() - for (numerator_index in 1:length(ratio_numerator)) { - sel_numerator <- c(sel_numerator, which(dims_xls_copy[, "HMDB.code"] == ratio_numerator[numerator_index])) - } - for (denominator_index in 1:length(ratio_denominator)) { - # special case for sum of metabolites (dividing by one) - if (ratio_denominator[denominator_index] != "one") { - sel_denominator <- c(sel_denominator, which(dims_xls_copy[, "HMDB.code"] == ratio_denominator[denominator_index])) - } - } - # calculate ratio - if (ratio_denominator[denominator_index] != "one") { - ratio_list[ratio_index, intensity_cols] <- apply(dims_xls_copy[sel_numerator, intensity_cols], 2, sum) / - apply(dims_xls_copy[sel_denominator, intensity_cols], 2, sum) - } else { - # special case for sum of metabolites (dividing by one) - ratio_list[ratio_index, intensity_cols] <- apply(dims_xls_copy[sel_numerator, intensity_cols], 2, sum) - } - # calculate log of ratio - ratio_list[ratio_index, intensity_cols] <- log2(ratio_list[ratio_index, intensity_cols]) - } - - # Calculate means and SD's of the calculated ratios for Controls - ratio_list[, "Mean_controls"] <- apply(ratio_list[, control_cols], 1, mean) - ratio_list[, "SD_controls"] <- apply(ratio_list[, control_cols], 1, sd) - - # Calc z-scores with the means and SD's of Controls - zscore_cols <- grep("Zscore", colnames(ratio_list)) - for (sample_index in 1:length(zscore_cols)) { - zscore_col <- zscore_cols[sample_index] - # matching intensity column - int_col <- intensity_cols[sample_index] - # test on column names - if (check_same_samplename(colnames(ratio_list)[int_col], colnames(ratio_list)[zscore_col])) { - # calculate Z-scores - ratio_list[, zscore_col] <- (ratio_list[, int_col] - ratio_list[, "Mean_controls"]) / ratio_list[, "SD_controls"] - } +export_scripts_dir <- cmd_args[2] +path_metabolite_groups <- cmd_args[3] +file_ratios_metabolites <- cmd_args[4] +file_expected_biomarkers_iem <- cmd_args[5] +file_explanation <- cmd_args[6] + +# load functions +source(paste0(export_scripts_dir, "generate_violin_plots_functions.R")) +# load dataframe with intensities and Z-scores for all samples +intensities_zscore_df <- get(load("outlist.RData")) +# read input files +ratios_metabs_df <- read.csv(file_ratios_metabolites, sep = ";", stringsAsFactors = FALSE) +expected_biomarkers_df <- read.csv(file_expected_biomarkers_iem, sep = ";", stringsAsFactors = FALSE) +explanation_violin_plot <- readLines(file_explanation) + + +## Set global variables +output_dir <- "./" # path: output folder for dIEM and violin plots +top_number_iem_diseases <- 5 # number of diseases that score highest in algorithm to plot +threshold_iem <- 5 # probability score cut-off for plotting the top diseases +ratios_cutoff <- -5 # z-score cutoff of axis on the left for top diseases +nr_plots_perpage <- 20 # number of violin plots per page in PDF +zscore_cutoff <- 5 +xaxis_cutoff <- 20 +protocol_name <- "DIMS_PL_DIAG" + +# Remove columns, move HMDB_code & HMDB_name column to the front, change intensity columns to numeric +intensities_zscore_df <- intensities_zscore_df %>% + select(-c(plots, HMDB_name_all, HMDB_ID_all, sec_HMDB_ID, HMDB_key, sec_HMBD_ID_rlvnc, name, + relevance, descr, origin, fluids, tissue, disease, pathway, nr_ctrls)) %>% + relocate(c(HMDB_code, HMDB_name)) %>% + rename(mean_controls = avg_ctrls, sd_controls = sd_ctrls) %>% + mutate(across(!c(HMDB_name, HMDB_code), as.numeric)) + +# Get the controls and patient IDs, select the intensity columns +controls <- colnames(intensities_zscore_df)[grepl("^C", colnames(intensities_zscore_df)) & + !grepl("_Zscore$", colnames(intensities_zscore_df))] +control_intensities_cols_index <- which(colnames(intensities_zscore_df) %in% controls) +nr_of_controls <- length(controls) + +patients <- colnames(intensities_zscore_df)[grepl("^P", colnames(intensities_zscore_df)) & + !grepl("_Zscore$", colnames(intensities_zscore_df))] +patient_intensities_cols_index <- which(colnames(intensities_zscore_df) %in% patients) +nr_of_patients <- length(patients) + +intensity_cols_index <- c(control_intensities_cols_index, patient_intensities_cols_index) +intensity_cols <- colnames(intensities_zscore_df)[intensity_cols_index] + +#### Calculate ratios of intensities for metabolites #### +# Prepare empty data frame to fill with ratios +ratio_zscore_df <- data.frame(matrix( + ncol = ncol(intensities_zscore_df), + nrow = nrow(ratios_metabs_df) +)) +colnames(ratio_zscore_df) <- colnames(intensities_zscore_df) + +# put HMDB info into first two columns of ratio_zscore_df +ratio_zscore_df$HMDB_code <- ratios_metabs_df$HMDB.code +ratio_zscore_df$HMDB_name <- ratios_metabs_df$Ratio_name + +for (row_index in 1:nrow(ratios_metabs_df)) { + numerator_intensities <- get_intentities_for_ratios(ratios_metabs_df, row_index, + intensities_zscore_df, "HMDB_numerator", intensity_cols) + denominator_intensities <- get_intentities_for_ratios(ratios_metabs_df, row_index, + intensities_zscore_df, "HMDB_denominator", intensity_cols) + # calculate intensity ratios + ratio_zscore_df[row_index, intensity_cols_index] <- log2(numerator_intensities / denominator_intensities) +} +# Calculate means and SD's of the calculated ratios for Controls +ratio_zscore_df[, "mean_controls"] <- apply(ratio_zscore_df[, control_intensities_cols_index], 1, mean) +ratio_zscore_df[, "sd_controls"] <- apply(ratio_zscore_df[, control_intensities_cols_index], 1, sd) + +# Calculate Zscores for the ratios +samples_zscore_columns <- get_zscore_columns(colnames(intensities_zscore_df), intensity_cols) +ratio_zscore_df[, samples_zscore_columns] <- (ratio_zscore_df[, intensity_cols] - ratio_zscore_df[, "mean_controls"]) / + ratio_zscore_df[, "sd_controls"] + +intensities_zscore_ratios_df <- rbind(intensities_zscore_df, ratio_zscore_df) + +# for debugging: +save(intensities_zscore_ratios_df, file = paste0(output_dir, "/outlist_with_ratios.RData")) + +# Select only the cols with zscores of the patients +zscore_patients_df <- intensities_zscore_ratios_df %>% select(HMDB_code, HMDB_name, any_of(paste0(patients, "_Zscore"))) +zscore_controls_df <- intensities_zscore_ratios_df %>% select(HMDB_code, HMDB_name, any_of(paste0(controls, "_Zscore"))) + +#### Make violin plots ##### +# preparation +colnames(zscore_patients_df) <- gsub("_Zscore", "", colnames(zscore_patients_df)) +colnames(zscore_controls_df) <- gsub("_Zscore", "", colnames(zscore_controls_df)) + +expected_biomarkers_df <- expected_biomarkers_df %>% rename(HMDB_code = HMDB.code, HMDB_name = Metabolite) + +expected_biomarkers_info <- expected_biomarkers_df %>% + select(c(Disease, HMDB_code, HMDB_name)) %>% + distinct(Disease, HMDB_code, .keep_all = TRUE) + +metabolite_dirs <- list.files(path = path_metabolite_groups, full.names = FALSE, recursive = FALSE) +for (metabolite_dir in metabolite_dirs) { + # create a directory for the output PDFs + pdf_dir <- paste(output_dir, metabolite_dir, sep = "/") + dir.create(pdf_dir, showWarnings = FALSE) + + metab_list_all <- get_list_metabolites(paste(path_metabolite_groups, metabolite_dir, sep = "/")) + + # prepare list of metabolites; max nr_plots_perpage on one page + metab_interest_sorted <- combine_metab_info_zscores(metab_list_all, zscore_patients_df) + metab_interest_controls <- combine_metab_info_zscores(metab_list_all, zscore_controls_df) + metab_perpage <- prepare_data_perpage(metab_interest_sorted, metab_interest_controls, + nr_plots_perpage, nr_of_patients, nr_of_controls) + + # for Diagnostics metabolites to be saved in Helix + if(grepl("Diagnost", pdf_dir)) { + # get table that combines DIMS results with stofgroepen/Helix table + dims_helix_table <- get_patient_data_to_helix(metab_interest_sorted, metab_list_all) + + # check if run contains Diagnostics patients (e.g. "P2024M"), not for research runs + if(any(is_diagnostic_patient(dims_helix_table$Sample))){ + # get output file for Helix + output_helix <- output_for_helix(protocol_name, dims_helix_table) + # write output to file + path_helixfile <- paste0(output_dir, "output_Helix_", run_name,".csv") + write.csv(output_helix, path_helixfile, quote = F, row.names = F) } - - # Add rows of the ratio hmdb codes to the data of zscores from the pipeline. - dims_xls_ratios <- rbind(ratio_list, dims_xls_copy) - - # Edit the DIMS output Zscores of all patients in format: - # HMDB_code patientname1 patientname2 - names(dims_xls_ratios) <- gsub("HMDB.code", "HMDB_code", names(dims_xls_ratios)) - names(dims_xls_ratios) <- gsub("HMDB.name", "HMDB_name", names(dims_xls_ratios)) - - # for debugging: - write.table(dims_xls_ratios, file = paste0(output_dir, "/ratios.txt"), sep = "\t") - - # Select only the cols with zscores of the patients - zscore_patients <- dims_xls_ratios[, c(1, 2, zscore_cols[grep("P", colnames(dims_xls_ratios)[zscore_cols])])] - # Select only the cols with zscores of the controls - zscore_controls <- dims_xls_ratios[, c(1, 2, zscore_cols[grep("C", colnames(dims_xls_ratios)[zscore_cols])])] - } - - #### STEP 4: Run the IEM algorithm ######### - # in: algorithm, file_expected_biomarkers_iem, zscore_patients ||| out: prob_score (+file) - # algorithm taken from DOI: 10.3390/ijms21030979 - - if (algorithm == 1) { - # Load data - cat(paste0("\nloading expected file:\n -> ", file_expected_biomarkers_iem, "\n")) - expected_biomarkers <- read.csv(file_expected_biomarkers_iem, sep = ";", stringsAsFactors = FALSE) - # modify column names - names(expected_biomarkers) <- gsub("HMDB.code", "HMDB_code", names(expected_biomarkers)) - names(expected_biomarkers) <- gsub("Metabolite", "HMDB_name", names(expected_biomarkers)) - - # prepare dataframe scaffold rank_patients - rank_patients <- zscore_patients - # Fill df rank_patients with the ranks for each patient - for (patient_index in 3:ncol(zscore_patients)) { - # number of positive zscores in patient - pos <- sum(zscore_patients[, patient_index] > 0) - # sort the column on zscore; NB: this sorts the entire object, not just one column - rank_patients <- rank_patients[order(-rank_patients[patient_index]), ] - # Rank all positive zscores highest to lowest - rank_patients[1:pos, patient_index] <- as.numeric(ordered(-rank_patients[1:pos, patient_index])) - # Rank all negative zscores lowest to highest - rank_patients[(pos + 1):nrow(rank_patients), patient_index] <- as.numeric(ordered(rank_patients[(pos + 1): - nrow(rank_patients), patient_index])) - } - - # Calculate metabolite score, using the dataframes with only values, and later add the cols without values (1&2). - expected_zscores <- merge(x = expected_biomarkers, y = zscore_patients, by.x = c("HMDB_code"), by.y = c("HMDB_code")) - expected_zscores_original <- expected_zscores - - # determine which columns contain Z-scores and which contain disease info - select_zscore_cols <- grep("_Zscore", colnames(expected_zscores)) - select_info_cols <- 1:(min(select_zscore_cols) - 1) - # set some zscores to zero - select_incr_indisp <- which(expected_zscores$Change == "Increase" & expected_zscores$Dispensability == "Indispensable") - expected_zscores[select_incr_indisp, select_zscore_cols] <- lapply(expected_zscores[select_incr_indisp, - select_zscore_cols], function(x) ifelse (x <= 1.6, 0, x)) - select_decr_indisp <- which(expected_zscores$Change == "Decrease" & expected_zscores$Dispensability == "Indispensable") - expected_zscores[select_decr_indisp, select_zscore_cols] <- lapply(expected_zscores[select_decr_indisp, - select_zscore_cols], function(x) ifelse (x >= -1.2, 0, x)) - - # calculate rank score: - expected_ranks <- merge(x = expected_biomarkers, y = rank_patients, by.x = c("HMDB_code"), by.y = c("HMDB_code")) - rank_scores <- expected_zscores[order(expected_zscores$HMDB_code), select_zscore_cols] / - (expected_ranks[order(expected_ranks$HMDB_code), select_zscore_cols] * 0.9) - # combine disease info with rank scores - expected_metabscore <- cbind(expected_ranks[order(expected_zscores$HMDB_code), select_info_cols], rank_scores) - - # multiply weight score and rank score - weight_score <- expected_zscores - weight_score[, select_zscore_cols] <- expected_metabscore$Total_Weight * expected_metabscore[, select_zscore_cols] - - # sort table on Disease and Absolute_Weight - weight_score <- weight_score[order(weight_score$Disease, weight_score$Absolute_Weight, decreasing = TRUE), ] - - # select columns to check duplicates - dup <- weight_score[, c("Disease", "M.z")] - uni <- weight_score[!duplicated(dup) | !duplicated(dup, fromLast = FALSE), ] - - # calculate probability score - prob_score <- aggregate(uni[, select_zscore_cols], uni["Disease"], sum) - - # list of all diseases that have at least one metabolite Zscore at 0 - for (patient_index in 2:ncol(prob_score)) { - patient_zscore_colname <- colnames(prob_score)[patient_index] - matching_colname_expected <- which(colnames(expected_zscores) == patient_zscore_colname) - # determine which Zscores are 0 for this patient - zscores_zero <- which(expected_zscores[, matching_colname_expected] == 0) - # get Disease for these - disease_zero <- unique(expected_zscores[zscores_zero, "Disease"]) - # set the probability score of these diseases to 0 - prob_score[which(prob_score$Disease %in% disease_zero), patient_index] <- 0 - } - - # determine disease rank per patient - disease_rank <- prob_score - # rank diseases in decreasing order - disease_rank[2:ncol(disease_rank)] <- lapply(2:ncol(disease_rank), function(x) - as.numeric(ordered(-disease_rank[1:nrow(disease_rank), x]))) - # modify column names, Zscores have now been converted to probability scores - colnames(prob_score) <- gsub("_Zscore", "_prob_score", colnames(prob_score)) - colnames(disease_rank) <- gsub("_Zscore", "", colnames(disease_rank)) - - # Create conditional formatting for output Excel sheet. Colors according to values. - wb <- createWorkbook() - addWorksheet(wb, "Probability Scores") - writeData(wb, "Probability Scores", prob_score) - conditionalFormatting(wb, "Probability Scores", cols = 2:ncol(prob_score), rows = 1:nrow(prob_score), - type = "colourScale", style = c("white", "#FFFDA2", "red"), rule = c(1, 10, 100)) - saveWorkbook(wb, file = paste0(output_dir, "/dIEM_algoritme_output_", run_name, ".xlsx"), overwrite = TRUE) - # check whether prob_score df exists and has expected dimensions. - if (exists("expected_biomarkers") & (length(disease_rank) == length(prob_score))) { - cat("\n### Step 4 # Running the IEM algorithm is done.\n\n") + + # make violin plots per patient + for (patient_id in patients) { + # for category Diagnostics, make list of metabolites that exceed alarm values for this patient + # for category Other, make list of top highest and lowest Z-scores for this patient + if (grepl("Diagnost", pdf_dir)) { + top_metabs_patient <- prepare_alarmvalues(patient_id, dims_helix_table) } else { - cat("\n**** Error: Could not run IEM algorithm. Check if path to expected_biomarkers csv-file is correct. \n") + top_metabs_patient <- prepare_toplist(patient_id, zscore_patients) } - rm(wb) + # generate normal violin plots + create_pdf_violin_plots(pdf_dir, patient_id, metab_perpage, top_metabs_patient, explanation_violin_plot) } - #### STEP 5: Make violin plots ##### - # in: algorithm / zscore_patients, violin, nr_contr, nr_pat, Data, path_textfiles, zscore_cutoff, xaxis_cutoff, - # top_diseases, top_metab, output_dir ||| out: pdf file, Helix csv file - - if (violin == 1) { - - # preparation - zscore_patients_copy <- zscore_patients - colnames(zscore_patients) <- gsub("_Zscore", "", colnames(zscore_patients)) - colnames(zscore_controls) <- gsub("_Zscore", "", colnames(zscore_controls)) - - # Make patient list for violin plots - patient_list <- names(zscore_patients)[-c(1, 2)] - - # from table expected_biomarkers, choose selected columns - select_columns <- c("Disease", "HMDB_code", "HMDB_name") - #select_col_nrs <- which(colnames(expected_biomarkers) %in% select_columns) - expected_biomarkers_select <- expected_biomarkers %>% select(all_of(select_columns)) - # remove duplicates - expected_biomarkers_select <- expected_biomarkers_select[!duplicated(expected_biomarkers_select[, c(1, 2)]), ] - - # load file with explanatory information to be included in PDF. - explanation <- readLines(file_explanation) - - # first step: normal violin plots - # Find all text files in the given folder, which contain metabolite lists of which - # each file will be a page in the pdf with violin plots. - # Make a PDF file for each of the categories in metabolite_dirs - metabolite_dirs <- list.files(path = path_metabolite_groups, full.names = FALSE, recursive = FALSE) - for (metabolite_dir in metabolite_dirs) { - # create a directory for the output PDFs - pdf_dir <- paste(output_dir, metabolite_dir, sep = "/") - dir.create(pdf_dir, showWarnings = FALSE) - cat("making plots in category:", metabolite_dir, "\n") - - # get a list of all metabolite files - metabolite_files <- list.files(path = paste(path_metabolite_groups, metabolite_dir, sep = "/"), - pattern = "*.txt", full.names = FALSE, recursive = FALSE) - # put all metabolites into one list - metab_list_all <- list() - metab_list_names <- c() - cat("making plots from the input files:") - # open the text files and add each to a list of dataframes (metab_list_all) - for (file_index in seq_along(metabolite_files)) { - infile <- metabolite_files[file_index] - metab_list <- read.table(paste(path_metabolite_groups, metabolite_dir, infile, sep = "/"), - sep = "\t", header = TRUE, quote = "") - # put into list of all lists - metab_list_all[[file_index]] <- metab_list - metab_list_names <- c(metab_list_names, strsplit(infile, ".txt")[[1]][1]) - cat(paste0("\n", infile)) - } - # include list of classes in metabolite list - names(metab_list_all) <- metab_list_names - - # prepare list of metabolites; max nr_plots_perpage on one page - metab_interest_sorted <- prepare_data(metab_list_all, zscore_patients) - metab_interest_controls <- prepare_data(metab_list_all, zscore_controls) - metab_perpage <- prepare_data_perpage(metab_interest_sorted, metab_interest_controls, nr_plots_perpage, nr_pat, nr_contr) - - # for Diagnostics metabolites to be saved in Helix - if(grepl("Diagnost", pdf_dir)) { - # get table that combines DIMS results with stofgroepen/Helix table - dims_helix_table <- get_patient_data_to_helix(metab_interest_sorted, metab_list_all) - - # check if run contains Diagnostics patients (e.g. "P2024M"), not for research runs - if(any(is_diagnostic_patient(dims_helix_table$Patient))){ - # get output file for Helix - output_helix <- output_for_helix(protocol_name, dims_helix_table) - # write output to file - path_helixfile <- paste0(output_dir, "/output_Helix_", run_name,".csv") - write.csv(output_helix, path_helixfile, quote = F, row.names = F) - } - } - - # make violin plots per patient - for (pt_nr in 1:length(patient_list)) { - pt_name <- patient_list[pt_nr] - # for category Diagnostics, make list of metabolites that exceed alarm values for this patient - # for category Other, make list of top highest and lowest Z-scores for this patient - if (grepl("Diagnost", pdf_dir)) { - top_metab_pt <- prepare_alarmvalues(pt_name, dims_helix_table) - } else { - top_metab_pt <- prepare_toplist(pt_name, zscore_patients) - } - - # generate normal violin plots - create_violin_plots(pdf_dir, pt_name, metab_perpage, top_metab_pt) - - } - - } - - # Second step: dIEM plots in separate directory - diem_plot_dir <- paste(output_dir, "dIEM_plots", sep = "/") - dir.create(diem_plot_dir) - - # Select the metabolites that are associated with the top highest scoring IEM, for each patient - # disease_rank is from step 4: the dIEM algorithm. The lower the value, the more likely. - for (pt_nr in 1:length(patient_list)) { - pt_name <- patient_list[pt_nr] - # get top diseases for this patient - pt_colnr <- which(colnames(disease_rank) == pt_name) - pt_top_indices <- which(disease_rank[, pt_colnr] <= top_nr_iem) - pt_iems <- disease_rank[pt_top_indices, "Disease"] - pt_top_iems <- pt_prob_score_top_iems <- c() - for (single_iem in pt_iems) { - # get the probability score - prob_score_iem <- prob_score[which(prob_score$Disease == single_iem), pt_colnr] - # use only diseases for which probability score is above threshold - if (prob_score_iem >= threshold_iem) { - pt_top_iems <- c(pt_top_iems, single_iem) - pt_prob_score_top_iems <- c(pt_prob_score_top_iems, prob_score_iem) - } - } - - # prepare data for plotting dIEM violin plots - # If prob_score_top_iem is an empty list, don't make a plot - if (length(pt_top_iems) > 0) { - # Sorting from high to low, both prob_score_top_iems and pt_top_iems. - pt_prob_score_order <- order(-pt_prob_score_top_iems) - pt_prob_score_top_iems <- round(pt_prob_score_top_iems, 1) - pt_prob_score_top_iem_sorted <- pt_prob_score_top_iems[pt_prob_score_order] - pt_top_iem_sorted <- pt_top_iems[pt_prob_score_order] - # getting metabolites for each top_iem disease exactly like in metab_list_all - metab_iem_all <- list() - metab_iem_names <- c() - for (single_iem_index in 1:length(pt_top_iem_sorted)) { - single_iem <- pt_top_iem_sorted[single_iem_index] - single_prob_score <- pt_prob_score_top_iem_sorted[single_iem_index] - select_rows <- which(expected_biomarkers_select$Disease == single_iem) - metab_list <- expected_biomarkers_select[select_rows, ] - metab_iem_names <- c(metab_iem_names, paste0(single_iem, ", probability score ", single_prob_score)) - metab_list <- metab_list[, -1] - metab_iem_all[[single_iem_index]] <- metab_list - } - # put all metabolites into one list - names(metab_iem_all) <- metab_iem_names - - # get Zscore information from zscore_patients_copy, similar to normal violin plots - metab_iem_sorted <- prepare_data(metab_iem_all, zscore_patients_copy) - metab_iem_controls <- prepare_data(metab_iem_all, zscore_controls) - # make sure every page has 20 metabolites - diem_metab_perpage <- prepare_data_perpage(metab_iem_sorted, metab_iem_controls, nr_plots_perpage, nr_pat) - # add table of metabolites with increased or decreased Z-scores - top_metab_pt <- prepare_toplist(pt_name, zscore_patients) - - # generate dIEM violin plots - create_violin_plots(diem_plot_dir, pt_name, diem_metab_perpage, top_metab_pt) - - } else { - cat(paste0("\n\n**** This patient had no prob_scores higher than ", threshold_iem, ". - Therefore, this pdf was not made:\t ", pt_name, "_iem \n")) - } - - } +} +#### Run the IEM algorithm ######### +expected_biomarkers_df <- expected_biomarkers_df %>% rename(HMDB_code = HMDB.code, HMDB_name = Metabolite) + +diem_probability_score <- run_diem_algorithm(expected_biomarkers_df, zscore_patients_df, patients) + +save_prob_scores_to_Excel(diem_probability_score, output_dir, run_name) + + +#### Generate dIEM plots ######### +diem_plot_dir <- paste(output_dir, "dIEM_plots", sep = "/") +dir.create(diem_plot_dir) + +colnames(diem_probability_score) <- gsub("_Zscore", "", colnames(diem_probability_score)) +patient_no_iem <- c() + +for (patient_id in patients) { + # Select the top IEMs and filter on the IEM threshold + patient_top_iems_probs <- diem_probability_score %>% + select(c(Disease, !!sym(patient_id))) %>% + arrange(desc(!!sym(patient_id))) %>% + slice(1:top_number_iem_diseases) %>% + filter(!!sym(patient_id) >= threshold_iem) + + if (nrow(patient_top_iems_probs) > 0) { + top_iems <- patient_top_iems_probs %>% pull(Disease) + # Get the metabolites for each IEM and their probability + metabs_iems_names <- c() + metabs_iems <- lapply(top_iems, function(iem) { + iem_probablity <- patient_top_iems_probs %>% filter(Disease == iem) %>% pull(!!sym(patient_id)) + metabs_iems_names <- c(metabs_iems_names, paste0(iem, ", probability score ", iem_probablity)) + metab_iem <- expected_biomarkers_df %>% filter(Disease == iem) %>% select(HMDB_code, HMDB_name) + return(metab_iem) + }) + names(metabs_iems) <- metabs_iems_names + + # Get the Z-scores with metabolite information + metab_iem_sorted <- combine_metab_info_zscores(metabs_iems, zscore_patients_df) + metab_iem_controls <- combine_metab_info_zscores(metabs_iems, zscore_controls_df) + # Get a list of dataframes for each IEM + diem_metab_perpage <- prepare_data_perpage(metab_iem_sorted, metab_iem_controls, + nr_plots_perpage, nr_of_patients, nr_of_controls) + # Get a dataframe of the top metabolites + top_metabs_patient <- prepare_toplist(patient_id, zscore_patients_df) + + # Generate and save dIEM violin plots + create_pdf_violin_plots(diem_plot_dir, patient_id, diem_metab_perpage, top_metabs_patient, explanation_violin_plot) + + } else { + patient_no_iem <- c(patient_no_iem, patient_id) } } + +if (length(patient_no_iem) > 0) { + patient_no_iem <- c(paste0("The following patient(s) did not have dIEM probability scores higher than ", threshold_iem, " :"), + patient_no_iem) + write(file = paste0(output_dir, "missing_probability_scores.txt"), patient_no_iem) +} diff --git a/DIMS/GenerateViolinPlots.nf b/DIMS/GenerateViolinPlots.nf index 1c4b532d..ec65a2e9 100755 --- a/DIMS/GenerateViolinPlots.nf +++ b/DIMS/GenerateViolinPlots.nf @@ -18,11 +18,10 @@ process GenerateViolinPlots { script: """ - Rscript ${baseDir}/CustomModules/DIMS/GenerateViolinPlots.R $analysis_id $params.scripts_dir $params.zscore \ + Rscript ${baseDir}/CustomModules/DIMS/GenerateViolinPlots.R $analysis_id $params.export_scripts_dir \ $params.path_metabolite_groups \ $params.file_ratios_metabolites \ $params.file_expected_biomarkers_IEM \ - $params.file_explanation \ - $params.file_isomers + $params.file_explanation """ } diff --git a/DIMS/export/generate_violin_plots_functions.R b/DIMS/export/generate_violin_plots_functions.R new file mode 100644 index 00000000..b1855a7f --- /dev/null +++ b/DIMS/export/generate_violin_plots_functions.R @@ -0,0 +1,572 @@ +#' Getting the intensities for calculating ratio Z-scores +#' +#' @param ratios_metabs_df: dataframe with HMDB codes for the ratios (dataframe) +#' @param row_index: index of the row in the ratios_metabs_df (integer) +#' @param intensities_zscore_df: dataframe with intensities for each sample (dataframe) +#' @param fraction_side: either numerator or denominator, which side of the fraction (string) +#' @param intensity_cols: names of the columns that contain the intensities (string) +#' +#' @returns fraction_side_intensity: a vector of intensities (vector of integers) +get_intentities_for_ratios <- function(ratios_metabs_df, row_index, intensities_zscore_df, fraction_side, intensity_cols) { + fraction_side_hmdb_ids <- ratios_metabs_df[row_index, fraction_side] + if (grepl("plus", fraction_side_hmdb_ids)) { + fraction_side_hmdb_id_list <- strsplit(fraction_side_hmdb_ids, "plus")[[1]] + fraction_side_intensity_list <- intensities_zscore_df %>% filter(HMDB_code %in% fraction_side_hmdb_id_list) %>% + select(any_of(intensity_cols)) + fraction_side_intensity <- apply(fraction_side_intensity_list, 2, sum) + } else if(fraction_side_hmdb_ids == "one") { + fraction_side_intensity <- 1 + } else { + fraction_side_intensity <- intensities_zscore_df %>% filter(HMDB_code == fraction_side_hmdb_ids) %>% + select(any_of(intensity_cols)) + } + return(fraction_side_intensity) +} + +#' Get the sample IDs for columns that have Z-score and intensities +#' +#' @param colnames_zscore: vector of sample IDs from the dataframe containing Z-scores (vector of strings) +#' @param intensity_cols: vector of sample IDs form the dataframe containing intensities (vector of strings) +#' +#' @returns: vector of sample IDs that are in both input vectors (vector of strings) +get_zscore_columns <- function(colnames_zscore, intensity_cols) { + intersect(paste0(intensity_cols, "_Zscore"), grep("_Zscore", colnames_zscore, value = T)) +} + +#' Get a list with dataframes for all off the metabolite group in a directory +#' +#' @param metab_group_dir: directory containing txt files with metabolites per group (string) +#' +#' @returns: list with dataframes with info on metabolites (list of dataframes) +get_list_metabolites <- function(metab_group_dir) { + # get a list of all metabolite files + metabolite_files <- list.files(metab_group_dir, pattern = "*.txt", full.names = FALSE, recursive = FALSE) + # put all metabolites into one list + metab_list_all <- lapply(paste(metab_group_dir, metabolite_files, sep = "/"), + read.table, sep = "\t", header = TRUE, quote = "") + names(metab_list_all) <- gsub(".txt", "", metabolite_files) + + return(metab_list_all) +} + +#' Combine patient Z-scores with metabolite info +#' +#' @param metab_list_all: list of dataframes with metabolite information for different stofgroepen (list) +#' @param zscore_df: dataframe with metabolite Z-scores for all patient +#' +#' @return: list of dataframes for each stofgroep with data for each metabolite and patient/control per row +combine_metab_info_zscores <- function(metab_list_all, zscore_df) { + # remove HMDB_name column and "_Zscore" from column (patient) names + zscore_df <- zscore_df %>% select(-HMDB_name) %>% + rename_with(~ str_remove(.x, "_Zscore"), .cols = contains("_Zscore")) + + # put data into pages, max 20 violin plots per page in PDF + metab_interest_sorted <- list() + + for (metab_class in names(metab_list_all)) { + metab_df <- metab_list_all[[metab_class]] + # Select HMDB_code and HMDB_name columns + metab_df <- metab_df %>% select(HMDB_code, HMDB_name) + + # Change the HMDB_name column so all names have 45 characters + metab_df <- metab_df %>% mutate(HMDB_name = case_when( + str_length(HMDB_name) > 45 ~ str_c(str_sub(HMDB_name, 1, 42), "..."), + str_length(HMDB_name) < 45 ~ str_pad(HMDB_name, 45, side = "right", pad = " "), + TRUE ~ HMDB_name + )) + + # Join metabolite info with the Z-score dataframe + metab_interest <- metab_df %>% inner_join(zscore_df, by = "HMDB_code") %>% select(-HMDB_code) + + # put the data frame in long format + metab_interest_melt <- reshape2::melt(metab_interest, id.vars = "HMDB_name", variable.name = "Sample", + value.name = "Z_score") + # Add the dataframe sorted on HMDB_name to a list + metab_interest_sorted[[metab_class]] <- metab_interest_melt + } + + return(metab_interest_sorted) +} + +#' Combine patient and control data for each page of the violinplot pdf +#' +#' @param metab_interest_sorted: list of dataframes with data for each metabolite and patient (list) +#' @param metab_interest_contr: list of dataframes with data for each metabolite and control (list) +#' @param nr_plots_perpage: number of plots per page in the violinplot pdf (integer) +#' @param nr_pat: number of patients (integer) +#' @param nr_contr: number of controls (integer) +#' +#' @return: list of dataframes with metabolite Z-scores for each patient and control, +#' the length of list is the number of pages for the violinplot pdf (list) +prepare_data_perpage <- function(metab_interest_sorted, metab_interest_contr, nr_plots_perpage, nr_pat, nr_contr) { + metab_perpage <- list() + metab_category <- c() + + for (metab_class in names(metab_interest_sorted)) { + # Get the data for patients and controls for the metab_interest_sorted list + metab_sort_patients_df <- metab_interest_sorted[[metab_class]] + metab_sort_controls_df <- metab_interest_contr[[metab_class]] + + # Calculate the number of pages + nr_pages <- ceiling(length(unique(metab_sort_patients_df$HMDB_name)) / nr_plots_perpage) + + # Get all metabolites and create list with HMDB naames of max nr_plots_perpage long + metabolites <- unique(metab_sort_patients_df$HMDB_name) + metabolites_in_chunks <- split(metabolites, ceiling(seq_along(metabolites) / nr_plots_perpage)) + nr_chunks <- length(metabolites_in_chunks) + + current_perpage <- lapply(metabolites_in_chunks, function(metab_name) { + patients_df <- metab_sort_patients_df %>% filter(HMDB_name %in% metab_name) + controls_df <- metab_sort_controls_df %>% filter(HMDB_name %in% metab_name) + + # Combine both dataframes + combined_df <- rbind(patients_df, controls_df) + + # Add empty dummy's to extend the number of metabs to the nr_plots_perpage + n_missing <- nr_plots_perpage - length(metab_name) + if (n_missing > 0) { + dummy_names <- paste0(" ", strrep(" ", seq_len(n_missing))) + metab_order <- c(metab_name, dummy_names) + } else { + metab_order <- metab_name + } + attr(combined_df, "y_order") <- rev(metab_order) + + return(combined_df) + }) + # Add new items to main list + metab_perpage <- append(metab_perpage, current_perpage) + # create list of page headers + metab_category <- c(metab_category, paste(metab_class, seq(nr_chunks), sep = "_")) + } + # add page headers to list + names(metab_perpage) <- metab_category + + return(metab_perpage) +} + +#' Get patient data to be uploaded to Helix +#' +#' @param metab_interest_sorted: list of dataframes with metabolite Z-scores for each sample/patient (list) +#' @param metab_list_all: list of tables with metabolites for Helix and violin plots (list) +#' +#' @return: dataframe with patient data with only metabolites for Helix and violin plots +#' with Helix name, high/low Z-score cutoffs +get_patient_data_to_helix <- function(metab_interest_sorted, metab_list_all) { + # Combine Z-scores of metab groups together + df_all_metabs_zscores <- bind_rows(metab_interest_sorted) + + # Change the Sample column to characters, trim HMDB_name and split HMDB_name in new column + df_all_metabs_zscores <- df_all_metabs_zscores %>% + mutate(Sample = as.character(Sample), + HMDB_name = str_trim(HMDB_name, "right"), + HMDB_name_split = str_split_fixed(HMDB_name, "nitine;", 2)[, 1]) + + # Combine stofgroepen + dims_helix_table <- bind_rows(metab_list_all) + + # Filter for Helix metabolites and split HMDB_name column for matching with df_all_metabs_zscores + dims_helix_table <- dims_helix_table %>% + filter(Helix == "ja") %>% + mutate(HMDB_name_split = str_split_fixed(HMDB_name, "nitine;", 2)[, 1]) %>% + select(HMDB_name_split, Helix_naam, high_zscore, low_zscore) + + # Filter DIMS results for metabolites for Helix and combine Helix info + df_metabs_helix <- df_all_metabs_zscores %>% + filter(HMDB_name_split %in% dims_helix_table$HMDB_name_split) %>% + left_join(dims_helix_table, by = join_by(HMDB_name_split)) %>% + select(HMDB_name, Sample, Z_score, Helix_naam, high_zscore, low_zscore) + + return(df_metabs_helix) +} + +#' Check for Diagnostics patients with correct patient number (e.g. starting with "P2024M") +#' +#' @param patient_column: a column from dataframe with IDs (character vector) +#' +#' @return: a logical vector with TRUE or FALSE for each element (vector) +is_diagnostic_patient <- function(patient_column) { + diagnostic_patients <- grepl("^P[0-9]{4}M", patient_column) + + return(diagnostic_patients) +} + +#' Get the output dataframe for Helix +#' +#' @param protocol_name: protocol name (string) +#' @param df_metabs_helix: dataframe with metabolite Z-scores for patients (dataframe) +#' +#' @return: dataframe with patient metabolite Z-scores in correct format for Helix +output_for_helix <- function(protocol_name, df_metabs_helix) { + # Remove positive controls + df_metabs_helix <- df_metabs_helix %>% filter(is_diagnostic_patient(Sample)) + + # Add 'Vial' column, each patient has unique ID + df_metabs_helix <- df_metabs_helix %>% + group_by(Sample) %>% + mutate(Vial = cur_group_id()) %>% + ungroup() + + # Split patient number into labnummer and Onderzoeksnummer + df_metabs_helix <- add_lab_id_and_onderzoeksnummer(df_metabs_helix) + + # Add column with protocol name + df_metabs_helix$Protocol <- protocol_name + + # Change name Z_score and Helix_naam columns to Amount and Name + change_columns <- c(Amount = "Z_score", Name = "Helix_naam") + df_metabs_helix <- df_metabs_helix %>% rename(all_of(change_columns)) + + # Select only necessary columns and set them in correct order + df_metabs_helix <- df_metabs_helix %>% + select(c(Vial, labnummer, Onderzoeksnummer, Protocol, Name, Amount)) + + # Remove duplicate patient-metabolite combinations ("leucine + isoleucine + allo-isoleucin_Z-score" is added 3 times) + df_metabs_helix <- df_metabs_helix %>% + group_by(Onderzoeksnummer, Name) %>% + distinct() %>% + ungroup() + + return(df_metabs_helix) +} + +#' Adding labnummer and Onderzoeksnummer to a dataframe +#' +#' @param df_metabs_helix: dataframe with patient data to be uploaded to Helix +#' +#' @return: dataframe with added labnummer and Onderzoeksnummer columns +add_lab_id_and_onderzoeksnummer <- function(df_metabs_helix) { + # Split patient number into labnummer and Onderzoeksnummer + for (row in 1:nrow(df_metabs_helix)) { + df_metabs_helix[row, "labnummer"] <- gsub("^P|\\.[0-9]*", "", df_metabs_helix[row, "Sample"]) + labnummer_split <- strsplit(as.character(df_metabs_helix[row, "labnummer"]), "M")[[1]] + df_metabs_helix[row, "Onderzoeksnummer"] <- paste0("MB", labnummer_split[1], "/", labnummer_split[2]) + } + + return(df_metabs_helix) +} + +#' Create a dataframe with all metabolites that exceed the min and max Z-score cutoffs +#' +#' @param patient_name: patient code (string) +#' @param dims_helix_table: dataframe with metabolite Z-scores for each patient and Helix info (dataframe) +#' +#' @return: dataframe with metabolites that exceed the min and max Z-score cutoffs for the selected patient +prepare_alarmvalues <- function(patient_name, dims_helix_table) { + # extract data for patient of interest (patient_name) + patient_metabs_helix <- dims_helix_table %>% + filter(Sample == patient_name) %>% + mutate(Z_score = round(Z_score, 2)) + + patient_high_df <- patient_metabs_helix %>% filter(Z_score > high_zscore) + patient_low_df <- patient_metabs_helix %>% filter(Z_score < low_zscore) + + # sort tables on zscore + patient_high_df <- patient_high_df %>% arrange(desc(Z_score)) + patient_low_df <- patient_low_df %>% arrange(Z_score) + # add lines for increased, decreased + extra_line1 <- c("Increased", "") + extra_line2 <- c("Decreased", "") + + # combine the two lists + top_metab_patient <- rbind(extra_line1, patient_high_df, extra_line2, patient_low_df) + top_metab_patient <- top_metab_patient %>% select(c(HMDB_name, Z_score)) + # remove row names + rownames(top_metab_patient) <- NULL + # change column names for display + colnames(top_metab_patient) <- c("Metabolite", "Z-score") + + return(top_metab_patient) +} + +#' Create a dataframe with the top 20 highest and top 10 lowest metabolites per patient +#' +#' @param pt_name: patient code (string) +#' @param zscore_patients: dataframe with metabolite Z-scores per patient (dataframe) +#' @param top_highest: the number of metabolites with the highest Z-score to display in the table (numeric) +#' @param top_lowest: the number of metabolites with the lowest Z-score to display in the table (numeric) +#' +#' @return: dataframe with 30 metabolites and Z-scores (dataframe) +prepare_toplist <- function(patient_id, zscore_patients) { + top_highest <- 20 + top_lowest <- 10 + patient_df <- zscore_patients %>% + select(c(HMDB_code, HMDB_name, all_of(patient_id))) %>% + arrange(desc(across(patient_id))) + + # Get lowest Zscores + patient_df_low <- patient_df[1:top_lowest, ] + patient_df_low <- patient_df_low %>% mutate(across(patient_id, ~ round(.x ,2))) + + # Get highest Zscores + patient_df_high <- patient_df[nrow(patient_df):(nrow(patient_df) - top_highest + 1), ] + patient_df_high <- patient_df_high %>% mutate(across(patient_id, ~ round(.x ,2))) + + # add lines for increased, decreased + extra_line1 <- c("Increased", "", "") + extra_line2 <- c("Decreased", "", "") + top_metab_pt <- rbind(extra_line1, patient_df_high, extra_line2, patient_df_high) + # remove row names + rownames(top_metab_pt) <- NULL + + # change column names for display + colnames(top_metab_pt) <- c("HMDB_ID", "Metabolite", "Z-score") + + return(top_metab_pt) +} + +#' Create a pdf with table with metabolites and violin plots +#' +#' @param pdf_dir: location where to save the pdf file (string) +#' @param patient_id: patient id (string) +#' @param metab_perpage: list of dataframes, each dataframe contains data for a page in de pdf (list) +#' @param top_metab_pt: dataframe with increased and decreased metabolites for this patient (dataframe) +#' @param explanation: text that explains the violin plots and the pipeline version (string) +create_pdf_violin_plots <- function(pdf_dir, patient_id, metab_perpage, top_metab_pt, explanation) { + # set parameters for plots + plot_height <- 9.6 + plot_width <- 6 + + # patient plots, create the PDF device + patient_id_sub <- patient_id + suffix <- "" + if (grepl("Diagnostics", pdf_dir) & is_diagnostic_patient(patient_id)) { + prefix <- "MB" + suffix <- "_DIMS_PL_DIAG" + # substitute P and M in P2020M00001 into right format for Helix + patient_id_sub <- gsub("[PM]", "", patient_id) + patient_id_sub <- gsub("\\..*", "", patient_id_sub) + } else if (grepl("Diagnostics", pdf_dir)) { + prefix <- "Dx_" + } else if (grepl("IEM", pdf_dir)) { + prefix <- "IEM_" + } else { + prefix <- "R_" + } + + pdf(paste0(pdf_dir, "/", prefix, patient_id_sub, suffix, ".pdf"), + onefile = TRUE, + width = plot_width, + height = plot_height) + + # page headers: + page_headers <- names(metab_perpage) + + # put table into PDF file, if not empty + if (!is.null(dim(top_metab_pt))) { + max_rows_per_page <- 35 + total_rows <- nrow(top_metab_pt) + number_of_pages <- ceiling(total_rows / max_rows_per_page) + + # get the names and numbers in the table aligned + table_theme <- ttheme_default(core = list(fg_params = list(hjust = 0, x = 0.05, fontsize = 6)), + colhead = list(fg_params = list(fontsize = 8, fontface = "bold"))) + + for (page in seq(number_of_pages)) { + start_row <- (page - 1) * max_rows_per_page + 1 + end_row <- min(page * max_rows_per_page, total_rows) + page_data <- top_metab_pt[start_row:end_row, ] + + table_grob <- tableGrob(page_data, theme = table_theme, rows = NULL) + + grid.arrange( + table_grob, + top = paste0("Top deviating metabolites for patient: ", patient_id) + ) + } + } + + # violin plots + for (metab_class in names(metab_perpage)) { + # extract list of metabolites to plot on a page + metab_zscores_df <- metab_perpage[[metab_class]] + # extract original data for patient of interest (pt_name) before cut-offs + patient_zscore_df <- metab_zscores_df %>% filter(Sample == patient_id) + + # Remove patient column and change Z-score. If under -5 to -5 and if above 20 to 20. + metab_zscores_df <- metab_zscores_df %>% + filter(Sample != patient_id) %>% + mutate(Z_score = pmin(pmax(Z_score, -5), 20)) + + # subtitle per page + sub_perpage <- gsub("_", " ", metab_class) + # for IEM plots, put subtitle on two lines + sub_perpage <- gsub("probability", "\nprobability", sub_perpage) + + # draw violin plot. + ggplot_object <- create_violin_plot(metab_zscores_df, patient_zscore_df, sub_perpage, patient_id) + + suppressWarnings(print(ggplot_object)) + } + + # add explanation of violin plots, version number etc. + plot(NA, xlim = c(0, 5), ylim = c(0, 5), bty = "n", xaxt = "n", yaxt = "n", xlab = "", ylab = "") + if (length(explanation) > 0) { + text(0.2, 5, explanation[1], pos = 4, cex = 0.8) + for (line_index in 2:length(explanation)) { + text_y_position <- 5 - (line_index * 0.2) + text(-0.2, text_y_position, explanation[line_index], pos = 4, cex = 0.5) + } + } + + # close the PDF file + dev.off() +} + +#' Create violin plots +#' +#' @param metab_zscores_df: dataframe with Z-scores for all samples (dataframe) +#' @param patient_zscore_df: dataframe with Z-scores for the specified patient (dataframe) +#' @param sub_perpage: subtitle of the page (string) +#' @param patient_id: the patient id of the selected patient (string) +#' +#' @returns +create_violin_plot <- function(metab_zscores_df, patient_zscore_df, sub_perpage, patient_id) { + fontsize <- 1 + circlesize <- 0.8 + # Set colors for the violinplot: green, blue, blue/purple, purple, orange, red + colors_plot <- c("#22E4AC", "#00B0F0", "#504FFF", "#A704FD", "#F36265", "#DA0641") + + y_order <- attr(metab_zscores_df, "y_order") + metab_zscores_df$HMDB_name <- rev(factor(metab_zscores_df$HMDB_name, levels = rev(y_order))) + patient_zscore_df$HMDB_name <- rev(factor(patient_zscore_df$HMDB_name, levels = rev(y_order))) + + ggplot_object <- ggplot(metab_zscores_df, aes(x = Z_score, y = HMDB_name)) + + # Make violin plots + geom_violin(scale = "width", na.rm = TRUE) + + # Add Z-score for the selected patient, shape=22 gives square for patient of interest + geom_point(data = patient_zscore_df, aes(color = Z_score), + size = 3.5 * circlesize, shape = 22, fill = "white", na.rm = TRUE) + + # Add the Z-score at the right side of the plot + geom_text( + data = patient_zscore_df, + aes(16, label = paste0("Z=", round(Z_score, 2))), + hjust = "left", vjust = +0.2, size = 3, na.rm = TRUE) + + # Set colour for the Z-score of the selected patient + scale_fill_gradientn( + colors = colors_plot, values = NULL, space = "Lab", na.value = "grey50", guide = "colourbar", + aesthetics = "colour" + ) + + # Add labels to the axis + labs(x = "Z-scores", y = "Metabolites", subtitle = sub_perpage, color = "z-score") + + # Add a title to the page + ggtitle(label = paste0("Results for patient ", patient_id)) + + # Set theme: size and font type of y-axis labels, remove legend and make the + theme( + axis.text.y = element_text(family = "Courier", size = 6), + legend.position = "none", + plot.caption = element_text(size = rel(fontsize)) + ) + + # Set y-axis to set order + scale_y_discrete(limits = y_order) + + # Limit the x-axis to between -5 and 20 + xlim(-5, 20) + + # Set grey vertical lines at -2 and 2 + geom_vline(xintercept = c(-2, 2), col = "grey", lwd = 0.5, lty = 2) + + + return(ggplot_object) +} + +#' Run the dIEM algorithm (DOI: 10.3390/ijms21030979) +#' +#' @param expected_biomarkers_df: table with information for HMDB codes about IEMs (dataframe) +#' @param zscore_patients: dataframe containing Z-scores for patient (dataframe) +#' +#' @returns probability_score: a dataframe with probability scores for IEMs for each patient (dataframe) +run_diem_algorithm <- function(expected_biomarkers_df, zscore_patients_df, sample_cols) { + # Rank the metabolites for each patient individually + ranking_patients <- zscore_patients_df %>% + mutate(across(-c(HMDB_code, HMDB_name), rank_patient_zscores)) + + ranking_patients <- merge(x = expected_biomarkers_df, y = ranking_patients, + by.x = c("HMDB_code"), by.y = c("HMDB_code")) + + zscore_expected_df <- merge(x = expected_biomarkers_df, y = zscore_patients_df, + by.x = c("HMDB_code"), by.y = c("HMDB_code")) + + # Change Z-score to zero for specific cases + zscore_expected_df <- zscore_expected_df %>% mutate(across( + all_of(sample_cols), + ~ case_when( + Change == "Increase" & Dispensability == "Indispensable" & .x <= 1.6 ~ 0, + Change == "Decrease" & Dispensability == "Indispensable" & .x >= -1.2 ~ 0, + TRUE ~ .x + ) + )) + + # Sort both dataframes on HMDB_code for calculating the metabolite score + zscore_expected_df <- zscore_expected_df[order(zscore_expected_df$HMDB_code), ] + ranking_patients <- ranking_patients[order(ranking_patients$HMDB_code), ] + + # Set up dataframe for the metabolite score, copy zscore_expected_df for biomarker info + metabolite_score_info <- zscore_expected_df + # Calculate metabolite score: Z-score/(Rank * 0.9) + metabolite_score_info[sample_cols] <- zscore_expected_df[sample_cols] / (ranking_patients[sample_cols] * 0.9) + + # Calculate the weighted score: metabolite_score * Total_Weight + metabolite_weight_score <- metabolite_score_info %>% + mutate(across( + all_of(sample_cols), + ~ .x * Total_Weight + )) + + #TODO: dit klopt nu niet, checken dat alleen de eerste waarde wordt gebruikt in orginele dIEM algoritme + # Calculate the probability score for each disease - Mz combination + probability_score <- metabolite_weight_score %>% + group_by(Disease, M.z) %>% + summarise(across( + all_of(sample_cols), + ~ sum(.x, na.rm = TRUE) + ), .groups = "drop") + + # Set probability score to 0 for Z-scores == 0 + for (sample_col in sample_cols) { + # Get indexes of Zscore that equal 0 + zscores_zero_idx <- which(zscore_expected_df[[sample_col]] == 0) + # Get diseases that have a Zscore of 0 + diseases_zero <- unique(zscore_expected_df[zscores_zero_idx, "Disease"]) + # Set probabilty of these diseases to 0 + probability_score[probability_score$Disease %in% diseases_zero, sample_col] <- 0 + } + + colnames(probability_score) <- gsub("_Zscore", "_prob_score", colnames(probability_score)) + + return(probability_score) +} + +#' Ranking Z-scores for a patient, separate for positive and negative Z-scores +#' +#' @param zscore_col: vector with Z-scores for a single patient (vector of integers) +#' +#' @returns ranking: a vector of the ranking of the Z-scores (vector of integers) +rank_patient_zscores <- function(zscore_col) { + # Create ranking column with default NA values + ranking <- rep(NA_real_, length(zscore_col)) + + # Get indexes for negative and positive rows + neg_indexes <- which(zscore_col <= 0) + pos_indexes <- which(zscore_col > 0) + + # Rank the negative and positive Zscores + ranking[neg_indexes] <- dense_rank(zscore_col[neg_indexes]) + ranking[pos_indexes] <- dense_rank(-zscore_col[pos_indexes]) + + return(ranking) +} + +#' Save the probability score dataframe as an Excel file +#' +#' @param probability_score: a dataframe containing probability scores for each patient (dataframe) +#' @param output_dir: location where to save the Excel file (string) +#' @param run_name: name of the run, for the file name (string) +save_prob_scores_to_Excel <- function(probability_score, output_dir, run_name) { + # Create conditional formatting for output Excel sheet. Colors according to values. + wb <- createWorkbook() + addWorksheet(wb, "Probability Scores") + writeData(wb, "Probability Scores", probability_score) + conditionalFormatting(wb, "Probability Scores", cols = 2:ncol(probability_score), rows = 1:nrow(probability_score), + type = "colourScale", style = c("white", "#FFFDA2", "red"), rule = c(1, 10, 100)) + saveWorkbook(wb, file = paste0(output_dir, "/dIEM_algoritme_output_", run_name, ".xlsx"), overwrite = TRUE) + rm(wb) +} From 9ffd606737ba8606a0e4bbe710d86508c9b2ed46 Mon Sep 17 00:00:00 2001 From: ALuesink Date: Fri, 15 Aug 2025 16:12:31 +0200 Subject: [PATCH 02/14] Fixed errors --- DIMS/GenerateViolinPlots.R | 2 +- DIMS/export/generate_violin_plots_functions.R | 43 +++++++++++-------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/DIMS/GenerateViolinPlots.R b/DIMS/GenerateViolinPlots.R index 2e6cb885..67f94b17 100644 --- a/DIMS/GenerateViolinPlots.R +++ b/DIMS/GenerateViolinPlots.R @@ -143,7 +143,7 @@ for (metabolite_dir in metabolite_dirs) { if (grepl("Diagnost", pdf_dir)) { top_metabs_patient <- prepare_alarmvalues(patient_id, dims_helix_table) } else { - top_metabs_patient <- prepare_toplist(patient_id, zscore_patients) + top_metabs_patient <- prepare_toplist(patient_id, zscore_patients_df) } # generate normal violin plots diff --git a/DIMS/export/generate_violin_plots_functions.R b/DIMS/export/generate_violin_plots_functions.R index b1855a7f..beb0ddb9 100644 --- a/DIMS/export/generate_violin_plots_functions.R +++ b/DIMS/export/generate_violin_plots_functions.R @@ -30,7 +30,8 @@ get_intentities_for_ratios <- function(ratios_metabs_df, row_index, intensities_ #' #' @returns: vector of sample IDs that are in both input vectors (vector of strings) get_zscore_columns <- function(colnames_zscore, intensity_cols) { - intersect(paste0(intensity_cols, "_Zscore"), grep("_Zscore", colnames_zscore, value = T)) + sample_intersect <- intersect(paste0(intensity_cols, "_Zscore"), grep("_Zscore", colnames_zscore, value = TRUE)) + return(sample_intersect) } #' Get a list with dataframes for all off the metabolite group in a directory @@ -261,16 +262,18 @@ prepare_alarmvalues <- function(patient_name, dims_helix_table) { patient_high_df <- patient_metabs_helix %>% filter(Z_score > high_zscore) patient_low_df <- patient_metabs_helix %>% filter(Z_score < low_zscore) - # sort tables on zscore - patient_high_df <- patient_high_df %>% arrange(desc(Z_score)) - patient_low_df <- patient_low_df %>% arrange(Z_score) + if (nrow(patient_high_df) > 0 | nrow(patient_low_df) > 0) { + # sort tables on zscore + patient_high_df <- patient_high_df %>% arrange(desc(Z_score)) %>% select(c(HMDB_name, Z_score)) + patient_low_df <- patient_low_df %>% arrange(Z_score) %>% select(c(HMDB_name, Z_score)) + } # add lines for increased, decreased extra_line1 <- c("Increased", "") extra_line2 <- c("Decreased", "") # combine the two lists top_metab_patient <- rbind(extra_line1, patient_high_df, extra_line2, patient_low_df) - top_metab_patient <- top_metab_patient %>% select(c(HMDB_name, Z_score)) + # remove row names rownames(top_metab_patient) <- NULL # change column names for display @@ -291,21 +294,21 @@ prepare_toplist <- function(patient_id, zscore_patients) { top_highest <- 20 top_lowest <- 10 patient_df <- zscore_patients %>% - select(c(HMDB_code, HMDB_name, all_of(patient_id))) %>% - arrange(desc(across(patient_id))) + select(HMDB_code, HMDB_name, !!sym(patient_id)) %>% + arrange(!!sym(patient_id)) # Get lowest Zscores patient_df_low <- patient_df[1:top_lowest, ] - patient_df_low <- patient_df_low %>% mutate(across(patient_id, ~ round(.x ,2))) + patient_df_low <- patient_df_low %>% mutate(across(!!sym(patient_id), ~ round(.x ,2))) # Get highest Zscores patient_df_high <- patient_df[nrow(patient_df):(nrow(patient_df) - top_highest + 1), ] - patient_df_high <- patient_df_high %>% mutate(across(patient_id, ~ round(.x ,2))) + patient_df_high <- patient_df_high %>% mutate(across(!!sym(patient_id), ~ round(.x ,2))) # add lines for increased, decreased extra_line1 <- c("Increased", "", "") extra_line2 <- c("Decreased", "", "") - top_metab_pt <- rbind(extra_line1, patient_df_high, extra_line2, patient_df_high) + top_metab_pt <- rbind(extra_line1, patient_df_high, extra_line2, patient_df_low) # remove row names rownames(top_metab_pt) <- NULL @@ -420,7 +423,7 @@ create_pdf_violin_plots <- function(pdf_dir, patient_id, metab_perpage, top_meta #' @param sub_perpage: subtitle of the page (string) #' @param patient_id: the patient id of the selected patient (string) #' -#' @returns +#' @returns ggpplot_object: a violin plot of metabolites that highlights the selected patient (ggplot object) create_violin_plot <- function(metab_zscores_df, patient_zscore_df, sub_perpage, patient_id) { fontsize <- 1 circlesize <- 0.8 @@ -509,16 +512,18 @@ run_diem_algorithm <- function(expected_biomarkers_df, zscore_patients_df, sampl mutate(across( all_of(sample_cols), ~ .x * Total_Weight - )) + )) %>% + arrange(desc(Disease), desc(Absolute_Weight)) - #TODO: dit klopt nu niet, checken dat alleen de eerste waarde wordt gebruikt in orginele dIEM algoritme # Calculate the probability score for each disease - Mz combination - probability_score <- metabolite_weight_score %>% - group_by(Disease, M.z) %>% - summarise(across( - all_of(sample_cols), - ~ sum(.x, na.rm = TRUE) - ), .groups = "drop") + probability_score <- metabolite_weight_score %>% + filter( + !duplicated(select(., Disease, M.z)) | + !duplicated(select(., Disease, M.z), fromLast = FALSE) + ) %>% + group_by(Disease) %>% + summarise(across(all_of(sample_cols), sum), .groups = "drop") + # Set probability score to 0 for Z-scores == 0 for (sample_col in sample_cols) { From aede6ee53a197286609bda7937f7b812c3314717 Mon Sep 17 00:00:00 2001 From: ALuesink Date: Thu, 21 Aug 2025 12:13:54 +0200 Subject: [PATCH 03/14] Fixed linting --- DIMS/GenerateViolinPlots.R | 43 ++-- DIMS/export/generate_violin_plots_functions.R | 222 +++++++++--------- 2 files changed, 130 insertions(+), 135 deletions(-) diff --git a/DIMS/GenerateViolinPlots.R b/DIMS/GenerateViolinPlots.R index 67f94b17..847c4cb5 100644 --- a/DIMS/GenerateViolinPlots.R +++ b/DIMS/GenerateViolinPlots.R @@ -38,7 +38,7 @@ protocol_name <- "DIMS_PL_DIAG" # Remove columns, move HMDB_code & HMDB_name column to the front, change intensity columns to numeric intensities_zscore_df <- intensities_zscore_df %>% - select(-c(plots, HMDB_name_all, HMDB_ID_all, sec_HMDB_ID, HMDB_key, sec_HMBD_ID_rlvnc, name, + select(-c(plots, HMDB_name_all, HMDB_ID_all, sec_HMDB_ID, HMDB_key, sec_HMBD_ID_rlvnc, name, relevance, descr, origin, fluids, tissue, disease, pathway, nr_ctrls)) %>% relocate(c(HMDB_code, HMDB_name)) %>% rename(mean_controls = avg_ctrls, sd_controls = sd_ctrls) %>% @@ -70,11 +70,11 @@ colnames(ratio_zscore_df) <- colnames(intensities_zscore_df) ratio_zscore_df$HMDB_code <- ratios_metabs_df$HMDB.code ratio_zscore_df$HMDB_name <- ratios_metabs_df$Ratio_name -for (row_index in 1:nrow(ratios_metabs_df)) { - numerator_intensities <- get_intentities_for_ratios(ratios_metabs_df, row_index, - intensities_zscore_df, "HMDB_numerator", intensity_cols) - denominator_intensities <- get_intentities_for_ratios(ratios_metabs_df, row_index, - intensities_zscore_df, "HMDB_denominator", intensity_cols) +for (row_index in seq_len(nrow(ratios_metabs_df))) { + numerator_intensities <- get_intentities_for_ratios(ratios_metabs_df, row_index, + intensities_zscore_df, "HMDB_numerator", intensity_cols) + denominator_intensities <- get_intentities_for_ratios(ratios_metabs_df, row_index, + intensities_zscore_df, "HMDB_denominator", intensity_cols) # calculate intensity ratios ratio_zscore_df[row_index, intensity_cols_index] <- log2(numerator_intensities / denominator_intensities) } @@ -103,8 +103,8 @@ colnames(zscore_controls_df) <- gsub("_Zscore", "", colnames(zscore_controls_df) expected_biomarkers_df <- expected_biomarkers_df %>% rename(HMDB_code = HMDB.code, HMDB_name = Metabolite) -expected_biomarkers_info <- expected_biomarkers_df %>% - select(c(Disease, HMDB_code, HMDB_name)) %>% +expected_biomarkers_info <- expected_biomarkers_df %>% + select(c(Disease, HMDB_code, HMDB_name)) %>% distinct(Disease, HMDB_code, .keep_all = TRUE) metabolite_dirs <- list.files(path = path_metabolite_groups, full.names = FALSE, recursive = FALSE) @@ -122,20 +122,20 @@ for (metabolite_dir in metabolite_dirs) { nr_plots_perpage, nr_of_patients, nr_of_controls) # for Diagnostics metabolites to be saved in Helix - if(grepl("Diagnost", pdf_dir)) { + if (grepl("Diagnost", pdf_dir)) { # get table that combines DIMS results with stofgroepen/Helix table dims_helix_table <- get_patient_data_to_helix(metab_interest_sorted, metab_list_all) - + # check if run contains Diagnostics patients (e.g. "P2024M"), not for research runs - if(any(is_diagnostic_patient(dims_helix_table$Sample))){ + if (any(is_diagnostic_patient(dims_helix_table$Sample))) { # get output file for Helix output_helix <- output_for_helix(protocol_name, dims_helix_table) # write output to file - path_helixfile <- paste0(output_dir, "output_Helix_", run_name,".csv") - write.csv(output_helix, path_helixfile, quote = F, row.names = F) + path_helixfile <- paste0(output_dir, "output_Helix_", run_name, ".csv") + write.csv(output_helix, path_helixfile, quote = FALSE, row.names = FALSE) } } - + # make violin plots per patient for (patient_id in patients) { # for category Diagnostics, make list of metabolites that exceed alarm values for this patient @@ -157,7 +157,7 @@ expected_biomarkers_df <- expected_biomarkers_df %>% rename(HMDB_code = HMDB.cod diem_probability_score <- run_diem_algorithm(expected_biomarkers_df, zscore_patients_df, patients) -save_prob_scores_to_Excel(diem_probability_score, output_dir, run_name) +save_prob_scores_to_excel(diem_probability_score, output_dir, run_name) #### Generate dIEM plots ######### @@ -174,7 +174,7 @@ for (patient_id in patients) { arrange(desc(!!sym(patient_id))) %>% slice(1:top_number_iem_diseases) %>% filter(!!sym(patient_id) >= threshold_iem) - + if (nrow(patient_top_iems_probs) > 0) { top_iems <- patient_top_iems_probs %>% pull(Disease) # Get the metabolites for each IEM and their probability @@ -186,26 +186,27 @@ for (patient_id in patients) { return(metab_iem) }) names(metabs_iems) <- metabs_iems_names - + # Get the Z-scores with metabolite information metab_iem_sorted <- combine_metab_info_zscores(metabs_iems, zscore_patients_df) metab_iem_controls <- combine_metab_info_zscores(metabs_iems, zscore_controls_df) # Get a list of dataframes for each IEM diem_metab_perpage <- prepare_data_perpage(metab_iem_sorted, metab_iem_controls, nr_plots_perpage, nr_of_patients, nr_of_controls) - # Get a dataframe of the top metabolites + # Get a dataframe of the top metabolites top_metabs_patient <- prepare_toplist(patient_id, zscore_patients_df) - + # Generate and save dIEM violin plots create_pdf_violin_plots(diem_plot_dir, patient_id, diem_metab_perpage, top_metabs_patient, explanation_violin_plot) - + } else { patient_no_iem <- c(patient_no_iem, patient_id) } } if (length(patient_no_iem) > 0) { - patient_no_iem <- c(paste0("The following patient(s) did not have dIEM probability scores higher than ", threshold_iem, " :"), + patient_no_iem <- c(paste0("The following patient(s) did not have dIEM probability scores higher than ", + threshold_iem, " :"), patient_no_iem) write(file = paste0(output_dir, "missing_probability_scores.txt"), patient_no_iem) } diff --git a/DIMS/export/generate_violin_plots_functions.R b/DIMS/export/generate_violin_plots_functions.R index beb0ddb9..0ae7edff 100644 --- a/DIMS/export/generate_violin_plots_functions.R +++ b/DIMS/export/generate_violin_plots_functions.R @@ -11,13 +11,15 @@ get_intentities_for_ratios <- function(ratios_metabs_df, row_index, intensities_ fraction_side_hmdb_ids <- ratios_metabs_df[row_index, fraction_side] if (grepl("plus", fraction_side_hmdb_ids)) { fraction_side_hmdb_id_list <- strsplit(fraction_side_hmdb_ids, "plus")[[1]] - fraction_side_intensity_list <- intensities_zscore_df %>% filter(HMDB_code %in% fraction_side_hmdb_id_list) %>% + fraction_side_intensity_list <- intensities_zscore_df %>% + filter(HMDB_code %in% fraction_side_hmdb_id_list) %>% select(any_of(intensity_cols)) fraction_side_intensity <- apply(fraction_side_intensity_list, 2, sum) - } else if(fraction_side_hmdb_ids == "one") { + } else if (fraction_side_hmdb_ids == "one") { fraction_side_intensity <- 1 } else { - fraction_side_intensity <- intensities_zscore_df %>% filter(HMDB_code == fraction_side_hmdb_ids) %>% + fraction_side_intensity <- intensities_zscore_df %>% + filter(HMDB_code == fraction_side_hmdb_ids) %>% select(any_of(intensity_cols)) } return(fraction_side_intensity) @@ -43,10 +45,10 @@ get_list_metabolites <- function(metab_group_dir) { # get a list of all metabolite files metabolite_files <- list.files(metab_group_dir, pattern = "*.txt", full.names = FALSE, recursive = FALSE) # put all metabolites into one list - metab_list_all <- lapply(paste(metab_group_dir, metabolite_files, sep = "/"), + metab_list_all <- lapply(paste(metab_group_dir, metabolite_files, sep = "/"), read.table, sep = "\t", header = TRUE, quote = "") names(metab_list_all) <- gsub(".txt", "", metabolite_files) - + return(metab_list_all) } @@ -58,34 +60,35 @@ get_list_metabolites <- function(metab_group_dir) { #' @return: list of dataframes for each stofgroep with data for each metabolite and patient/control per row combine_metab_info_zscores <- function(metab_list_all, zscore_df) { # remove HMDB_name column and "_Zscore" from column (patient) names - zscore_df <- zscore_df %>% select(-HMDB_name) %>% + zscore_df <- zscore_df %>% + select(-HMDB_name) %>% rename_with(~ str_remove(.x, "_Zscore"), .cols = contains("_Zscore")) - + # put data into pages, max 20 violin plots per page in PDF metab_interest_sorted <- list() - + for (metab_class in names(metab_list_all)) { metab_df <- metab_list_all[[metab_class]] # Select HMDB_code and HMDB_name columns metab_df <- metab_df %>% select(HMDB_code, HMDB_name) - + # Change the HMDB_name column so all names have 45 characters metab_df <- metab_df %>% mutate(HMDB_name = case_when( str_length(HMDB_name) > 45 ~ str_c(str_sub(HMDB_name, 1, 42), "..."), str_length(HMDB_name) < 45 ~ str_pad(HMDB_name, 45, side = "right", pad = " "), TRUE ~ HMDB_name )) - + # Join metabolite info with the Z-score dataframe metab_interest <- metab_df %>% inner_join(zscore_df, by = "HMDB_code") %>% select(-HMDB_code) - + # put the data frame in long format - metab_interest_melt <- reshape2::melt(metab_interest, id.vars = "HMDB_name", variable.name = "Sample", + metab_interest_melt <- reshape2::melt(metab_interest, id.vars = "HMDB_name", variable.name = "Sample", value.name = "Z_score") # Add the dataframe sorted on HMDB_name to a list metab_interest_sorted[[metab_class]] <- metab_interest_melt } - + return(metab_interest_sorted) } @@ -102,27 +105,27 @@ combine_metab_info_zscores <- function(metab_list_all, zscore_df) { prepare_data_perpage <- function(metab_interest_sorted, metab_interest_contr, nr_plots_perpage, nr_pat, nr_contr) { metab_perpage <- list() metab_category <- c() - + for (metab_class in names(metab_interest_sorted)) { # Get the data for patients and controls for the metab_interest_sorted list metab_sort_patients_df <- metab_interest_sorted[[metab_class]] metab_sort_controls_df <- metab_interest_contr[[metab_class]] - + # Calculate the number of pages nr_pages <- ceiling(length(unique(metab_sort_patients_df$HMDB_name)) / nr_plots_perpage) - + # Get all metabolites and create list with HMDB naames of max nr_plots_perpage long metabolites <- unique(metab_sort_patients_df$HMDB_name) metabolites_in_chunks <- split(metabolites, ceiling(seq_along(metabolites) / nr_plots_perpage)) nr_chunks <- length(metabolites_in_chunks) - + current_perpage <- lapply(metabolites_in_chunks, function(metab_name) { patients_df <- metab_sort_patients_df %>% filter(HMDB_name %in% metab_name) controls_df <- metab_sort_controls_df %>% filter(HMDB_name %in% metab_name) - + # Combine both dataframes combined_df <- rbind(patients_df, controls_df) - + # Add empty dummy's to extend the number of metabs to the nr_plots_perpage n_missing <- nr_plots_perpage - length(metab_name) if (n_missing > 0) { @@ -132,7 +135,7 @@ prepare_data_perpage <- function(metab_interest_sorted, metab_interest_contr, nr metab_order <- metab_name } attr(combined_df, "y_order") <- rev(metab_order) - + return(combined_df) }) # Add new items to main list @@ -142,7 +145,7 @@ prepare_data_perpage <- function(metab_interest_sorted, metab_interest_contr, nr } # add page headers to list names(metab_perpage) <- metab_category - + return(metab_perpage) } @@ -151,33 +154,33 @@ prepare_data_perpage <- function(metab_interest_sorted, metab_interest_contr, nr #' @param metab_interest_sorted: list of dataframes with metabolite Z-scores for each sample/patient (list) #' @param metab_list_all: list of tables with metabolites for Helix and violin plots (list) #' -#' @return: dataframe with patient data with only metabolites for Helix and violin plots +#' @return: dataframe with patient data with only metabolites for Helix and violin plots #' with Helix name, high/low Z-score cutoffs get_patient_data_to_helix <- function(metab_interest_sorted, metab_list_all) { # Combine Z-scores of metab groups together df_all_metabs_zscores <- bind_rows(metab_interest_sorted) - + # Change the Sample column to characters, trim HMDB_name and split HMDB_name in new column df_all_metabs_zscores <- df_all_metabs_zscores %>% mutate(Sample = as.character(Sample), HMDB_name = str_trim(HMDB_name, "right"), HMDB_name_split = str_split_fixed(HMDB_name, "nitine;", 2)[, 1]) - + # Combine stofgroepen dims_helix_table <- bind_rows(metab_list_all) - + # Filter for Helix metabolites and split HMDB_name column for matching with df_all_metabs_zscores dims_helix_table <- dims_helix_table %>% filter(Helix == "ja") %>% mutate(HMDB_name_split = str_split_fixed(HMDB_name, "nitine;", 2)[, 1]) %>% select(HMDB_name_split, Helix_naam, high_zscore, low_zscore) - + # Filter DIMS results for metabolites for Helix and combine Helix info df_metabs_helix <- df_all_metabs_zscores %>% filter(HMDB_name_split %in% dims_helix_table$HMDB_name_split) %>% left_join(dims_helix_table, by = join_by(HMDB_name_split)) %>% select(HMDB_name, Sample, Z_score, Helix_naam, high_zscore, low_zscore) - + return(df_metabs_helix) } @@ -188,7 +191,7 @@ get_patient_data_to_helix <- function(metab_interest_sorted, metab_list_all) { #' @return: a logical vector with TRUE or FALSE for each element (vector) is_diagnostic_patient <- function(patient_column) { diagnostic_patients <- grepl("^P[0-9]{4}M", patient_column) - + return(diagnostic_patients) } @@ -201,33 +204,33 @@ is_diagnostic_patient <- function(patient_column) { output_for_helix <- function(protocol_name, df_metabs_helix) { # Remove positive controls df_metabs_helix <- df_metabs_helix %>% filter(is_diagnostic_patient(Sample)) - + # Add 'Vial' column, each patient has unique ID df_metabs_helix <- df_metabs_helix %>% group_by(Sample) %>% mutate(Vial = cur_group_id()) %>% ungroup() - + # Split patient number into labnummer and Onderzoeksnummer - df_metabs_helix <- add_lab_id_and_onderzoeksnummer(df_metabs_helix) - + df_metabs_helix <- add_lab_id_and_onderzoeksnr(df_metabs_helix) + # Add column with protocol name df_metabs_helix$Protocol <- protocol_name - + # Change name Z_score and Helix_naam columns to Amount and Name change_columns <- c(Amount = "Z_score", Name = "Helix_naam") df_metabs_helix <- df_metabs_helix %>% rename(all_of(change_columns)) - + # Select only necessary columns and set them in correct order df_metabs_helix <- df_metabs_helix %>% select(c(Vial, labnummer, Onderzoeksnummer, Protocol, Name, Amount)) - + # Remove duplicate patient-metabolite combinations ("leucine + isoleucine + allo-isoleucin_Z-score" is added 3 times) df_metabs_helix <- df_metabs_helix %>% group_by(Onderzoeksnummer, Name) %>% distinct() %>% ungroup() - + return(df_metabs_helix) } @@ -236,14 +239,13 @@ output_for_helix <- function(protocol_name, df_metabs_helix) { #' @param df_metabs_helix: dataframe with patient data to be uploaded to Helix #' #' @return: dataframe with added labnummer and Onderzoeksnummer columns -add_lab_id_and_onderzoeksnummer <- function(df_metabs_helix) { +add_lab_id_and_onderzoeksnr <- function(df_metabs_helix) { # Split patient number into labnummer and Onderzoeksnummer - for (row in 1:nrow(df_metabs_helix)) { + for (row in seq_len(nrow(df_metabs_helix))) { df_metabs_helix[row, "labnummer"] <- gsub("^P|\\.[0-9]*", "", df_metabs_helix[row, "Sample"]) labnummer_split <- strsplit(as.character(df_metabs_helix[row, "labnummer"]), "M")[[1]] df_metabs_helix[row, "Onderzoeksnummer"] <- paste0("MB", labnummer_split[1], "/", labnummer_split[2]) } - return(df_metabs_helix) } @@ -258,11 +260,11 @@ prepare_alarmvalues <- function(patient_name, dims_helix_table) { patient_metabs_helix <- dims_helix_table %>% filter(Sample == patient_name) %>% mutate(Z_score = round(Z_score, 2)) - + patient_high_df <- patient_metabs_helix %>% filter(Z_score > high_zscore) patient_low_df <- patient_metabs_helix %>% filter(Z_score < low_zscore) - - if (nrow(patient_high_df) > 0 | nrow(patient_low_df) > 0) { + + if (nrow(patient_high_df) > 0 || nrow(patient_low_df) > 0) { # sort tables on zscore patient_high_df <- patient_high_df %>% arrange(desc(Z_score)) %>% select(c(HMDB_name, Z_score)) patient_low_df <- patient_low_df %>% arrange(Z_score) %>% select(c(HMDB_name, Z_score)) @@ -270,15 +272,15 @@ prepare_alarmvalues <- function(patient_name, dims_helix_table) { # add lines for increased, decreased extra_line1 <- c("Increased", "") extra_line2 <- c("Decreased", "") - + # combine the two lists top_metab_patient <- rbind(extra_line1, patient_high_df, extra_line2, patient_low_df) - + # remove row names rownames(top_metab_patient) <- NULL # change column names for display colnames(top_metab_patient) <- c("Metabolite", "Z-score") - + return(top_metab_patient) } @@ -286,7 +288,7 @@ prepare_alarmvalues <- function(patient_name, dims_helix_table) { #' #' @param pt_name: patient code (string) #' @param zscore_patients: dataframe with metabolite Z-scores per patient (dataframe) -#' @param top_highest: the number of metabolites with the highest Z-score to display in the table (numeric) +#' @param top_highest: the number of metabolites with the highest Z-score to display in the table (numeric) #' @param top_lowest: the number of metabolites with the lowest Z-score to display in the table (numeric) #' #' @return: dataframe with 30 metabolites and Z-scores (dataframe) @@ -296,25 +298,25 @@ prepare_toplist <- function(patient_id, zscore_patients) { patient_df <- zscore_patients %>% select(HMDB_code, HMDB_name, !!sym(patient_id)) %>% arrange(!!sym(patient_id)) - + # Get lowest Zscores patient_df_low <- patient_df[1:top_lowest, ] - patient_df_low <- patient_df_low %>% mutate(across(!!sym(patient_id), ~ round(.x ,2))) - + patient_df_low <- patient_df_low %>% mutate(across(!!sym(patient_id), ~ round(.x, 2))) + # Get highest Zscores patient_df_high <- patient_df[nrow(patient_df):(nrow(patient_df) - top_highest + 1), ] - patient_df_high <- patient_df_high %>% mutate(across(!!sym(patient_id), ~ round(.x ,2))) - + patient_df_high <- patient_df_high %>% mutate(across(!!sym(patient_id), ~ round(.x, 2))) + # add lines for increased, decreased extra_line1 <- c("Increased", "", "") extra_line2 <- c("Decreased", "", "") top_metab_pt <- rbind(extra_line1, patient_df_high, extra_line2, patient_df_low) # remove row names rownames(top_metab_pt) <- NULL - + # change column names for display colnames(top_metab_pt) <- c("HMDB_ID", "Metabolite", "Z-score") - + return(top_metab_pt) } @@ -329,11 +331,11 @@ create_pdf_violin_plots <- function(pdf_dir, patient_id, metab_perpage, top_meta # set parameters for plots plot_height <- 9.6 plot_width <- 6 - + # patient plots, create the PDF device patient_id_sub <- patient_id suffix <- "" - if (grepl("Diagnostics", pdf_dir) & is_diagnostic_patient(patient_id)) { + if (grepl("Diagnostics", pdf_dir) && is_diagnostic_patient(patient_id)) { prefix <- "MB" suffix <- "_DIMS_PL_DIAG" # substitute P and M in P2020M00001 into right format for Helix @@ -346,62 +348,62 @@ create_pdf_violin_plots <- function(pdf_dir, patient_id, metab_perpage, top_meta } else { prefix <- "R_" } - + pdf(paste0(pdf_dir, "/", prefix, patient_id_sub, suffix, ".pdf"), onefile = TRUE, width = plot_width, height = plot_height) - + # page headers: page_headers <- names(metab_perpage) - + # put table into PDF file, if not empty if (!is.null(dim(top_metab_pt))) { max_rows_per_page <- 35 total_rows <- nrow(top_metab_pt) number_of_pages <- ceiling(total_rows / max_rows_per_page) - + # get the names and numbers in the table aligned table_theme <- ttheme_default(core = list(fg_params = list(hjust = 0, x = 0.05, fontsize = 6)), colhead = list(fg_params = list(fontsize = 8, fontface = "bold"))) - + for (page in seq(number_of_pages)) { start_row <- (page - 1) * max_rows_per_page + 1 end_row <- min(page * max_rows_per_page, total_rows) page_data <- top_metab_pt[start_row:end_row, ] - + table_grob <- tableGrob(page_data, theme = table_theme, rows = NULL) - + grid.arrange( table_grob, top = paste0("Top deviating metabolites for patient: ", patient_id) ) } } - + # violin plots for (metab_class in names(metab_perpage)) { # extract list of metabolites to plot on a page metab_zscores_df <- metab_perpage[[metab_class]] # extract original data for patient of interest (pt_name) before cut-offs patient_zscore_df <- metab_zscores_df %>% filter(Sample == patient_id) - - # Remove patient column and change Z-score. If under -5 to -5 and if above 20 to 20. + + # Remove patient column and change Z-score. If under -5 to -5 and if above 20 to 20. metab_zscores_df <- metab_zscores_df %>% filter(Sample != patient_id) %>% mutate(Z_score = pmin(pmax(Z_score, -5), 20)) - + # subtitle per page sub_perpage <- gsub("_", " ", metab_class) # for IEM plots, put subtitle on two lines sub_perpage <- gsub("probability", "\nprobability", sub_perpage) - - # draw violin plot. + + # draw violin plot. ggplot_object <- create_violin_plot(metab_zscores_df, patient_zscore_df, sub_perpage, patient_id) - + suppressWarnings(print(ggplot_object)) } - + # add explanation of violin plots, version number etc. plot(NA, xlim = c(0, 5), ylim = c(0, 5), bty = "n", xaxt = "n", yaxt = "n", xlab = "", ylab = "") if (length(explanation) > 0) { @@ -411,7 +413,7 @@ create_pdf_violin_plots <- function(pdf_dir, patient_id, metab_perpage, top_meta text(-0.2, text_y_position, explanation[line_index], pos = 4, cex = 0.5) } } - + # close the PDF file dev.off() } @@ -420,7 +422,7 @@ create_pdf_violin_plots <- function(pdf_dir, patient_id, metab_perpage, top_meta #' #' @param metab_zscores_df: dataframe with Z-scores for all samples (dataframe) #' @param patient_zscore_df: dataframe with Z-scores for the specified patient (dataframe) -#' @param sub_perpage: subtitle of the page (string) +#' @param sub_perpage: subtitle of the page (string) #' @param patient_id: the patient id of the selected patient (string) #' #' @returns ggpplot_object: a violin plot of metabolites that highlights the selected patient (ggplot object) @@ -429,11 +431,11 @@ create_violin_plot <- function(metab_zscores_df, patient_zscore_df, sub_perpage, circlesize <- 0.8 # Set colors for the violinplot: green, blue, blue/purple, purple, orange, red colors_plot <- c("#22E4AC", "#00B0F0", "#504FFF", "#A704FD", "#F36265", "#DA0641") - + y_order <- attr(metab_zscores_df, "y_order") metab_zscores_df$HMDB_name <- rev(factor(metab_zscores_df$HMDB_name, levels = rev(y_order))) patient_zscore_df$HMDB_name <- rev(factor(patient_zscore_df$HMDB_name, levels = rev(y_order))) - + ggplot_object <- ggplot(metab_zscores_df, aes(x = Z_score, y = HMDB_name)) + # Make violin plots geom_violin(scale = "width", na.rm = TRUE) + @@ -441,53 +443,48 @@ create_violin_plot <- function(metab_zscores_df, patient_zscore_df, sub_perpage, geom_point(data = patient_zscore_df, aes(color = Z_score), size = 3.5 * circlesize, shape = 22, fill = "white", na.rm = TRUE) + # Add the Z-score at the right side of the plot - geom_text( - data = patient_zscore_df, - aes(16, label = paste0("Z=", round(Z_score, 2))), - hjust = "left", vjust = +0.2, size = 3, na.rm = TRUE) + + geom_text(data = patient_zscore_df, + aes(16, label = paste0("Z=", round(Z_score, 2))), + hjust = "left", vjust = +0.2, size = 3, na.rm = TRUE) + # Set colour for the Z-score of the selected patient - scale_fill_gradientn( - colors = colors_plot, values = NULL, space = "Lab", na.value = "grey50", guide = "colourbar", - aesthetics = "colour" - ) + + scale_fill_gradientn(colors = colors_plot, values = NULL, space = "Lab", + na.value = "grey50", guide = "colourbar", aesthetics = "colour") + # Add labels to the axis labs(x = "Z-scores", y = "Metabolites", subtitle = sub_perpage, color = "z-score") + # Add a title to the page ggtitle(label = paste0("Results for patient ", patient_id)) + - # Set theme: size and font type of y-axis labels, remove legend and make the - theme( - axis.text.y = element_text(family = "Courier", size = 6), - legend.position = "none", - plot.caption = element_text(size = rel(fontsize)) - ) + + # Set theme: size and font type of y-axis labels, remove legend and make the + theme(axis.text.y = element_text(family = "Courier", size = 6), + legend.position = "none", + plot.caption = element_text(size = rel(fontsize))) + # Set y-axis to set order scale_y_discrete(limits = y_order) + # Limit the x-axis to between -5 and 20 xlim(-5, 20) + # Set grey vertical lines at -2 and 2 geom_vline(xintercept = c(-2, 2), col = "grey", lwd = 0.5, lty = 2) - - + + return(ggplot_object) } #' Run the dIEM algorithm (DOI: 10.3390/ijms21030979) #' -#' @param expected_biomarkers_df: table with information for HMDB codes about IEMs (dataframe) +#' @param expected_biomarkers_df: table with information for HMDB codes about IEMs (dataframe) #' @param zscore_patients: dataframe containing Z-scores for patient (dataframe) #' #' @returns probability_score: a dataframe with probability scores for IEMs for each patient (dataframe) run_diem_algorithm <- function(expected_biomarkers_df, zscore_patients_df, sample_cols) { # Rank the metabolites for each patient individually - ranking_patients <- zscore_patients_df %>% + ranking_patients <- zscore_patients_df %>% mutate(across(-c(HMDB_code, HMDB_name), rank_patient_zscores)) - + ranking_patients <- merge(x = expected_biomarkers_df, y = ranking_patients, by.x = c("HMDB_code"), by.y = c("HMDB_code")) - + zscore_expected_df <- merge(x = expected_biomarkers_df, y = zscore_patients_df, by.x = c("HMDB_code"), by.y = c("HMDB_code")) - + # Change Z-score to zero for specific cases zscore_expected_df <- zscore_expected_df %>% mutate(across( all_of(sample_cols), @@ -497,34 +494,31 @@ run_diem_algorithm <- function(expected_biomarkers_df, zscore_patients_df, sampl TRUE ~ .x ) )) - + # Sort both dataframes on HMDB_code for calculating the metabolite score zscore_expected_df <- zscore_expected_df[order(zscore_expected_df$HMDB_code), ] ranking_patients <- ranking_patients[order(ranking_patients$HMDB_code), ] - + # Set up dataframe for the metabolite score, copy zscore_expected_df for biomarker info metabolite_score_info <- zscore_expected_df # Calculate metabolite score: Z-score/(Rank * 0.9) metabolite_score_info[sample_cols] <- zscore_expected_df[sample_cols] / (ranking_patients[sample_cols] * 0.9) - + # Calculate the weighted score: metabolite_score * Total_Weight - metabolite_weight_score <- metabolite_score_info %>% + metabolite_weight_score <- metabolite_score_info %>% mutate(across( all_of(sample_cols), ~ .x * Total_Weight )) %>% arrange(desc(Disease), desc(Absolute_Weight)) - + # Calculate the probability score for each disease - Mz combination probability_score <- metabolite_weight_score %>% - filter( - !duplicated(select(., Disease, M.z)) | - !duplicated(select(., Disease, M.z), fromLast = FALSE) - ) %>% - group_by(Disease) %>% + filter(!duplicated(select(., Disease, M.z)) | + !duplicated(select(., Disease, M.z), fromLast = FALSE)) %>% + group_by(Disease) %>% summarise(across(all_of(sample_cols), sum), .groups = "drop") - - + # Set probability score to 0 for Z-scores == 0 for (sample_col in sample_cols) { # Get indexes of Zscore that equal 0 @@ -534,9 +528,9 @@ run_diem_algorithm <- function(expected_biomarkers_df, zscore_patients_df, sampl # Set probabilty of these diseases to 0 probability_score[probability_score$Disease %in% diseases_zero, sample_col] <- 0 } - + colnames(probability_score) <- gsub("_Zscore", "_prob_score", colnames(probability_score)) - + return(probability_score) } @@ -548,15 +542,15 @@ run_diem_algorithm <- function(expected_biomarkers_df, zscore_patients_df, sampl rank_patient_zscores <- function(zscore_col) { # Create ranking column with default NA values ranking <- rep(NA_real_, length(zscore_col)) - + # Get indexes for negative and positive rows neg_indexes <- which(zscore_col <= 0) pos_indexes <- which(zscore_col > 0) - + # Rank the negative and positive Zscores ranking[neg_indexes] <- dense_rank(zscore_col[neg_indexes]) ranking[pos_indexes] <- dense_rank(-zscore_col[pos_indexes]) - + return(ranking) } @@ -565,12 +559,12 @@ rank_patient_zscores <- function(zscore_col) { #' @param probability_score: a dataframe containing probability scores for each patient (dataframe) #' @param output_dir: location where to save the Excel file (string) #' @param run_name: name of the run, for the file name (string) -save_prob_scores_to_Excel <- function(probability_score, output_dir, run_name) { +save_prob_scores_to_excel <- function(probability_score, output_dir, run_name) { # Create conditional formatting for output Excel sheet. Colors according to values. wb <- createWorkbook() addWorksheet(wb, "Probability Scores") writeData(wb, "Probability Scores", probability_score) - conditionalFormatting(wb, "Probability Scores", cols = 2:ncol(probability_score), rows = 1:nrow(probability_score), + conditionalFormatting(wb, "Probability Scores", cols = 2:ncol(probability_score), rows = seq_len(nrow(probability_score)), type = "colourScale", style = c("white", "#FFFDA2", "red"), rule = c(1, 10, 100)) saveWorkbook(wb, file = paste0(output_dir, "/dIEM_algoritme_output_", run_name, ".xlsx"), overwrite = TRUE) rm(wb) From 8094aede0a4bdfe3998e4fcee546785cbd214540 Mon Sep 17 00:00:00 2001 From: ALuesink Date: Thu, 21 Aug 2025 12:15:08 +0200 Subject: [PATCH 04/14] Added new package for unit testing --- .github/workflows/dims_test.yml | 2 +- DIMS/tests/testthat.R | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dims_test.yml b/.github/workflows/dims_test.yml index fa2a8aa2..b547d126 100644 --- a/.github/workflows/dims_test.yml +++ b/.github/workflows/dims_test.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v4 - name: Install dependencies - run: Rscript -e "install.packages(c('testthat', 'withr'))" + run: Rscript -e "install.packages(c('testthat', 'withr', 'vdiffr'))" - name: Run tests run: Rscript tests/testthat.R diff --git a/DIMS/tests/testthat.R b/DIMS/tests/testthat.R index 3f13a069..636acf7d 100644 --- a/DIMS/tests/testthat.R +++ b/DIMS/tests/testthat.R @@ -1,6 +1,7 @@ # Run all unit tests library(testthat) library(withr) +library(vdiffr) # enable snapshots local_edition(3) From 62160b2095f45a79bbf43d64ababe2b577db1a22 Mon Sep 17 00:00:00 2001 From: ALuesink Date: Thu, 21 Aug 2025 12:17:34 +0200 Subject: [PATCH 05/14] Added unit tests and associated files for GenerateViolinPlots --- .../generate_qc_output/test_barplot.new.png | Bin 0 -> 46638 bytes .../test_excel_dIEM.xlsx | Bin 0 -> 6754 bytes .../violin-plot-p2025m1.svg | 74 ++++ .../violin_pdf_P2025M1.new.pdf | Bin 0 -> 28962 bytes .../violin_pdf_P2025M1.pdf | Bin 0 -> 28962 bytes .../make_test_data_GenerateViolinPlots.R | 290 +++++++++++++ .../test_acyl_carnitines_controls.txt | 11 + .../fixtures/test_acyl_carnitines_df.txt | 21 + .../test_acyl_carnitines_patients.txt | 11 + .../fixtures/test_crea_gua_controls.txt | 11 + .../testthat/fixtures/test_crea_gua_df.txt | 21 + .../fixtures/test_crea_gua_patients.txt | 11 + .../fixtures/test_df_metabs_helix.txt | 16 + .../fixtures/test_expected_biomarkers_df.txt | 16 + .../fixtures/test_intensities_zscore_df.txt | 7 + .../test_acyl_carnitines.txt | 4 + .../test_metabolite_groups/test_crea_gua.txt | 3 + .../fixtures/test_probability_score_df.txt | 8 + .../fixtures/test_zscore_patient_df.txt | 31 ++ .../testthat/test_generate_violin_plots.R | 397 ++++++++++++++++++ 20 files changed, 932 insertions(+) create mode 100644 DIMS/tests/testthat/_snaps/generate_qc_output/test_barplot.new.png create mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx create mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/violin-plot-p2025m1.svg create mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.new.pdf create mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.pdf create mode 100644 DIMS/tests/testthat/fixtures/make_test_data_GenerateViolinPlots.R create mode 100644 DIMS/tests/testthat/fixtures/test_acyl_carnitines_controls.txt create mode 100644 DIMS/tests/testthat/fixtures/test_acyl_carnitines_df.txt create mode 100644 DIMS/tests/testthat/fixtures/test_acyl_carnitines_patients.txt create mode 100644 DIMS/tests/testthat/fixtures/test_crea_gua_controls.txt create mode 100644 DIMS/tests/testthat/fixtures/test_crea_gua_df.txt create mode 100644 DIMS/tests/testthat/fixtures/test_crea_gua_patients.txt create mode 100644 DIMS/tests/testthat/fixtures/test_df_metabs_helix.txt create mode 100644 DIMS/tests/testthat/fixtures/test_expected_biomarkers_df.txt create mode 100644 DIMS/tests/testthat/fixtures/test_intensities_zscore_df.txt create mode 100644 DIMS/tests/testthat/fixtures/test_metabolite_groups/test_acyl_carnitines.txt create mode 100644 DIMS/tests/testthat/fixtures/test_metabolite_groups/test_crea_gua.txt create mode 100644 DIMS/tests/testthat/fixtures/test_probability_score_df.txt create mode 100644 DIMS/tests/testthat/fixtures/test_zscore_patient_df.txt create mode 100644 DIMS/tests/testthat/test_generate_violin_plots.R diff --git a/DIMS/tests/testthat/_snaps/generate_qc_output/test_barplot.new.png b/DIMS/tests/testthat/_snaps/generate_qc_output/test_barplot.new.png new file mode 100644 index 0000000000000000000000000000000000000000..58f016c18244ebec324251a250268171c93e9633 GIT binary patch literal 46638 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 C+t(xj literal 0 HcmV?d00001 diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx b/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..fa6d905118380c37c24a2dd07c5009e9e5c1a20f GIT binary patch literal 6754 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Z=0.31 +Z=2.34 + + + + +metab3 +metab1 + + + + + + + + +-5 +0 +5 +10 +15 +20 +Z-scores +Metabolites +test acyl carnitines +Results for patient P2025M1 + + diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.new.pdf b/DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.new.pdf new file mode 100644 index 0000000000000000000000000000000000000000..fc5c3d6b710f85266785259b8e01c0c48e6b2e1b GIT binary patch literal 28962 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 amu=|i% select(HMDB_code, HMDB_name, any_of(test_patient_cols)) + + expect_type(combine_metab_info_zscores(test_metab_list_all, test_zscore_patients_df), "list") + expect_identical(names(combine_metab_info_zscores(test_metab_list_all, test_zscore_patients_df)), + c("test_acyl_carnitines", "test_crea_gua")) + + expect_identical(colnames(combine_metab_info_zscores(test_metab_list_all, test_zscore_patients_df)$test_acyl_carnitines), + c("HMDB_name", "Sample", "Z_score")) + expect_identical((combine_metab_info_zscores(test_metab_list_all, + test_zscore_patients_df)$test_acyl_carnitines$Z_score), + c(0.31, 2.34, 2.45, 1.45, 2.14, -1.44, 12.18, -0.18, 3.22, -3.18)) + expect_identical(as.character(combine_metab_info_zscores(test_metab_list_all, + test_zscore_patients_df)$test_acyl_carnitines$Sample), + c("P2025M1", "P2025M1", "P2025M2", "P2025M2", "P2025M3", + "P2025M3", "P2025M4", "P2025M4", "P2025M5", "P2025M5")) + expect_equal(nchar(combine_metab_info_zscores(test_metab_list_all, + test_zscore_patients_df)$test_acyl_carnitines$HMDB_name[1]), + 45) + + expect_identical(colnames(combine_metab_info_zscores(test_metab_list_all, test_zscore_patients_df)$test_crea_gua), + c("HMDB_name", "Sample", "Z_score")) + expect_identical((combine_metab_info_zscores(test_metab_list_all, + test_zscore_patients_df)$test_crea_gua$Z_score), + c(0.84, -0.46, -0.15, -1.51, -0.78, 1.68, 0.84, 1.48, 0.47, 1.18)) + expect_identical(as.character(combine_metab_info_zscores(test_metab_list_all, + test_zscore_patients_df)$test_crea_gua$Sample), + c("P2025M1", "P2025M1", "P2025M2", "P2025M2", "P2025M3", + "P2025M3", "P2025M4", "P2025M4", "P2025M5", "P2025M5")) + expect_equal(nchar(combine_metab_info_zscores(test_metab_list_all, + test_zscore_patients_df)$test_crea_gua$HMDB_name[1]), + 45) +}) + +testthat::test_that("Combine patient and control data for each page of the violinplot pdf", { + test_acyl_carnitines_pat <- read.delim(test_path("fixtures/", "test_acyl_carnitines_patients.txt")) + test_acyl_carnitines_ctrl <- read.delim(test_path("fixtures/", "test_acyl_carnitines_controls.txt")) + + test_crea_gua_pat <- read.delim(test_path("fixtures/", "test_crea_gua_patients.txt")) + test_crea_gua_ctrl <- read.delim(test_path("fixtures/", "test_crea_gua_controls.txt")) + + test_metab_interest_sorted <- list(test_acyl_carnitines_pat, test_crea_gua_pat) + names(test_metab_interest_sorted) <- c("test_acyl_carnitines", "test_crea_gua") + + test_metab_interest_contr <- list(test_acyl_carnitines_ctrl, test_crea_gua_ctrl) + names(test_metab_interest_contr) <- c("test_acyl_carnitines", "test_crea_gua") + + test_nr_plots_perpage <- 1 + test_nr_pat <- 5 + test_nr_contr <- 5 + + expect_type(prepare_data_perpage(test_metab_interest_sorted, test_metab_interest_contr, + test_nr_plots_perpage, test_nr_pat, test_nr_contr), + "list") + expect_equal(length(prepare_data_perpage(test_metab_interest_sorted, test_metab_interest_contr, + test_nr_plots_perpage, test_nr_pat, test_nr_contr)), + 4) + expect_identical(names(prepare_data_perpage(test_metab_interest_sorted, test_metab_interest_contr, + test_nr_plots_perpage, test_nr_pat, test_nr_contr)), + c("test_acyl_carnitines_1", "test_acyl_carnitines_2", "test_crea_gua_1", "test_crea_gua_2")) + expect_identical(unique(prepare_data_perpage(test_metab_interest_sorted, test_metab_interest_contr, + test_nr_plots_perpage, test_nr_pat, + test_nr_contr)$test_acyl_carnitines_1$HMDB_name), + c("metab1 ")) + expect_identical(prepare_data_perpage(test_metab_interest_sorted, test_metab_interest_contr, + test_nr_plots_perpage, test_nr_pat, + test_nr_contr)$test_acyl_carnitines_1$Sample, + c("P2025M1", "P2025M2", "P2025M3", "P2025M4", "P2025M5", "C101.1", "C102.1", "C103.1", "C104.1", "C105.1")) + + test_nr_plots_perpage <- 2 + + expect_equal(length(prepare_data_perpage(test_metab_interest_sorted, test_metab_interest_contr, + test_nr_plots_perpage, test_nr_pat, test_nr_contr)), + 2) + expect_identical(names(prepare_data_perpage(test_metab_interest_sorted, test_metab_interest_contr, + test_nr_plots_perpage, test_nr_pat, test_nr_contr)), + c("test_acyl_carnitines_1", "test_crea_gua_1")) + expect_identical(unique(prepare_data_perpage(test_metab_interest_sorted, test_metab_interest_contr, + test_nr_plots_perpage, test_nr_pat, + test_nr_contr)$test_acyl_carnitines_1$HMDB_name), + c("metab1 ", "metab3 ")) + expect_identical(prepare_data_perpage(test_metab_interest_sorted, test_metab_interest_contr, + test_nr_plots_perpage, test_nr_pat, + test_nr_contr)$test_acyl_carnitines_1$Sample, + c("P2025M1", "P2025M1", "P2025M2", "P2025M2", "P2025M3", + "P2025M3", "P2025M4", "P2025M4", "P2025M5", "P2025M5", + "C101.1", "C101.1", "C102.1", "C102.1", "C103.1", "C103.1", "C104.1", "C104.1", "C105.1", "C105.1")) +}) + +testthat::test_that("Generate a dataframe with information for Helix", { + test_acyl_carnitines_pat <- read.delim(test_path("fixtures/", "test_acyl_carnitines_patients.txt")) + test_crea_gua_pat <- read.delim(test_path("fixtures/", "test_crea_gua_patients.txt")) + + test_metab_interest_sorted <- list(test_acyl_carnitines_pat, test_crea_gua_pat) + names(test_metab_interest_sorted) <- c("test_acyl_carnitines", "test_crea_gua") + + test_acyl_carnitines_df <- read.delim(test_path("fixtures/test_metabolite_groups/", "test_acyl_carnitines.txt")) + test_crea_gua_df <- read.delim(test_path("fixtures/test_metabolite_groups/", "test_crea_gua.txt")) + + test_metab_list_all <- list(test_acyl_carnitines_df, test_crea_gua_df) + names(test_metab_list_all) <- c("test_acyl_carnitines", "test_crea_gua") + + expect_identical(colnames(get_patient_data_to_helix(test_metab_interest_sorted, test_metab_list_all)), + c("HMDB_name", "Sample", "Z_score", "Helix_naam", "high_zscore", "low_zscore")) + expect_equal(dim(get_patient_data_to_helix(test_metab_interest_sorted, test_metab_list_all)), + c(15, 6)) + expect_identical(unique(get_patient_data_to_helix(test_metab_interest_sorted, test_metab_list_all)$HMDB_name), + c("metab1", "metab4", "metab11")) + expect_false("ratio1" %in% get_patient_data_to_helix(test_metab_interest_sorted, test_metab_list_all)$HMDB_name) + expect_equal(get_patient_data_to_helix(test_metab_interest_sorted, test_metab_list_all)$Z_score, + c(0.31, 2.45, 2.14, 12.18, 3.22, 0.84, -0.46, -0.15, -1.51, -0.78, 1.68, 0.84, 1.48, 0.47, 1.18)) +}) + +testthat::test_that("Check for diagnostic patients", { + test_patient_column <- c("P2025M1", "P2025M2", "P2025M3", "P2025M4", "C101.1", "C102.1", "P2025D1", "P225M1") + + expect_equal(is_diagnostic_patient(test_patient_column), c(TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE)) + expect_equal(length(is_diagnostic_patient(test_patient_column)), 8) +}) + +testthat::test_that("Adding labnummer and Onderzoeksnummer to the Helix dataframe", { + test_df_metabs_helix <- read.delim(test_path("fixtures/", "test_df_metabs_helix.txt")) + + test_df_metabs_helix <- test_df_metabs_helix %>% + group_by(Sample) %>% + mutate(Vial = cur_group_id()) %>% + ungroup() + + expect_true("labnummer" %in% colnames(add_lab_id_and_onderzoeksnr(test_df_metabs_helix))) + expect_true("Onderzoeksnummer" %in% colnames(add_lab_id_and_onderzoeksnr(test_df_metabs_helix))) + expect_identical(unique(add_lab_id_and_onderzoeksnr(test_df_metabs_helix)$labnummer), + c("2025M1", "2025M2", "2025M3", "2025M4", "2025M5")) + expect_identical(unique(add_lab_id_and_onderzoeksnr(test_df_metabs_helix)$Onderzoeksnummer), + c("MB2025/1", "MB2025/2", "MB2025/3", "MB2025/4", "MB2025/5")) +}) + +testthat::test_that("Make the output for Helix", { + test_protocol_name <- "test_protocol_name" + + test_df_metabs_helix <- read.delim(test_path("fixtures/", "test_df_metabs_helix.txt")) + + expect_equal(dim(output_for_helix(test_protocol_name, test_df_metabs_helix)), + c(15, 6)) + expect_identical(colnames(output_for_helix(test_protocol_name, test_df_metabs_helix)), + c("Vial", "labnummer", "Onderzoeksnummer", "Protocol", "Name", "Amount")) + expect_identical(unique(output_for_helix(test_protocol_name, test_df_metabs_helix)$Protocol), + "test_protocol_name") + expect_identical(unique(output_for_helix(test_protocol_name, test_df_metabs_helix)$labnummer), + c("2025M1", "2025M2", "2025M3", "2025M4", "2025M5")) + expect_identical(unique(output_for_helix(test_protocol_name, test_df_metabs_helix)$Onderzoeksnummer), + c("MB2025/1", "MB2025/2", "MB2025/3", "MB2025/4", "MB2025/5")) + expect_equal(output_for_helix(test_protocol_name, test_df_metabs_helix)$Amount, + c(0.31, 2.45, 2.14, 12.18, 3.22, 0.84, -0.46, -0.15, -1.51, -0.78, 1.68, 0.84, 1.48, 0.47, 1.18)) +}) + +testthat::test_that("Create a dataframe with all metabolites that exceed the min and max Z-score cutoff", { + test_df_metabs_helix <- read.delim(test_path("fixtures/", "test_df_metabs_helix.txt")) + test_patient_id <- "P2025M1" + + expect_equal(dim(prepare_alarmvalues(test_patient_id, test_df_metabs_helix)), + c(2, 2)) + expect_equal(colnames(prepare_alarmvalues(test_patient_id, test_df_metabs_helix)), + c("Metabolite", "Z-score")) + + test_patient_id <- "P2025M2" + expect_equal(dim(prepare_alarmvalues(test_patient_id, test_df_metabs_helix)), + c(4, 2)) + expect_equal(prepare_alarmvalues(test_patient_id, test_df_metabs_helix)$`Z-score`, + c("", "2.45", "", "-1.51")) + + test_patient_id <- "P2025M4" + expect_equal(dim(prepare_alarmvalues(test_patient_id, test_df_metabs_helix)), + c(3, 2)) + expect_equal(prepare_alarmvalues(test_patient_id, test_df_metabs_helix)$`Z-score`, + c("", "12.18", "")) +}) + +testthat::test_that("Create a dataframe with the top 20 highest and top 10 lowest metabolites", { + test_zscore_patient_df <- read.delim(test_path("fixtures/", "test_zscore_patient_df.txt")) + test_patient_id <- "P2025M1" + + expect_equal(dim(prepare_toplist(test_patient_id, test_zscore_patient_df)), + c(32, 3)) + expect_equal(colnames(prepare_toplist(test_patient_id, test_zscore_patient_df)), + c("HMDB_ID", "Metabolite", "Z-score")) + expect_equal(prepare_toplist(test_patient_id, test_zscore_patient_df)$HMDB_ID, + c("Increased", "HMDB030", "HMDB029", "HMDB028", "HMDB027", "HMDB026", "HMDB025", "HMDB024", "HMDB023", + "HMDB022", "HMDB021", "HMDB020", "HMDB019", "HMDB018", "HMDB017", "HMDB016", "HMDB015", "HMDB014", "HMDB013", + "HMDB012", "HMDB011", "Decreased", "HMDB001", "HMDB002", "HMDB003", "HMDB004", "HMDB005", "HMDB006", + "HMDB007", "HMDB008", "HMDB009", "HMDB010")) + expect_equal(prepare_toplist(test_patient_id, test_zscore_patient_df)$`Z-score`, + c("", "30", "29", "28", "27", "26", "25", "24", "23", "22", "21", "20", "19", "18", "17", "16", "15", + "14", "13", "12", "11", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10")) + + test_patient_id <- "P2025M2" + + expect_equal(prepare_toplist(test_patient_id, test_zscore_patient_df)$Metabolite, + c("", "metab1", "metab2", "metab3", "metab4", "metab5", "metab6", "metab7", "metab8", "metab9", "metab10", + "metab11", "metab12", "metab13", "metab14", "metab15", "metab16", "metab17", "metab18", "metab19", "metab20", + "", "metab30", "metab29", "metab28", "metab27", "metab26", "metab25", "metab24", "metab23", "metab22", + "metab21")) + expect_equal(prepare_toplist(test_patient_id, test_zscore_patient_df)$`Z-score`, + c("", "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10", "-11", "-12", "-13", "-14", "-15", + "-16", "-17", "-18", "-19", "-20", "", "-30", "-29", "-28", "-27", "-26", "-25", "-24", "-23", "-22", "-21")) +}) + +testthat::test_that("Create a pdf with a table of top metabolites and violin plots", { + local_edition(3) + temp_dir <- "./" + dir.create(paste0(temp_dir, "violin_plots/")) + + test_pdf_dir <- paste0(temp_dir, "violin_plots/") + test_patient_id <- "P2025M1" + test_explanation <- "Unit test Generate Violin Plots" + + test_acyl_carnitines_df <- read.delim(test_path("fixtures/", "test_acyl_carnitines_df.txt")) + attr(test_acyl_carnitines_df, "y_order") <- rev(unique(test_acyl_carnitines_df$HMDB_name)) + test_crea_gua_df <- read.delim(test_path("fixtures/", "test_crea_gua_df.txt")) + attr(test_crea_gua_df, "y_order") <- rev(unique(test_crea_gua_df$HMDB_name)) + + test_metab_perpage <- list(test_acyl_carnitines_df, test_crea_gua_df) + names(test_metab_perpage) <- c("test_acyl_carnitines", "test_crea_gua") + + test_top_metab_pt <- data.frame( + Metabolite = c("Increased", "metab1", "Decreased", "metab11"), + `Z-score` = c("", "2.45", "", "-1.51") + ) + + expect_silent(create_pdf_violin_plots(test_pdf_dir, test_patient_id, + test_metab_perpage, test_top_metab_pt, test_explanation)) + + expect_true(file.exists(paste0(test_pdf_dir, "R_P2025M1.pdf"))) + expect_snapshot_file(paste0(test_pdf_dir, "R_P2025M1.pdf"), "violin_pdf_P2025M1.pdf") + + unlink(test_pdf_dir, recursive = TRUE) +}) + +testthat::test_that("Create a violin plot", { + test_patient_id <- "P2025M1" + test_sub_perpage <- "test acyl carnitines" + + test_acyl_carnitines_df <- read.delim(test_path("fixtures/", "test_acyl_carnitines_df.txt")) + attr(test_acyl_carnitines_df, "y_order") <- rev(unique(test_acyl_carnitines_df$HMDB_name)) + + test_patient_zscore_df <- test_acyl_carnitines_df %>% filter(Sample == test_patient_id) + + test_metab_zscores_df <- test_acyl_carnitines_df %>% filter(Sample != test_patient_id) + + expect_silent(create_violin_plot(test_metab_zscores_df, test_patient_zscore_df, test_sub_perpage, test_patient_id)) + + expect_doppelganger("violin_plot_P2025M1", create_violin_plot(test_metab_zscores_df, test_patient_zscore_df, + test_sub_perpage, test_patient_id)) +}) + +testthat::test_that("Run dIEM algorithm", { + test_expected_biomarkers_df <- read.delim(test_path("fixtures/", "test_expected_biomarkers_df.txt")) + test_zscore_patient_df <- read.delim(test_path("fixtures/", "test_zscore_patient_df.txt")) + test_sample_cols <- c("P2025M1", "P2025M2", "P2025M3", "P2025M4") + + expect_equal(dim(run_diem_algorithm(test_expected_biomarkers_df, test_zscore_patient_df, test_sample_cols)), + c(7, 5)) + expect_identical(colnames(run_diem_algorithm(test_expected_biomarkers_df, test_zscore_patient_df, test_sample_cols)), + c("Disease", "P2025M1", "P2025M2", "P2025M3", "P2025M4")) + expect_identical(run_diem_algorithm(test_expected_biomarkers_df, test_zscore_patient_df, test_sample_cols)$Disease, + c("Disease A", "Disease B", "Disease C", "Disease D", "Disease E", "Disease F", "Disease G")) + expect_equal(run_diem_algorithm(test_expected_biomarkers_df, test_zscore_patient_df, test_sample_cols)$P2025M1, + c(10.94172, 0.95343, 12.12121, 0.00000, 44.28850, 0.00000, -38.70370), tolerance = 0.0001) +}) + +testthat::test_that("Ranking Z-scores for a patient", { + test_zscore_col <- c(1, 5, 6, 2, 7, -2, 3) + + expect_equal(length(rank_patient_zscores(test_zscore_col)), 7) + + expect_identical(rank_patient_zscores(test_zscore_col), + c(6, 3, 2, 5, 1, 1, 4)) + + test_zscore_col <- c(3, 2, 1, 3) + + expect_identical(rank_patient_zscores(test_zscore_col), + c(1, 2, 3, 1)) + + test_zscore_col <- c(-1, -2, -3, -4) + + expect_identical(rank_patient_zscores(test_zscore_col), + c(4, 3, 2, 1)) +}) + +testthat::test_that("Saving the probability score dataframe as an Excel file", { + local_edition(3) + test_probability_score_df <- read.delim(test_path("fixtures/", "test_probability_score_df.txt")) + test_output_dir <- "./test_excel" + dir.create(test_output_dir) + + test_run_name <- "test_run" + + expect_silent(save_prob_scores_to_excel(test_probability_score_df, test_output_dir, test_run_name)) + expect_true(file.exists(paste0(test_output_dir, "/dIEM_algoritme_output_", test_run_name, ".xlsx"))) + + expect_snapshot_file(paste0(test_output_dir, "/dIEM_algoritme_output_", test_run_name, ".xlsx"), "test_excel_dIEM.xlsx") + + unlink(test_output_dir, recursive = TRUE) +}) From cf9f3493759d9a57dcb038bcde8e914a9c6284ed Mon Sep 17 00:00:00 2001 From: ALuesink Date: Thu, 21 Aug 2025 13:54:56 +0200 Subject: [PATCH 06/14] Fixed snapshot issues GenerateViolinPlots --- .../test_excel_dIEM.xlsx | Bin 6754 -> 6752 bytes .../violin-plot-p2025m1.svg | 4 ++-- .../violin_pdf_P2025M1.new.pdf | Bin 28962 -> 0 bytes .../violin_pdf_P2025M1.pdf | Bin 28962 -> 28932 bytes 4 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.new.pdf diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx b/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx index fa6d905118380c37c24a2dd07c5009e9e5c1a20f..e1a75d59aa1f5b86eb270ba6265b0a264a876978 100644 GIT binary patch delta 842 zcmaE4^1y^Qz?+#xgn@&DgCQwSbR(|!XK!-ERsN7UbeeI-fD0{fCYURDBd>Ntj)6BOpPl;Nzgjx5yaNnHDn4k6TS*D7A6}Kom zXmjb7Bp3#T8B~2#YSH^ADKYhAWlvhs*V_0mn=ek6GW@lxu0rbc^J9GSD;rFlwAV3t zlq}>FsZ2UXzNchEKnUZO*3T%FExwie2(eB;%*LVa^ zy=r2kFJ5`ntmmWUa@+`j0_BFObiStA-Y+PRSOcN z-fW!^#&vcf2;&V02NO87zjO7of*G9xhaggZLb?z}o$wZBIbZ}tC%n16^%VmHgE!Cy zZXgW6@W_ap|Ub`_?!yM?#DL}pIDB5i%PmnN^2f6dw@16~p zfpYtR?i4{$b7JyS31zSy+>%nZjdwX17%Fn~i%TkVQj7H}a&ypa>zTpN8pz7PuvnUb zK^VoP7n74Dm101)B^io5?*O{!ATt94KZ=?v0kHAq`9;}D`T5z{EGT!6_;4SnDFx_M nWfaZ!lOISLfxR>B%oL$~py8IlFqc44lRw!|N}EkZ93%(;2{r_w delta 840 zcmaE0^2mfYz?+#xgn@&DgJESW|3+Q~MrI(r*?@5cm@)Y_(+iNmNzIe_}?mtn`K7q{=Hi+?{e+8K2-hwICuZrzTC+*O`lJ_ z5Spmt&Y6+83;x+wStECPxfj2@CPSzXmzK^3nR9Z^Iq@lX_VN42KhbW}XJ5CEA;6oRBi&%pK}kji1`Q?#ARj4AH_NbU zK?2p2trNny$}R+9yyDcs%h)XduDl<;DXB3@0Pn-uVwpLtD*sw-4w}5fnA2CO?)?jsmHXecs1=0ccJ-3j+f$ikkZz3=9=H`o$%cIjO~Z6}dU+ zPUxAz&l#NBLl1gAFBpHf4?*JNqkePvjA4N^g - - + + Z=0.31 diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.new.pdf b/DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.new.pdf deleted file mode 100644 index fc5c3d6b710f85266785259b8e01c0c48e6b2e1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28962 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 From bd128ddb18a967912b63d49e2d9c35a5bb662d6d Mon Sep 17 00:00:00 2001 From: ALuesink Date: Thu, 21 Aug 2025 14:04:10 +0200 Subject: [PATCH 07/14] Changes to snapshots --- .../generate_qc_output/test_barplot.new.png | Bin 46638 -> 0 bytes .../test_excel_dIEM.xlsx | Bin 6752 -> 6752 bytes .../violin_pdf_P2025M1.pdf | Bin 28932 -> 28932 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 DIMS/tests/testthat/_snaps/generate_qc_output/test_barplot.new.png diff --git a/DIMS/tests/testthat/_snaps/generate_qc_output/test_barplot.new.png b/DIMS/tests/testthat/_snaps/generate_qc_output/test_barplot.new.png deleted file mode 100644 index 58f016c18244ebec324251a250268171c93e9633..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46638 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 C+t(xj diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx b/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx index e1a75d59aa1f5b86eb270ba6265b0a264a876978..e9ce8ca1f1818b9e66940f6917ebdec53e0065be 100644 GIT binary patch delta 502 zcmaE0^1y^Az?+#xgn@&DgCQVcBab2@Q$WIIea4j_dh#u%mmumWvub^;_hAEx*8g57 zYiHLj=$TNqV3Rg`lkm~q6ZYJ0$`zVaUiSC{#D8v(+VzlNt_bT#RBil~kCJdU)yA4^P%I_e(hmDXLvb>3<=y)bZUy zVa4uEou{t-@=LJ!C0puL*CBhssQ!F@CcDNI2S@j)S7|bqA7_+=yK7l0-#xfp*uj%a zwzir4xc%#6rPll`lnL@My}=G(&I~$*K+LWv(7PHvHM}pZ|#ro7cI9~p>i$JV#kha{hy-l+UJBV(fs_$ zSnaHMW@Jv+q^GK@SAGBZw7cf;%cpzJiU)YJb7HC&Q4>g_Z)w2cjyZINZ-DFdfBa=FP2U(IQP@yVaL;r*_-(}E?Ptj zhfPsoUOmUGEPV3wvs&>JbQW!i+IG&#*H7T&Cc#sz6+Gvh9heQh1*Ee#xqq2+X~nk- zCnHpDs-?bmQa6-6+*h^o-c!De(E4fSTbQRrEn32?`(3ziPG!u`diN|-#lMPMlpVCW zbW0KpgTf4|J}R~7{gafKda|-7t>|lQ{Fluar%M_B+ErH}b^7@+KKYdmCQjPxm^?}r zatiX_vT&@w!}+vQTY24OzG&uO-%2+AopvPrVzErgv{wZ-Ket@l{>f>SaWsSW^qOa1~n!I2ISD(EX}G74o(lY zE--zCT^LNiR2xDXP$^rm>L Date: Thu, 21 Aug 2025 14:20:54 +0200 Subject: [PATCH 08/14] Fixed snapshot issues, second try --- .../generate_violin_plots/test_excel_dIEM.xlsx | Bin 6752 -> 0 bytes .../violin_pdf_P2025M1.pdf | Bin 28932 -> 0 bytes .../tests/testthat/test_generate_violin_plots.R | 10 ++++++---- 3 files changed, 6 insertions(+), 4 deletions(-) delete mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx delete mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.pdf diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx b/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx deleted file mode 100644 index e9ce8ca1f1818b9e66940f6917ebdec53e0065be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6752 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 M%!qtqB)vKPAMFfoo&W#< diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.pdf b/DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.pdf deleted file mode 100644 index 799d6504f3363a2fa7a32ff102881aa2cd4cbaba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28932 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

Q*wRoZ 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

ck} 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 Date: Thu, 21 Aug 2025 14:25:49 +0200 Subject: [PATCH 09/14] Fixing snapshot issue, third try --- .../generate_violin_plots/test_excel_dIEM.xlsx | Bin 0 -> 6753 bytes .../violin_pdf_P2025M1.pdf | Bin 0 -> 28932 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx create mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.pdf diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx b/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1f0e614f3b852b516ef4227f531a9ba209f3b2fc GIT binary patch literal 6753 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 NV@2c>3;Ffw{{Wb>Y9#;w literal 0 HcmV?d00001 diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.pdf b/DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e285f615d4af8007ef593d0be114b08a93dce122 GIT binary patch literal 28932 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

`OU!;?OU&?5Z~#p;cHR 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 I=0<$~3u7WaRsaA1 literal 0 HcmV?d00001 From 936f292fc5fa1bca1797f41ace7783db0108cd7a Mon Sep 17 00:00:00 2001 From: ALuesink Date: Thu, 21 Aug 2025 14:50:47 +0200 Subject: [PATCH 10/14] Fixed snapshot issue, fourth try --- .github/workflows/dims_test.yml | 2 +- DIMS/tests/testthat.R | 1 + .../testthat/_snaps/generate_violin_plots.md | 21 ++++++++++++++++++ .../test_excel_dIEM.xlsx | Bin 6753 -> 0 bytes .../violin_pdf_P2025M1.pdf | Bin 28932 -> 0 bytes .../testthat/test_generate_violin_plots.R | 6 +++-- 6 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots.md delete mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx delete mode 100644 DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.pdf diff --git a/.github/workflows/dims_test.yml b/.github/workflows/dims_test.yml index b547d126..e8c4078c 100644 --- a/.github/workflows/dims_test.yml +++ b/.github/workflows/dims_test.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v4 - name: Install dependencies - run: Rscript -e "install.packages(c('testthat', 'withr', 'vdiffr'))" + run: Rscript -e "install.packages(c('testthat', 'withr', 'vdiffr', 'pdftools'))" - name: Run tests run: Rscript tests/testthat.R diff --git a/DIMS/tests/testthat.R b/DIMS/tests/testthat.R index 636acf7d..6e5a4962 100644 --- a/DIMS/tests/testthat.R +++ b/DIMS/tests/testthat.R @@ -2,6 +2,7 @@ library(testthat) library(withr) library(vdiffr) +library(pdftools) # enable snapshots local_edition(3) diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots.md b/DIMS/tests/testthat/_snaps/generate_violin_plots.md new file mode 100644 index 00000000..5df67e7a --- /dev/null +++ b/DIMS/tests/testthat/_snaps/generate_violin_plots.md @@ -0,0 +1,21 @@ +# Create a pdf with a table of top metabolites and violin plots + + Code + content_pdf_violinplots + Output + [1] "Top deviating metabolites for patient: P2025M1\n Metabolite Z.score\n Increased\n metab1 2.45\n Decreased\n metab11 −1.51\n" + [2] " Results for patient P2025M1\n test acyl carnitines\n metab1 Z=2.34\nMetabolites\n metab3 Z=0.31\n −5 0 5 10 15 20\n Z−scores\n" + [3] " Results for patient P2025M1\n test crea gua\n metab4 Z=−0.46\nMetabolites\n metab11 Z=0.84\n −5 0 5 10 15 20\n Z−scores\n" + [4] " Unit test Generate Violin Plots\nUnit test Generate Violin Plots\n" + +# Saving the probability score dataframe as an Excel file + + Disease P2025M1 P2025M2 P2025M3 P2025M4 + 1 Disease A 10.900 -10.9 49.90 -49.9 + 2 Disease B 0.953 0.0 2.29 0.0 + 3 Disease C 12.100 0.0 0.00 12.1 + 4 Disease D 0.000 -12.5 0.00 18.2 + 5 Disease E 44.300 0.0 0.00 28.1 + 6 Disease F 0.000 -77.4 -77.40 0.0 + 7 Disease G -38.700 38.7 38.70 -38.7 + diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx b/DIMS/tests/testthat/_snaps/generate_violin_plots/test_excel_dIEM.xlsx deleted file mode 100644 index 1f0e614f3b852b516ef4227f531a9ba209f3b2fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6753 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 NV@2c>3;Ffw{{Wb>Y9#;w diff --git a/DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.pdf b/DIMS/tests/testthat/_snaps/generate_violin_plots/violin_pdf_P2025M1.pdf deleted file mode 100644 index e285f615d4af8007ef593d0be114b08a93dce122..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28932 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

`OU!;?OU&?5Z~#p;cHR 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 I=0<$~3u7WaRsaA1 diff --git a/DIMS/tests/testthat/test_generate_violin_plots.R b/DIMS/tests/testthat/test_generate_violin_plots.R index e80df979..55a2dac1 100644 --- a/DIMS/tests/testthat/test_generate_violin_plots.R +++ b/DIMS/tests/testthat/test_generate_violin_plots.R @@ -325,7 +325,8 @@ testthat::test_that("Create a pdf with a table of top metabolites and violin plo out_pdf_violinplots <- file.path(test_pdf_dir, "R_P2025M1.pdf") expect_true(file.exists(out_pdf_violinplots)) - expect_snapshot_file(out_pdf_violinplots, "violin_pdf_P2025M1.pdf") + content_pdf_violinplots <- pdftools::pdf_text(out_pdf_violinplots) + expect_snapshot(content_pdf_violinplots) unlink(test_pdf_dir, recursive = TRUE) }) @@ -393,7 +394,8 @@ testthat::test_that("Saving the probability score dataframe as an Excel file", { expect_silent(save_prob_scores_to_excel(test_probability_score_df, test_output_dir, test_run_name)) expect_true(file.exists(out_excel_file)) - expect_snapshot_file(out_excel_file, "test_excel_dIEM.xlsx") + content_excel_file <- openxlsx::read.xlsx(out_excel_file, sheet = 1) + expect_snapshot_output(content_excel_file) unlink(test_output_dir, recursive = TRUE) }) From 926ad6d0c0985b677501eed5da072229e808444d Mon Sep 17 00:00:00 2001 From: ALuesink Date: Mon, 8 Sep 2025 13:14:48 +0200 Subject: [PATCH 11/14] Fixed issue if P1001 is present but no Z-scores --- DIMS/GenerateQCOutput.R | 1 + 1 file changed, 1 insertion(+) diff --git a/DIMS/GenerateQCOutput.R b/DIMS/GenerateQCOutput.R index 321c6ec0..5a439d5c 100644 --- a/DIMS/GenerateQCOutput.R +++ b/DIMS/GenerateQCOutput.R @@ -328,6 +328,7 @@ if (length(sst_colnrs) > 0) { } else { sst_list_intensities <- sst_list[, intensity_col_ids] } +sst_list_intensities <- as.data.frame(sst_list_intensities) for (col_nr in seq_len(ncol(sst_list_intensities))) { sst_list_intensities[, col_nr] <- as.numeric(sst_list_intensities[, col_nr]) if (grepl("Zscore", colnames(sst_list_intensities)[col_nr])) { From b1a38581172cc113cd2986e38ddd23cfa86157fa Mon Sep 17 00:00:00 2001 From: ALuesink Date: Mon, 8 Sep 2025 16:32:47 +0200 Subject: [PATCH 12/14] print statement for testing --- DIMS/GenerateViolinPlots.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIMS/GenerateViolinPlots.R b/DIMS/GenerateViolinPlots.R index 847c4cb5..801f61bb 100644 --- a/DIMS/GenerateViolinPlots.R +++ b/DIMS/GenerateViolinPlots.R @@ -101,6 +101,8 @@ zscore_controls_df <- intensities_zscore_ratios_df %>% select(HMDB_code, HMDB_na colnames(zscore_patients_df) <- gsub("_Zscore", "", colnames(zscore_patients_df)) colnames(zscore_controls_df) <- gsub("_Zscore", "", colnames(zscore_controls_df)) +cat(colnames(expected_biomarkers_df)) + expected_biomarkers_df <- expected_biomarkers_df %>% rename(HMDB_code = HMDB.code, HMDB_name = Metabolite) expected_biomarkers_info <- expected_biomarkers_df %>% From ba47db588619c69b0852a736163c6c832dc91169 Mon Sep 17 00:00:00 2001 From: Anne Luesink Date: Thu, 11 Sep 2025 09:29:05 +0200 Subject: [PATCH 13/14] Removed duplicated line & print statement --- DIMS/GenerateViolinPlots.R | 4 ---- 1 file changed, 4 deletions(-) diff --git a/DIMS/GenerateViolinPlots.R b/DIMS/GenerateViolinPlots.R index 801f61bb..224b1f70 100644 --- a/DIMS/GenerateViolinPlots.R +++ b/DIMS/GenerateViolinPlots.R @@ -101,8 +101,6 @@ zscore_controls_df <- intensities_zscore_ratios_df %>% select(HMDB_code, HMDB_na colnames(zscore_patients_df) <- gsub("_Zscore", "", colnames(zscore_patients_df)) colnames(zscore_controls_df) <- gsub("_Zscore", "", colnames(zscore_controls_df)) -cat(colnames(expected_biomarkers_df)) - expected_biomarkers_df <- expected_biomarkers_df %>% rename(HMDB_code = HMDB.code, HMDB_name = Metabolite) expected_biomarkers_info <- expected_biomarkers_df %>% @@ -155,8 +153,6 @@ for (metabolite_dir in metabolite_dirs) { } #### Run the IEM algorithm ######### -expected_biomarkers_df <- expected_biomarkers_df %>% rename(HMDB_code = HMDB.code, HMDB_name = Metabolite) - diem_probability_score <- run_diem_algorithm(expected_biomarkers_df, zscore_patients_df, patients) save_prob_scores_to_excel(diem_probability_score, output_dir, run_name) From 3875aaf30adfb48db96be45f2de4bd02c4266c99 Mon Sep 17 00:00:00 2001 From: ALuesink Date: Tue, 28 Oct 2025 14:12:34 +0100 Subject: [PATCH 14/14] Fix for error dIEM plots --- DIMS/GenerateViolinPlots.R | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/DIMS/GenerateViolinPlots.R b/DIMS/GenerateViolinPlots.R index 224b1f70..38c0a105 100644 --- a/DIMS/GenerateViolinPlots.R +++ b/DIMS/GenerateViolinPlots.R @@ -176,14 +176,21 @@ for (patient_id in patients) { if (nrow(patient_top_iems_probs) > 0) { top_iems <- patient_top_iems_probs %>% pull(Disease) # Get the metabolites for each IEM and their probability + metabs_iems <- list() metabs_iems_names <- c() - metabs_iems <- lapply(top_iems, function(iem) { + for (iem in top_iems) { iem_probablity <- patient_top_iems_probs %>% filter(Disease == iem) %>% pull(!!sym(patient_id)) metabs_iems_names <- c(metabs_iems_names, paste0(iem, ", probability score ", iem_probablity)) - metab_iem <- expected_biomarkers_df %>% filter(Disease == iem) %>% select(HMDB_code, HMDB_name) - return(metab_iem) - }) - names(metabs_iems) <- metabs_iems_names + metab_iem_df <- expected_biomarkers_df %>% filter(Disease == iem) %>% select(HMDB_code, HMDB_name) + metabs_iems[[iem]] <- metab_iem_df + } + # metabs_iems <- lapply(top_iems, function(iem) { + # iem_probablity <- patient_top_iems_probs %>% filter(Disease == iem) %>% pull(!!sym(patient_id)) + # metabs_iems_names <- c(metabs_iems_names, paste0(iem, ", probability score ", iem_probablity)) + # metab_iem <- expected_biomarkers_df %>% filter(Disease == iem) %>% select(HMDB_code, HMDB_name) + # return(metab_iem) + # }) + # names(metabs_iems) <- metabs_iems_names # Get the Z-scores with metabolite information metab_iem_sorted <- combine_metab_info_zscores(metabs_iems, zscore_patients_df)