From 8391da9568f72f055faa1608692150c0c5611eb4 Mon Sep 17 00:00:00 2001 From: Jeremy Mathews <Jeremy.Mathews@utsouthwestern.edu> Date: Thu, 27 Jun 2019 11:05:51 -0500 Subject: [PATCH] Add MultiQC to output. Add version and reference material. fix README --- README.md | 10 +-- docs/references.md | 10 +++ workflow/conf/bicf_logo.png | Bin 0 -> 24863 bytes workflow/conf/multiqc_config.yaml | 56 ++++++++++++ workflow/main.nf | 63 ++++++++++++++ workflow/scripts/generate_references.py | 71 ++++++++++++++++ workflow/scripts/generate_versions.py | 108 ++++++++++++++++++++++++ 7 files changed, 313 insertions(+), 5 deletions(-) create mode 100644 docs/references.md create mode 100644 workflow/conf/bicf_logo.png create mode 100644 workflow/conf/multiqc_config.yaml create mode 100644 workflow/scripts/generate_references.py create mode 100644 workflow/scripts/generate_versions.py diff --git a/README.md b/README.md index 8643233..88d4eff 100755 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ To Run: * path to the fastq location * R1 and R2 only necessary but can include I2 * only fastq's in designFile (see below) are used, not present will be ignored - * eg: **--fastq '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/v3s2r100k/\*.fastq.gz'** + * eg: **--fastq '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r100k/\*.fastq.gz'** * **--designFile** * path to design file (csv format) location * column 1 = "Sample" @@ -35,7 +35,7 @@ To Run: * column 3 = "fastq_R2" * can have repeated "Sample" if there are multiple fastq R1/R2 pairs for the samples * can be downloaded [HERE](https://git.biohpc.swmed.edu/BICF/Astrocyte/cellranger_count/blob/master/docs/design.csv) - * eg: **--designFile '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/v3s2r100k/design.csv'** + * eg: **--designFile '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r100k/design.csv'** * **--genome** * reference genome * requires workflow/conf/biohpc.config to work @@ -44,8 +44,8 @@ To Run: * *'GRCh38-1.2.0'* = Human GRCh38 release 84 * *'hg19-3.0.0'* = Human GRCh37 (hg19) release 87 * *'hg19-1.2.0'* = Human GRCh37 (hg19) release 84 - * *'mm10-3.0.0'* = Human GRCm38 (mm10) release 93 - * *'mm10-3.0.0'* = Human GRCm38 (mm10) release 84 + * *'mm10-3.0.0'* = Mouse GRCm38 (mm10) release 93 + * *'mm10-3.0.0'* = Mouse GRCm38 (mm10) release 84 * *'hg19_and_mm10-3.0.0'* = Human GRCh37 (hg19) + Mouse GRCm38 (mm19) release 93 * *'hg19_and_mm10-1.2.0'* = Human GRCh37 (hg19) + Mouse GRCm38 (mm19) release 84 * *'ercc92-1.2.0'* = ERCC.92 Spike-In @@ -92,7 +92,7 @@ To Run: * eg: **--outDir 'test'** * FULL EXAMPLE: -**nextflow main.nf --fastq '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/v3s2r100k/\*.fastq.gz' --designFile '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/v3s2r100k/design.csv' --genome 'GRCh38-3.0.0' --kitVersion 'three' --version '3.0.2' --outDir 'test'** +**nextflow run workflow/main.nf --fastq '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r100k/\*.fastq.gz' --designFile '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r100k/design.csv' --genome 'GRCh38-3.0.0' --kitVersion 'three' --version '3.0.2' --outDir 'test'** * Design example: diff --git a/docs/references.md b/docs/references.md new file mode 100644 index 0000000..fb28d54 --- /dev/null +++ b/docs/references.md @@ -0,0 +1,10 @@ +### References + +1. **python**: + * Anaconda (Anaconda Software Distribution, [https://anaconda.com](https://anaconda.com)) + +2. **cellranger** + * Cellranger mkfastq [https://support.10xgenomics.com/single-cell-gene-expression/software/pipelines/latest/using/mkfastq](https://support.10xgenomics.com/single-cell-gene-expression/software/pipelines/latest/using/mkfastq) + +3. **MultiQc**: + * Ewels P., Magnusson M., Lundin S. and Käller M. 2016. MultiQC: Summarize analysis results for multiple tools and samples in a single report. Bioinformatics 32(19): 3047–3048. doi:[10.1093/bioinformatics/btw354](https://dx.doi.org/10.1093/bioinformatics/btw354) diff --git a/workflow/conf/bicf_logo.png b/workflow/conf/bicf_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0d8015590c5a94f92c39ec2470bd02baa3d09077 GIT binary patch literal 24863 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 ZPL2w7h5Opc`wjr0sj7RwT-iG8e*l&whlBtC literal 0 HcmV?d00001 diff --git a/workflow/conf/multiqc_config.yaml b/workflow/conf/multiqc_config.yaml new file mode 100644 index 0000000..51b196d --- /dev/null +++ b/workflow/conf/multiqc_config.yaml @@ -0,0 +1,56 @@ +# Custom Logo +custom_logo: 'bicf_logo.png' +custom_logo_url: 'https://www.utsouthwestern.edu/labs/bioinformatics/' +custom_logo_title: 'Bioinformatics Core Facility' + +report_header_info: + - Contact E-mail: 'bicf@utsouthwestern.edu' + - Application Type: 'CellRanger_Count' + - Department: 'Bioinformatic Core Facility, Department of Bioinformatics' + + +# Title to use for the report. +title: BICF CellRanger Count Analysis Report + +report_comment: > + This report has been generated by the <a href="https://git.biohpc.swmed.edu/BICF/Astrocyte/cellranger_count" + target="_blank">BICF/cellranger_count</a> pipeline. + +custom_data: + metrics_summary: + file_format: 'tsv' + id: 'metrics_summary' + contents: 'Estimated Number of Cells Mean Reads per Cell Median Genes per Cell Number of Reads Valid Barcodes Sequencing Saturation Q30 Bases in Barcode Q30 Bases in RNA Read Q30 Bases in UMI Reads Mapped to Genome Reads Mapped Confidently to Genome Reads Mapped Confidently to Intergenic Regions Reads Mapped Confidently to Intronic Regions Reads Mapped Confidently to Exonic Regions Reads Mapped Confidently to Transcriptome Reads Mapped Antisense to Gene Fraction Reads in Cells Total Genes Detected Median UMI Counts per Cell' + section_name: 'Metrics Summary' + plot_type: 'generalstats' + +sp: + metrics_summary: + fn: 'metrics_summary_mqc.tsv' + +table_columns_placement: + metrics_summary: + Estimated Number of Cells: 1 + Mean Reads per Cell: 2 + Median Genes per Cell: 3 + Number of Reads: 4 + Sequencing Saturation: 5 + Reads Mapped Confidently to Genome: 6 + Reads Mapped Confidently to Transcriptome: 7 + Fraction Reads in Cells: 8 + Total Genes Detected: 9 + Median UMI Counts per Cell: 10 + Valid Barcodes: 1100 + Reads Mapped Antisense to Gene: 1200 + +table_columns_visible: + metrics_summary: + Q30 Bases in Barcode: False + Q30 Bases in RNA Read: False + Q30 Bases in UMI: False + Reads Mapped to Genome: False + Reads Mapped Confidently to Intergenic Regions: False + Reads Mapped Confidently to Intronic Regions: False + Reads Mapped Confidently to Exonic Regions: False + +thousandsSep_format: '' diff --git a/workflow/main.nf b/workflow/main.nf index 1967212..6006190 100755 --- a/workflow/main.nf +++ b/workflow/main.nf @@ -14,6 +14,8 @@ params.kitVersion = 'three' params.version = '3.0.2' params.astrocyte = false params.outDir = "$baseDir/output" +params.multiqc = "$baseDir/conf/multiqc_config.yaml" +params.references = "$baseDir/../docs/references.md" // Assign variables if astrocyte if (params.astrocyte) { @@ -54,6 +56,8 @@ forceCells = params.forceCells chemistryParam = params.chemistryParam version = params.version outDir = params.outDir +multiqc = params.multiqc +references = params.references process checkDesignFile { @@ -121,6 +125,7 @@ process count211 { output: file("**/outs/**") into outPaths211 + file("*_metrics_summary.tsv") into metricsSummary211 when: version == '2.1.1' @@ -132,6 +137,7 @@ process count211 { ulimit -a bash "$baseDir/scripts/filename_check.sh" -r "$ref" cellranger count --id="$sample" --transcriptome="./$ref" --fastqs=. --sample="$sample" --expect-cells=$expectCells211 + sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv """ } else { """ @@ -139,6 +145,7 @@ process count211 { ulimit -a bash "$baseDir/scripts/filename_check.sh" -r "$ref" cellranger count --id="$sample" --transcriptome="./$ref" --fastqs=. --sample="$sample" --force-cells=$forceCells211 + sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv """ } } @@ -160,6 +167,7 @@ process count301 { output: file("**/outs/**") into outPaths301 + file("*_metrics_summary.tsv") into metricsSummary301 when: version == '3.0.1' @@ -171,6 +179,7 @@ process count301 { ulimit -a bash "$baseDir/scripts/filename_check.sh" -r "$ref" cellranger count --id="$sample" --transcriptome="./$ref" --fastqs=. --sample="$sample" --expect-cells=$expectCells301 --chemistry="$chemistryParam301" + sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv """ } else { """ @@ -178,6 +187,7 @@ process count301 { ulimit -a bash "$baseDir/scripts/filename_check.sh" -r "$ref" cellranger count --id="$sample" --transcriptome="./$ref" --fastqs=. --sample="$sample" --force-cells=$forceCells301 --chemistry="$chemistryParam301" + sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv """ } } @@ -199,6 +209,7 @@ process count302 { output: file("**/outs/**") into outPaths302 + file("*_metrics_summary.tsv") into metricsSummary302 when: version == '3.0.2' @@ -210,6 +221,7 @@ process count302 { ulimit -a bash "$baseDir/scripts/filename_check.sh" -r "$ref" cellranger count --id="$sample" --transcriptome="./$ref" --fastqs=. --sample="$sample" --expect-cells=$expectCells302 --chemistry="$chemistryParam302" + sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv """ } else { """ @@ -217,6 +229,57 @@ process count302 { ulimit -a bash "$baseDir/scripts/filename_check.sh" -r "$ref" cellranger count --id="$sample" --transcriptome="./$ref" --fastqs=. --sample="$sample" --force-cells=$forceCells302 --chemistry="$chemistryParam302" + sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv """ } } + + +process versions { + tag "$name" + publishDir "$outDir/${task.process}", mode: 'copy' + module 'python/3.6.1-2-anaconda:pandoc/2.7:multiqc/1.7' + + input: + + output: + + file("*.yaml") into yamlPaths + + script: + + """ + hostname + ulimit -a + echo $workflow.nextflow.version > version_nextflow.txt + echo $version > version_cellranger.txt + multiqc --version | tr -d 'multiqc, version ' > version_multiqc.txt + python3 "$baseDir/scripts/generate_versions.py" -f version_*.txt -o versions + python3 "$baseDir/scripts/generate_references.py" -r "$references" -o references + """ +} + +metricsSummary = metricsSummary211.mix(metricsSummary301, metricsSummary302) + +// Generate MultiQC Report +process multiqcReport { + publishDir "$outDir/${task.process}", mode: 'copy' + + input: + + file ('*') from metricsSummary.collect() + file yamlPaths + + output: + + file "multiqc_report.html" into multiqcReport + + script: + + """ + awk 'FNR==1 && NR!=1{next;}{print}' *.tsv > metrics_summary_mqc.tsv + sed -i '1s/^.*\tE/Sample\tE/' metrics_summary_mqc.tsv + module load multiqc/1.7 + multiqc -c $multiqc . + """ +} diff --git a/workflow/scripts/generate_references.py b/workflow/scripts/generate_references.py new file mode 100644 index 0000000..001c535 --- /dev/null +++ b/workflow/scripts/generate_references.py @@ -0,0 +1,71 @@ +# +# * -------------------------------------------------------------------------- +# * Licensed under MIT (https://git.biohpc.swmed.edu/BICF/Astrocyte/cellranger_count/LICENSE.md) +# * -------------------------------------------------------------------------- +# + +'''Make header for HTML of references.''' + +import argparse +import subprocess +import shlex +import logging + +EPILOG = ''' +For more details: + %(prog)s --help +''' + +# SETTINGS + +logger = logging.getLogger(__name__) +logger.addHandler(logging.NullHandler()) +logger.propagate = False +logger.setLevel(logging.INFO) + + +def get_args(): + '''Define arguments.''' + + parser = argparse.ArgumentParser( + description=__doc__, epilog=EPILOG, + formatter_class=argparse.RawDescriptionHelpFormatter) + + parser.add_argument('-r', '--reference', + help="The reference file (markdown format).", + required=True) + + parser.add_argument('-o', '--output', + help="The out file name.", + default='references') + + args = parser.parse_args() + return args + + +def main(): + args = get_args() + reference = args.reference + output = args.output + + out_filename = output + '_mqc.yaml' + + # Header for HTML + print(''' + id: 'Software References' + section_name: 'Software References' + description: 'This section describes references for the tools used.' + plot_type: 'html' + data: | + ''' + , file = open(out_filename, "w") + ) + + # Turn Markdown into HTML + references_html = 'bash -c "pandoc -p {} | sed \'s/^/ /\' >> {}"' + references_html = references_html.format(reference, out_filename) + subprocess.check_call(shlex.split(references_html)) + + +if __name__ == '__main__': + main() diff --git a/workflow/scripts/generate_versions.py b/workflow/scripts/generate_versions.py new file mode 100644 index 0000000..6e5d9ea --- /dev/null +++ b/workflow/scripts/generate_versions.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +'''Make YAML of software versions.''' + +from __future__ import print_function +from collections import OrderedDict +import re +import logging +import argparse +import numpy as np + +EPILOG = ''' +For more details: + %(prog)s --help +''' + +# SETTINGS + +logger = logging.getLogger(__name__) +logger.addHandler(logging.NullHandler()) +logger.propagate = False +logger.setLevel(logging.INFO) + +SOFTWARE_REGEX = { + 'Nextflow': ['version_nextflow.txt', r"(\S+)"], + 'Cellranger Count': ['version_cellranger.txt', r"(\S+)"], + 'MultiQC': ['version_multiqc.txt', r"(\S+)"], +} + + +def get_args(): + '''Define arguments.''' + + parser = argparse.ArgumentParser( + description=__doc__, epilog=EPILOG, + formatter_class=argparse.RawDescriptionHelpFormatter) + + parser.add_argument('-f', '--files', + help="The version files.", + required=True, + nargs='*') + + parser.add_argument('-o', '--output', + help="The out file name.", + required=True) + + args = parser.parse_args() + return args + + +def check_files(files): + '''Check if version files are found.''' + + logger.info("Running file check.") + + software_files = np.array(list(SOFTWARE_REGEX.values()))[:,0] + + extra_files = set(files) - set(software_files) + + if len(extra_files) > 0: + logger.error('Missing regex: %s', list(extra_files)) + raise Exception("Missing regex: %s" % list(extra_files)) + + +def main(): + args = get_args() + files = args.files + output = args.output + + out_filename = output + '_mqc.yaml' + + results = OrderedDict() + results['Nextflow'] = '<span style="color:#999999;\">N/A</span>' + results['Cellranger Count'] = '<span style="color:#999999;\">N/A</span>' + results['MultiQC'] = '<span style="color:#999999;\">N/A</span>' + + # Check for version files: + check_files(files) + + # Search each file using its regex + for k, v in SOFTWARE_REGEX.items(): + with open(v[0]) as x: + versions = x.read() + match = re.search(v[1], versions) + if match: + results[k] = "v{}".format(match.group(1)) + + # Dump to YAML + print( + ''' + id: 'software_versions' + section_name: 'Software Versions' + section_href: 'https://git.biohpc.swmed.edu/BICF/Astrocyte/cellranger_count/' + plot_type: 'html' + description: 'are collected at run time from the software output.' + data: | + <dl class="dl-horizontal"> + ''' + , file = open(out_filename, "w")) + + for k, v in results.items(): + print(" <dt>{}</dt><dd>{}</dd>".format(k, v), file = open(out_filename, "a")) + print(" </dl>", file = open(out_filename, "a")) + + +if __name__ == '__main__': + main() -- GitLab