diff --git a/modules/nf-core/custom/filterdifferentialtable/main.nf b/modules/nf-core/custom/filterdifferentialtable/main.nf index 6ee226f0982..8f5fc778340 100644 --- a/modules/nf-core/custom/filterdifferentialtable/main.nf +++ b/modules/nf-core/custom/filterdifferentialtable/main.nf @@ -9,10 +9,8 @@ process CUSTOM_FILTERDIFFERENTIALTABLE { input: tuple val(meta), path(input_file) - val(logFC_column) - val(FC_threshold) - val(padj_column) - val(padj_threshold) + tuple val(logfc_column), val(fc_threshold), val(fc_cardinality) + tuple val(stat_column), val(stat_threshold), val(stat_cardinality) output: tuple val(meta), path("*_filtered.tsv"), emit: filtered @@ -41,14 +39,27 @@ process CUSTOM_FILTERDIFFERENTIALTABLE { table = pd.read_csv("${input_file}", sep=sep) # Calculate log2 fold change threshold - logFC_threshold = log2(float("${FC_threshold}")) + logfc_threshold = log2(float("${fc_threshold}")) + + # define evaluation + def evaluate_condition(x, threshold, cardinality): + if cardinality == ">=": + return x >= threshold + elif cardinality == "<=": + return x <= threshold + elif cardinality == ">": + return x > threshold + elif cardinality == "<": + return x < threshold + else: + raise ValueError(f"Invalid cardinality: {cardinality}") # Apply filters mask = ( - table["${logFC_column}"].notna() & - table["${padj_column}"].notna() & - (table["${logFC_column}"].abs() >= logFC_threshold) & - (table["${padj_column}"] <= float("${padj_threshold}")) + table["${logfc_column}"].notna() & + table["${stat_column}"].notna() & + table["${logfc_column}"].abs().apply(lambda x: evaluate_condition(x, logfc_threshold, "${fc_cardinality}")) & + table["${stat_column}"].apply(lambda x: evaluate_condition(x, float("${stat_threshold}"), "${stat_cardinality}")) ) filtered_table = table[mask] diff --git a/modules/nf-core/custom/filterdifferentialtable/meta.yml b/modules/nf-core/custom/filterdifferentialtable/meta.yml index 236eae1f30e..4f3402a4299 100644 --- a/modules/nf-core/custom/filterdifferentialtable/meta.yml +++ b/modules/nf-core/custom/filterdifferentialtable/meta.yml @@ -4,6 +4,7 @@ keywords: - filter - differential expression - logFC + - significance statistic - p-value tools: - "pandas": @@ -26,18 +27,30 @@ input: type: file description: Input differential expression table (CSV, TSV, or TXT format) pattern: "*.{csv,tsv,txt}" - - - logFC_column: + - - logfc_column: type: string description: Name of the column containing log fold change values - - - FC_threshold: + - fc_threshold: type: float description: Fold change threshold for filtering - - - padj_column: + - fc_cardinality: type: string - description: Name of the column containing adjusted p-values - - - padj_threshold: + description: | + Operator to compare the fold change values with the threshold. + Valid values are: ">=", "<=", ">", "<". + - - stat_column: + type: string + description: | + Name of the column containing the significance statistic values + (eg. adjusted p-values). + - stat_threshold: type: float - description: Adjusted p-value threshold for filtering + description: Statistic threshold for filtering + - stat_cardinality: + type: string + description: | + Operator to compare the column values with the threshold. + Valid values are: ">=", "<=", ">", "<". output: - filtered: - meta: diff --git a/modules/nf-core/custom/filterdifferentialtable/tests/main.nf.test b/modules/nf-core/custom/filterdifferentialtable/tests/main.nf.test index 42ef28e6f86..b478b38bd2b 100644 --- a/modules/nf-core/custom/filterdifferentialtable/tests/main.nf.test +++ b/modules/nf-core/custom/filterdifferentialtable/tests/main.nf.test @@ -15,10 +15,8 @@ nextflow_process { process { """ input[0] = [ [ id:'test' ], file(params.modules_testdata_base_path + "genomics/mus_musculus/rnaseq_expression/SRP254919.salmon.merged.deseq2.results.tsv", checkIfExists: true) ] - input[1] = 'log2FoldChange' - input[2] = 2 - input[3] = 'padj' - input[4] = 0.05 + input[1] = Channel.of(['log2FoldChange', 2, '>=']) + input[2] = Channel.of(['padj', 0.05, '<=']) """ } } diff --git a/modules/nf-core/star/align/main.nf b/modules/nf-core/star/align/main.nf index b435f60c51d..22a52184d64 100644 --- a/modules/nf-core/star/align/main.nf +++ b/modules/nf-core/star/align/main.nf @@ -4,8 +4,8 @@ process STAR_ALIGN { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/10/101ea47973178f85ff66a34de6a7462aaf99d947d3924c27ce8a2d5a63009065/data' : - 'community.wave.seqera.io/library/htslib_samtools_star_gawk:311d422a50e6d829' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/26/268b4c9c6cbf8fa6606c9b7fd4fafce18bf2c931d1a809a0ce51b105ec06c89d/data' : + 'community.wave.seqera.io/library/htslib_samtools_star_gawk:ae438e9a604351a4' }" input: tuple val(meta), path(reads, stageAs: "input*/*") diff --git a/modules/nf-core/star/genomegenerate/main.nf b/modules/nf-core/star/genomegenerate/main.nf index d49ddfb8af4..4eb95654bc2 100644 --- a/modules/nf-core/star/genomegenerate/main.nf +++ b/modules/nf-core/star/genomegenerate/main.nf @@ -4,8 +4,8 @@ process STAR_GENOMEGENERATE { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/10/101ea47973178f85ff66a34de6a7462aaf99d947d3924c27ce8a2d5a63009065/data' : - 'community.wave.seqera.io/library/htslib_samtools_star_gawk:311d422a50e6d829' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/26/268b4c9c6cbf8fa6606c9b7fd4fafce18bf2c931d1a809a0ce51b105ec06c89d/data' : + 'community.wave.seqera.io/library/htslib_samtools_star_gawk:ae438e9a604351a4' }" input: tuple val(meta), path(fasta) diff --git a/modules/nf-core/star/starsolo/environment.yml b/modules/nf-core/star/starsolo/environment.yml index 7967c6a2016..9ed1940faac 100644 --- a/modules/nf-core/star/starsolo/environment.yml +++ b/modules/nf-core/star/starsolo/environment.yml @@ -1,5 +1,9 @@ channels: - conda-forge - bioconda + dependencies: + - bioconda::htslib=1.21 + - bioconda::samtools=1.21 - bioconda::star=2.7.11b + - conda-forge::gawk=5.1.0 diff --git a/modules/nf-core/star/starsolo/main.nf b/modules/nf-core/star/starsolo/main.nf index 94a9e2d0859..1f486106e6c 100644 --- a/modules/nf-core/star/starsolo/main.nf +++ b/modules/nf-core/star/starsolo/main.nf @@ -4,8 +4,8 @@ process STARSOLO { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/star:2.7.11b--h43eeafb_2': - 'biocontainers/star:2.7.11b--h43eeafb_2' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/26/268b4c9c6cbf8fa6606c9b7fd4fafce18bf2c931d1a809a0ce51b105ec06c89d/data' : + 'community.wave.seqera.io/library/htslib_samtools_star_gawk:ae438e9a604351a4' }" input: tuple val(meta), val(solotype), path(reads) diff --git a/subworkflows/nf-core/abundance_differential_filter/main.nf b/subworkflows/nf-core/abundance_differential_filter/main.nf index 04d6fa48ce8..4930b708b55 100644 --- a/subworkflows/nf-core/abundance_differential_filter/main.nf +++ b/subworkflows/nf-core/abundance_differential_filter/main.nf @@ -19,7 +19,7 @@ def mergeMaps(meta, meta2){ workflow ABUNDANCE_DIFFERENTIAL_FILTER { take: // Things we may need to iterate - ch_input // [[meta_input], counts, analysis method, fc_threshold, padj_threshold] + ch_input // [[meta_input], counts, analysis method, fc_threshold, stat_threshold] // Workflow-wide things, we don't need to iterate ch_samplesheet // [ meta_exp, samplesheet ] @@ -30,7 +30,7 @@ workflow ABUNDANCE_DIFFERENTIAL_FILTER { main: // Set up how the channels crossed below will be used to generate channels for processing - def criteria = multiMapCriteria { meta_input, abundance, analysis_method, fc_threshold, padj_threshold, meta_exp, samplesheet, meta_contrasts, variable, reference, target -> + def criteria = multiMapCriteria { meta_input, abundance, analysis_method, fc_threshold, stat_threshold, meta_exp, samplesheet, meta_contrasts, variable, reference, target -> samples_and_matrix: meta_map = meta_input + [ 'method': analysis_method ] [meta_map, samplesheet, abundance] @@ -39,7 +39,7 @@ workflow ABUNDANCE_DIFFERENTIAL_FILTER { [ meta_map, variable, reference, target ] filter_params: meta_map = mergeMaps(meta_contrasts, meta_input) + [ 'method': analysis_method ] - [meta_map, [ 'fc_threshold': fc_threshold, 'padj_threshold': padj_threshold ]] + [meta_map, [ 'fc_threshold': fc_threshold, 'stat_threshold': stat_threshold ]] } // For DIFFERENTIAL modules we need to cross the things we're iterating so we @@ -142,24 +142,37 @@ workflow ABUNDANCE_DIFFERENTIAL_FILTER { .join(inputs.filter_params) .multiMap { meta, results, filter_meta -> def method_params = [ - 'deseq2': [fc_column: 'log2FoldChange', padj_column: 'padj'], - 'limma' : [fc_column: 'logFC', padj_column: 'adj.P.Val'], - 'propd' : [fc_column: 'lfc', padj_column: 'weighted_connectivity'] + 'deseq2': [ + fc_column: 'log2FoldChange', fc_cardinality: '>=', + stat_column: 'padj', stat_cardinality: '<=' + ], + 'limma' : [ + fc_column: 'logFC', fc_cardinality: '>=', + stat_column: 'adj.P.Val', stat_cardinality: '<=' + ], + 'propd' : [ + fc_column: 'lfc', fc_cardinality: '>=', + stat_column: 'weighted_connectivity', stat_cardinality: '>=' + ] ] filter_input: [meta + filter_meta, results] - fc_column: method_params[meta.method].fc_column - padj_column: method_params[meta.method].padj_column - fc_threshold: filter_meta.fc_threshold - padj_threshold: filter_meta.padj_threshold + fc_input: [ + method_params[meta.method].fc_column, + filter_meta.fc_threshold, + method_params[meta.method].fc_cardinality + ] + stat_input: [ + method_params[meta.method].stat_column, + filter_meta.stat_threshold, + method_params[meta.method].stat_cardinality + ] } // Filter differential results CUSTOM_FILTERDIFFERENTIALTABLE( ch_diff_filter_params.filter_input, - ch_diff_filter_params.fc_column, - ch_diff_filter_params.fc_threshold, - ch_diff_filter_params.padj_column, - ch_diff_filter_params.padj_threshold + ch_diff_filter_params.fc_input, + ch_diff_filter_params.stat_input ) emit: diff --git a/subworkflows/nf-core/abundance_differential_filter/meta.yml b/subworkflows/nf-core/abundance_differential_filter/meta.yml index 4daac199c75..509520f3ec3 100644 --- a/subworkflows/nf-core/abundance_differential_filter/meta.yml +++ b/subworkflows/nf-core/abundance_differential_filter/meta.yml @@ -10,13 +10,16 @@ input: description: Count matrix file - analysis_method: type: value - description: Analysis method (deseq2 or limma) + description: Analysis method (deseq2, limma, or propd) - fc_threshold: type: value description: Fold change threshold for filtering - - padj_threshold: + - stat_threshold: type: value - description: Adjusted p-value threshold for filtering + description: | + Threshold for filtering the significance statistics + (eg. adjusted p-values in the case of deseq2 or limma, + weighted connectivity in the case of propd) - ch_samplesheet: description: Channel with sample information structure: diff --git a/subworkflows/nf-core/abundance_differential_filter/tests/main.nf.test b/subworkflows/nf-core/abundance_differential_filter/tests/main.nf.test index cdc12c4551f..8cbb8cf8767 100644 --- a/subworkflows/nf-core/abundance_differential_filter/tests/main.nf.test +++ b/subworkflows/nf-core/abundance_differential_filter/tests/main.nf.test @@ -16,6 +16,7 @@ nextflow_workflow { test("deseq2 - mouse - basic") { config './deseq2_basic.config' + tag "deseq2" when { workflow { @@ -45,7 +46,7 @@ nextflow_workflow { file(testData.expression_test_data_dir + testData.abundance_file), 'deseq2', // analysis method 1.5, // FC threshold - 0.05 // padj threshold + 0.05 // stat (adjusted p-value) threshold ]) input[0] = ch_input @@ -73,6 +74,7 @@ nextflow_workflow { test("limma - basic - microarray") { config './limma_basic_microarray.config' + tag "limma" setup { run("UNTAR") { @@ -128,7 +130,7 @@ nextflow_workflow { file, 'limma', 1.5, // FC threshold - 0.05 // padj threshold + 0.05 // stat (adjusted p-value) threshold ]} input[0] = ch_input @@ -155,6 +157,7 @@ nextflow_workflow { test("limma - voom") { config './limma_voom.config' + tag "limma_voom" when { workflow { @@ -184,7 +187,7 @@ nextflow_workflow { file(testData.expression_test_data_dir + testData.abundance_file), 'limma', 1.5, // FC threshold - 0.05 // padj threshold + 0.05 // stat (adjusted p-value) threshold ]) input[0] = ch_input @@ -211,6 +214,7 @@ nextflow_workflow { test("deseq2 - with transcript lengths") { config './deseq2_basic.config' + tag "deseq2_with_lengths" when { workflow { @@ -244,7 +248,7 @@ nextflow_workflow { file(testData.expression_test_data_dir + testData.abundance_file), 'deseq2', 1.5, // FC threshold - 0.05 // padj threshold + 0.05 // stat (adjusted p-value) threshold ]) input[0] = ch_input @@ -302,7 +306,7 @@ nextflow_workflow { file(testData.expression_test_data_dir + testData.abundance_file), 'propd', // analysis method 1.5, // FC threshold - 50 // weighted connectivity threshold + 100 // stat (weighted connectivity) threshold ]) input[0] = ch_input @@ -328,6 +332,7 @@ nextflow_workflow { test("deseq2 and limma - mouse - basic") { config './deseq2_limmavoom_basic.config' + tag "deseq2+limmavoom" when { workflow { @@ -358,14 +363,14 @@ nextflow_workflow { file(testData.expression_test_data_dir + testData.abundance_file), 'limma', 1.5, // FC threshold - 0.05 // padj threshold + 0.05 // stat (adjusted p-value) threshold ], [ [ id:'test' ], file(testData.expression_test_data_dir + testData.abundance_file), 'deseq2', 1.5, // FC threshold - 0.05 // padj threshold + 0.05 // stat (adjusted p-value) threshold ] ) @@ -425,21 +430,21 @@ nextflow_workflow { file(testData.expression_test_data_dir + testData.abundance_file), 'limma', 1.5, // FC threshold - 0.05 // padj threshold + 0.05 // stat (adjusted p-value) threshold ], [ [ id:'test' ], file(testData.expression_test_data_dir + testData.abundance_file), 'deseq2', 1.5, // FC threshold - 0.05 // padj threshold + 0.05 // stat (adjusted p-value) threshold ], [ [ id:'test' ], file(testData.expression_test_data_dir + testData.abundance_file), 'propd', 1.5, // FC threshold - 50 // weighted connectivity threshold + 100 // stat (weighted connectivity) threshold ] ) @@ -469,6 +474,7 @@ nextflow_workflow { test("stub") { config './deseq2_basic.config' + tag "stub" options "-stub" @@ -500,7 +506,7 @@ nextflow_workflow { file(testData.expression_test_data_dir + testData.abundance_file), 'deseq2', 1.5, // FC threshold - 0.05 // padj threshold + 0.05 // stat (adjusted p-value) threshold ]) input[0] = ch_input diff --git a/subworkflows/nf-core/abundance_differential_filter/tests/main.nf.test.snap b/subworkflows/nf-core/abundance_differential_filter/tests/main.nf.test.snap index 97901bf2065..dba530f24eb 100644 --- a/subworkflows/nf-core/abundance_differential_filter/tests/main.nf.test.snap +++ b/subworkflows/nf-core/abundance_differential_filter/tests/main.nf.test.snap @@ -22,7 +22,7 @@ "target": "uremia", "method": "limma", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "diagnosis_normal_uremia_test_filtered.tsv:md5,a971455ece4ae3c3ab902407b36fc6a5" ] @@ -110,7 +110,7 @@ "blocking": "", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6__test_filtered.tsv:md5,7829ead408f4c9cad4277598a231c494" ], @@ -123,7 +123,7 @@ "blocking": "", "method": "limma", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6__test_filtered.tsv:md5,0bfc9215edc6aad064c3ce6abc81bfce" ], @@ -136,7 +136,7 @@ "blocking": "sample_number", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,8b084475c9e7e1b34a510a73b613ff39" ], @@ -149,7 +149,7 @@ "blocking": "sample_number", "method": "limma", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,0bfc9215edc6aad064c3ce6abc81bfce" ] @@ -262,7 +262,7 @@ "blocking": "", "method": "limma", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6__test_filtered.tsv:md5,0bfc9215edc6aad064c3ce6abc81bfce" ], @@ -275,7 +275,7 @@ "blocking": "sample_number", "method": "limma", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,0bfc9215edc6aad064c3ce6abc81bfce" ] @@ -408,7 +408,7 @@ "blocking": "", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6__test_filtered.tsv:md5,7829ead408f4c9cad4277598a231c494" ], @@ -421,7 +421,7 @@ "blocking": "", "method": "limma", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6__test_filtered.tsv:md5,0bfc9215edc6aad064c3ce6abc81bfce" ], @@ -434,9 +434,9 @@ "blocking": "", "method": "propd", "fc_threshold": 1.5, - "padj_threshold": 50 + "stat_threshold": 100 }, - "treatment_mCherry_hND6__test_filtered.tsv:md5,67dd007d63858e49591c3de6fc77ccd6" + "treatment_mCherry_hND6__test_filtered.tsv:md5,432b2ba4e63fd8f7e2aee74e5b71b0a5" ], [ { @@ -447,7 +447,7 @@ "blocking": "sample_number", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,8b084475c9e7e1b34a510a73b613ff39" ], @@ -460,7 +460,7 @@ "blocking": "sample_number", "method": "limma", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,0bfc9215edc6aad064c3ce6abc81bfce" ], @@ -473,9 +473,9 @@ "blocking": "sample_number", "method": "propd", "fc_threshold": 1.5, - "padj_threshold": 50 + "stat_threshold": 100 }, - "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,67dd007d63858e49591c3de6fc77ccd6" + "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,432b2ba4e63fd8f7e2aee74e5b71b0a5" ] ], [ @@ -637,7 +637,7 @@ "blocking": "", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6__test_filtered.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" ], @@ -650,7 +650,7 @@ "blocking": "sample_number", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" ] @@ -786,7 +786,7 @@ "blocking": "", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6__test_filtered.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" ], @@ -799,7 +799,7 @@ "blocking": "sample_number", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" ] @@ -865,7 +865,7 @@ "blocking": "", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6__test_filtered.tsv:md5,7829ead408f4c9cad4277598a231c494" ], @@ -878,7 +878,7 @@ "blocking": "sample_number", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,8b084475c9e7e1b34a510a73b613ff39" ] @@ -980,7 +980,7 @@ "blocking": "", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6__test_filtered.tsv:md5,a48241fb5f24d961d3cce208f060b624" ], @@ -993,7 +993,7 @@ "blocking": "sample_number", "method": "deseq2", "fc_threshold": 1.5, - "padj_threshold": 0.05 + "stat_threshold": 0.05 }, "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,04d6911dce789f284c929694aa3d99b0" ] @@ -1095,9 +1095,9 @@ "blocking": "", "method": "propd", "fc_threshold": 1.5, - "padj_threshold": 50 + "stat_threshold": 100 }, - "treatment_mCherry_hND6__test_filtered.tsv:md5,67dd007d63858e49591c3de6fc77ccd6" + "treatment_mCherry_hND6__test_filtered.tsv:md5,432b2ba4e63fd8f7e2aee74e5b71b0a5" ], [ { @@ -1108,9 +1108,9 @@ "blocking": "sample_number", "method": "propd", "fc_threshold": 1.5, - "padj_threshold": 50 + "stat_threshold": 100 }, - "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,67dd007d63858e49591c3de6fc77ccd6" + "treatment_mCherry_hND6_sample_number_test_filtered.tsv:md5,432b2ba4e63fd8f7e2aee74e5b71b0a5" ] ], [