diff --git a/.gitignore b/.gitignore
index 0f456112..7f20e6ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,11 @@ work
# Python related files
*__pycache__*
-.venv
\ No newline at end of file
+.venv
+
+# R related files
+.Rproj.user
+htrnaseq.Rproj
+
+# vscode
+.vscode
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..14bce61b
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,9 @@
+# demultiplex v0.2.0
+
+# New functionality
+
+* Make sure that the Well ID matches the required format (PR #22).
+
+# demultiplex v0.1.0
+
+Initial release
diff --git a/README.md b/README.md
index 7bb25386..20d55213 100644
--- a/README.md
+++ b/README.md
@@ -122,3 +122,8 @@ nextflow run . -main-script target/nextflow/workflows/htrnaseq/main.nf \
```
Or, by running `src/workflows/htrnaseq/integration_test.sh`.
+
+
+# Special Thanks
+
+Developed in collaboration with Data Intuitive and Open Analytics.
\ No newline at end of file
diff --git a/src/base/authors/dries_schaumont.yaml b/src/base/authors/dries_schaumont.yaml
new file mode 100644
index 00000000..c8eaa47d
--- /dev/null
+++ b/src/base/authors/dries_schaumont.yaml
@@ -0,0 +1,11 @@
+name: Dries Schaumont
+info:
+ links:
+ email: dries@data-intuitive.com
+ github: DriesSchaumont
+ orcid: "0000-0002-4389-0440"
+ linkedin: dries-schaumont
+ organizations:
+ - name: Data Intuitive
+ href: https://www.data-intuitive.com
+ role: Data Scientist
\ No newline at end of file
diff --git a/src/base/authors/marijke_van_moerbeke.yaml b/src/base/authors/marijke_van_moerbeke.yaml
new file mode 100644
index 00000000..429bd926
--- /dev/null
+++ b/src/base/authors/marijke_van_moerbeke.yaml
@@ -0,0 +1,10 @@
+name: Marijke Van Moerbeke
+info:
+ links:
+ github: mvanmoerbeke
+ orcid: 0000-0002-3097-5621
+ linkedin: marijke-van-moerbeke-84303a34
+ organizations:
+ - name: OpenAnalytics
+ href: https://www.openanalytics.eu
+ role: Statistical Consultant
\ No newline at end of file
diff --git a/src/base/authors/toni_verbeiren.yaml b/src/base/authors/toni_verbeiren.yaml
new file mode 100644
index 00000000..aa78550d
--- /dev/null
+++ b/src/base/authors/toni_verbeiren.yaml
@@ -0,0 +1,10 @@
+name: Toni Verbeiren
+info:
+ role: Core Team Member
+ links:
+ github: tverbeiren
+ linkedin: verbeiren
+ organizations:
+ - name: Data Intuitive
+ href: https://www.data-intuitive.com
+ role: Data Scientist and CEO
\ No newline at end of file
diff --git a/src/config/labels.config b/src/config/labels.config
index 66f5e21c..2821ec46 100644
--- a/src/config/labels.config
+++ b/src/config/labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/src/eset/create_eset/config.vsh.yaml b/src/eset/create_eset/config.vsh.yaml
index f6848dd3..194c2bce 100644
--- a/src/eset/create_eset/config.vsh.yaml
+++ b/src/eset/create_eset/config.vsh.yaml
@@ -1,5 +1,10 @@
name: create_eset
namespace: "eset"
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ maintainer ]
+ - __merge__: /src/base/authors/marijke_van_moerbeke.yaml
+ roles: [ author ]
argument_groups:
- name: "Arguments"
arguments:
diff --git a/src/eset/create_eset/test_data/pData.tsv b/src/eset/create_eset/test_data/pData.tsv
index e7fe4de3..3bfc64e0 100644
--- a/src/eset/create_eset/test_data/pData.tsv
+++ b/src/eset/create_eset/test_data/pData.tsv
@@ -1,3 +1,3 @@
-WellBC NumberOfMTReads pctMT NumberOfERCCReads pctERCC NumberOfChromReads pctChrom NumberOfInputReads NumberOfMappedReads PctMappedReads NumberOfReadsMappedToMultipleLoci PectOfReadsMappedToMultipleLoci NumberOfReadsMappedToTooManyLoci PectOfReadsMappedToTooManyLoci NumberOfReadsUnmappedTooManyMismatches PectOfReadsUnmappedTooManyMismatches NumberOfReadsUnmappedTooShort PectOfReadsUnmappedTooShort NumberOfReadsUnmappedOther PectOfReadsUnmappedOther ReadsWithValidBarcodes SequencingSaturation Q30BasesInCB+UMI ReadsMappedToTranscriptome:Unique+MultipeGenes EstimatedNumberOfCells FractionOfReadsInCells MeanReadsPerCell NumberOfUMIs NumberOfGenes NumberOfCountedReads
-AACAAGGTAC 0 0 0 0 8542 100 141303 23749 16.81 0 0 8458 5.99 0 0 109035 77.16 61 0.04 0.999816 0.0698056 0.979965 0.0618175 1 1 8538 7942 408 9535
-ACGCCTTCGT 0 0 0 0 5863 100 96430 16869 17.49 0 0 6124 6.35 0 0 73375 76.09 62 0.06 0.999782 0.0665302 0.980077 0.0620969 1 1 5862 5472 377 6463
+WellBC WellID NumberOfMTReads pctMT NumberOfERCCReads pctERCC NumberOfChromReads pctChrom NumberOfInputReads NumberOfMappedReads PctMappedReads NumberOfReadsMappedToMultipleLoci PectOfReadsMappedToMultipleLoci NumberOfReadsMappedToTooManyLoci PectOfReadsMappedToTooManyLoci NumberOfReadsUnmappedTooManyMismatches PectOfReadsUnmappedTooManyMismatches NumberOfReadsUnmappedTooShort PectOfReadsUnmappedTooShort NumberOfReadsUnmappedOther PectOfReadsUnmappedOther ReadsWithValidBarcodes SequencingSaturation Q30BasesInCB+UMI ReadsMappedToTranscriptome:Unique+MultipeGenes EstimatedNumberOfCells FractionOfReadsInCells MeanReadsPerCell NumberOfUMIs NumberOfGenes NumberOfCountedReads
+AACAAGGTAC A1 0 0 0 0 8542 100 141303 23749 16.81 0 0 8458 5.99 0 0 109035 77.16 61 0.04 0.999816 0.0698056 0.979965 0.0618175 1 1 8538 7942 408 9535
+ACGCCTTCGT B2 0 0 0 0 5863 100 96430 16869 17.49 0 0 6124 6.35 0 0 73375 76.09 62 0.06 0.999782 0.0665302 0.980077 0.0620969 1 1 5862 5472 377 6463
diff --git a/src/eset/create_fdata/config.vsh.yaml b/src/eset/create_fdata/config.vsh.yaml
index f9cff04f..9a5651d4 100644
--- a/src/eset/create_fdata/config.vsh.yaml
+++ b/src/eset/create_fdata/config.vsh.yaml
@@ -2,6 +2,11 @@ name: create_fdata
namespace: eset
description: |
Create a fdata file
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ maintainer ]
+ - __merge__: /src/base/authors/marijke_van_moerbeke.yaml
+ roles: [ contributor ]
arguments:
- name: "--gtf"
type: file
diff --git a/src/eset/create_pdata/config.vsh.yaml b/src/eset/create_pdata/config.vsh.yaml
index 1dd868b6..48933e37 100644
--- a/src/eset/create_pdata/config.vsh.yaml
+++ b/src/eset/create_pdata/config.vsh.yaml
@@ -2,6 +2,11 @@ name: create_pdata
namespace: eset
description: |
Create a pdata file by combining the mapping statistics
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ maintainer ]
+ - __merge__: /src/base/authors/marijke_van_moerbeke.yaml
+ roles: [ contributor ]
arguments:
- name: "--star_stats_file"
type: file
diff --git a/src/eset/create_pdata/create_pdata.py b/src/eset/create_pdata/create_pdata.py
index 34d3cdd3..8f703648 100644
--- a/src/eset/create_pdata/create_pdata.py
+++ b/src/eset/create_pdata/create_pdata.py
@@ -33,7 +33,7 @@ def main(par):
logger.info("Reads per gene and chromosome table contains information for the following barcodes: %s",
", ".join(reads_and_genes_per_chr_stats.index))
logger.info("Filtering mapping statistics file columns.")
- cols_to_keep = ("NumberOfMTReads", "pctMT", "NumberOfERCCReads",
+ cols_to_keep = ("WellID", "NumberOfMTReads", "pctMT", "NumberOfERCCReads",
"pctERCC", "NumberOfChromReads", "pctChrom")
try:
reads_and_genes_per_chr_stats = reads_and_genes_per_chr_stats.loc[:,cols_to_keep]
diff --git a/src/eset/create_pdata/nrReadsNrGenesPerChromPool.txt b/src/eset/create_pdata/nrReadsNrGenesPerChromPool.txt
index ee68ce33..0b678058 100644
--- a/src/eset/create_pdata/nrReadsNrGenesPerChromPool.txt
+++ b/src/eset/create_pdata/nrReadsNrGenesPerChromPool.txt
@@ -1,8 +1,8 @@
-WellBC 20 pctChrom pctMT pctERCC SumReads NumberOfGenes NumberOfERCCReads NumberOfChromReads NumberOfMTReads
-AACAAGGTAC 8542 100 0 0 8542 408 0 8542 0
-ACGCCTTCGT 5863 100 0 0 5863 377 0 5863 0
-CCATACTGAC 7396 100 0 0 7396 391 0 7396 0
-GCAAGCGAAT 10092 100 0 0 10092 420 0 10092 0
-GTCTCGAGTG 470 100 0 0 470 150 0 470 0
-TGCGCTCATT 7650 100 0 0 7650 407 0 7650 0
-TTGTGTTCGA 9422 100 0 0 9422 420 0 9422 0
+WellBC WellID 20 pctChrom pctMT pctERCC SumReads NumberOfGenes NumberOfERCCReads NumberOfChromReads NumberOfMTReads
+AACAAGGTAC A1 8542 100 0 0 8542 408 0 8542 0
+ACGCCTTCGT A2 5863 100 0 0 5863 377 0 5863 0
+CCATACTGAC A3 7396 100 0 0 7396 391 0 7396 0
+GCAAGCGAAT B1 10092 100 0 0 10092 420 0 10092 0
+GTCTCGAGTG C5 470 100 0 0 470 150 0 470 0
+TGCGCTCATT D6 7650 100 0 0 7650 407 0 7650 0
+TTGTGTTCGA E19 9422 100 0 0 9422 420 0 9422 0
diff --git a/src/eset/create_pdata/test.py b/src/eset/create_pdata/test.py
index 7385df8f..5f1e3bb4 100644
--- a/src/eset/create_pdata/test.py
+++ b/src/eset/create_pdata/test.py
@@ -43,6 +43,7 @@ def test_create_fdata(run_component, test_reads_and_genes_per_chr_path,
expected_dict = {
'WellBC': ['AACAAGGTAC', 'ACGCCTTCGT', 'CCATACTGAC', 'GCAAGCGAAT',
'GTCTCGAGTG', 'TGCGCTCATT', 'TTGTGTTCGA'],
+ 'WellID': ['A1', 'A2', 'A3', 'B1', 'C5', 'D6', 'E19'],
'NumberOfMTReads': ['0', '0', '0', '0', '0', '0', '0'],
'pctMT': ['0', '0', '0', '0', '0', '0', '0'],
'NumberOfERCCReads': ['0', '0', '0', '0', '0', '0', '0'],
diff --git a/src/integration_test_components/htrnaseq/check_eset/config.vsh.yaml b/src/integration_test_components/htrnaseq/check_eset/config.vsh.yaml
index 1b470ad4..9c5b6d94 100644
--- a/src/integration_test_components/htrnaseq/check_eset/config.vsh.yaml
+++ b/src/integration_test_components/htrnaseq/check_eset/config.vsh.yaml
@@ -1,6 +1,9 @@
name: "check_eset"
namespace: "integration_test_components/htrnaseq"
description: "This component test the ExpressionSet object as output by the main pipeline."
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ author, maintainer ]
argument_groups:
- name: Inputs
arguments:
diff --git a/src/integration_test_components/htrnaseq/check_eset/script.R b/src/integration_test_components/htrnaseq/check_eset/script.R
index 179195bf..a5be5613 100644
--- a/src/integration_test_components/htrnaseq/check_eset/script.R
+++ b/src/integration_test_components/htrnaseq/check_eset/script.R
@@ -129,6 +129,7 @@ stopifnot(identical(sampleNames(sample_1_result), expected_sample_names))
expected_var_labels <- c(
"WellBC",
+ "WellID",
"NumberOfMTReads",
"pctMT",
"NumberOfERCCReads",
diff --git a/src/parallel_map/config.vsh.yaml b/src/parallel_map/config.vsh.yaml
index 8856f4ad..aee6457f 100644
--- a/src/parallel_map/config.vsh.yaml
+++ b/src/parallel_map/config.vsh.yaml
@@ -3,6 +3,11 @@ description: |
Map wells in batch, using STAR
Spliced Transcripts Alignment to a Reference (C) Alexander Dobin
https://github.com/alexdobin/STAR
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ maintainer ]
+ - __merge__: /src/base/authors/toni_verbeiren.yaml
+ roles: [ author, maintainer ]
requirements:
commands:
- STAR
diff --git a/src/report/OutputSTARsolo.png b/src/report/OutputSTARsolo.png
new file mode 100644
index 00000000..cb77d8e0
Binary files /dev/null and b/src/report/OutputSTARsolo.png differ
diff --git a/src/report/config.vsh.yaml b/src/report/config.vsh.yaml
new file mode 100644
index 00000000..cf0efbd7
--- /dev/null
+++ b/src/report/config.vsh.yaml
@@ -0,0 +1,73 @@
+name: create_report
+namespace: "report"
+description: |
+ Create a basic QC report in HTML format based on a number of esets.
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ maintainer ]
+ - __merge__: /src/base/authors/marijke_van_moerbeke.yaml
+ roles: [ author, maintainer ]
+argument_groups:
+ - name: "Arguments"
+ arguments:
+ - type: file
+ name: "--eset"
+ required: true
+ multiple: true
+ - type: file
+ name: "--output_report"
+ required: true
+ direction: output
+ example: report.html
+resources:
+ - type: r_script
+ path: script.R
+ - type: r_script
+ path: template.Rmd
+ - type: r_script
+ path: plateLayouts.R
+ - path: OutputSTARsolo.png
+ type: file
+test_resources:
+ - type: r_script
+ path: test.R
+ - path: ./test_data
+engines:
+ - type: docker
+ image: rocker/r2u:24.04
+ setup:
+ - type: apt
+ packages:
+ - procps
+ - pandoc
+ - type: r
+ bioc:
+ - Biobase
+ - ComplexHeatmap
+ cran:
+ - ggplot2
+ - knitr
+ - gridExtra
+ - RColorBrewer
+ - processx
+ - whisker
+ - rmarkdown
+ - bookdown
+ - data.table
+ - platetools
+ - htmltools
+ - DT
+ - logger
+ - bit64
+ script:
+ - install.packages("oaStyle", repos = c(rdepot = "https://repos.openanalytics.eu/repo/public", getOption("repos")))
+ test_setup:
+ - type: r
+ packages:
+ - testthat
+ - R.utils
+runners:
+ - type: executable
+ - type: nextflow
+
+
\ No newline at end of file
diff --git a/src/report/plateLayouts.R b/src/report/plateLayouts.R
new file mode 100644
index 00000000..c8b16cff
--- /dev/null
+++ b/src/report/plateLayouts.R
@@ -0,0 +1,424 @@
+
+#' Displays the annotation of the wells in a plateLayout
+#' @param plateData a data.table object containing the information
+#' of the plate. This must contain a "WellID".
+#' @param plateName The plate name
+#' @param valueVariable The name of the variable in 'plateData' to
+#' be visualized in a plate layout.
+#' @param textVariable The name of the variable in 'plateData' to be
+#' shown in the wells of the plate layout. If NULL, the valueVariable
+#' is shown.
+#' @param colours A named character vector containing the colours
+#' for the different levels of the valuevariable. The names should
+#' correspond to the dose levels. if not specified, a scheme of blues
+#' will be provided.
+#' @param breaks Numeric vector indicating breaks for plot coloring.
+#' @param colourWellText Colour to display the text in the wells.
+#' @param layout Integer vector of length two with number of rows and
+#' colums in a plate, e.g. \code{c(16,24)}
+#' @param legend.title A title for the legend
+#' @param plot.title A title for the plot, will be contracted
+#' with the plate name
+#' @param ... additional arguments for \code{plateLayout.default} function
+#' @import data.table
+#' @importFrom platetools fill_plate
+#' @export
+plateLayout.annotation <- function(
+ plateData,
+ plateName = character(),
+ valueVariable = "Dose",
+ textVariable = NULL,
+ breaks = NULL, colours = NULL,
+ colourWellText = "black",
+ layout = c(16, 24),
+ legend.title = "Dose",
+ plot.title = "Plate Annotation - ",
+ textFontSize = 9, ...
+) {
+ WellID <- Label <- NULL
+
+ if (!(all(c("WellID", "SampleName") %in% colnames(plateData)))) {
+ stop(" 'WellID' and 'SampleName' column required in plateData object")
+ }
+
+
+ plateData[, WellID := paste0(
+ sub(".*([[:alpha:]]).+", "\\1", plateData$WellID),
+ sprintf(
+ "%02d", as.numeric(sub(".*[[:alpha:]](.+)", "\\1", plateData$WellID))
+ )
+ )]
+
+ plateData <- platetools::fill_plate(plateData, "WellID", plate = 384)
+
+ plateData$column <- factor(
+ sprintf(
+ "%02d",
+ as.numeric(sub(".*[[:alpha:]](.+)", "\\1", plateData$WellID))
+ ),
+ levels = sprintf("%02d", seq(1, layout[2]))
+ )
+ plateData$row <- factor(sub(".*([[:alpha:]]).+", "\\1", plateData$WellID),
+ levels = LETTERS[seq(1, layout[1])])
+
+ if (!is.null(valueVariable)){
+ plateData[, values := as.character(plateData[, ..valueVariable][[1]])]
+ valueVar <- "values"
+ }else{
+ plateData[, values := "grey"]
+ valueVar <- "values"
+ colours <- setNames("grey", "grey")
+ }
+
+
+ if (is.null(colours)) {
+
+ blues <- colorRampPalette(c("#d6e0ff", "#2171B5"))
+ greens <- colorRampPalette(c("light green", "dark green"))
+
+ numLevels <- sort(as.numeric(as.character(unique(plateData[, values])[
+ grepl(
+ "^[[:digit:]]+([.][[:digit:]]+)?$",
+ trimws(unique(plateData[, values]))
+ )
+ ])))
+ otherLevels <- sort(as.character(unique(plateData[, values])[
+ !grepl(
+ "^[[:digit:]]+([.][[:digit:]]+)?$",
+ trimws(unique(plateData[,values]))
+ )
+ ]))
+
+ colours <- c(blues(length(numLevels)), greens(length(otherLevels)), "red")
+ names(colours) <- c(numLevels, otherLevels, "failed")
+ }
+
+ if (!is.null(textVariable)) {
+ plateData[,
+ Label := do.call(paste, c(.SD, sep = "\n ")),
+ .SDcols = textVariable
+ ]
+ plateData[, Label := gsub("-", "-\n", Label)]
+ plateData[, Label := gsub("_", "_\n", Label)]
+ textVar <- "Label"
+ } else {
+ textVar <- NULL
+ }
+
+
+ if (is.null(breaks)){
+ breaks <- seq_len(length(colours))
+ }
+
+ plateLayout(
+ plateData = plateData, valueVariable = valueVar,
+ textVariable = textVar, plateName = plateName,
+ breaks = breaks, colourWellText = colourWellText,
+ legend.title = legend.title, layout = layout,
+ colours = colours, plot.title = plot.title,
+ textFontSize = textFontSize, ...
+ )
+}
+
+
+
+#' Create a heatmap of values in a plateLayout view. The values can be
+#' library sizes, number of genes, qcScore (0/1) or a factor.
+#' @param plateData A data.table of the values to be visualized with
+#' at least the column of interest (specified in 'varOfInterest')
+#' and a 'WellID' column indicating the wells in the plate. The WellID
+#' is a combination of a letter (row in the plate) and an integer
+#' (column in the plate).
+#' @param valueVariable The name of the variable in 'plateData'
+#' to be visualized in a plate layout
+#' @param textVariable The name of the variable in 'plateData'
+#' to be shown in the wells of the plate layout. Defaults to the
+#' valueVariable and if NULL, no text will be displayed.
+#' @param breaks Numeric vector indicating breaks for plot coloring.
+#' @param colours Colours to be used for levels specified by
+#' the breaks. If NULL, a colour scheme of purples is shown.
+#' @param colourWellText Colour to display the text in the wells.
+#' @param layout Integer vector of length two with number of rows
+#' and colums in a plate, e.g. \code{c(16,24)}
+#' @param makeContourColours Logical, whether or not the plate
+#' layout will contain a contour colours for the wells based on the
+#' parameters in 'contourColours' and 'categories'
+#' @param contourVariable The variable used for the contour colouring
+#' @param contourColours Character vector specifying a colour for
+#' each range in 'categories'
+#' @param labelsCategories Character vector specifying the names
+#' (labels) for each range in 'categories'
+#' @param categories if contour Variable is not a factor, a numeric
+#' vector specifying the categories to divide the 'varOfInterest',
+#' including the lower and upper limits.
+#' @param plateName The plate name
+#' @param plot.title A title for the plot, will be contracted with
+#' the plate name
+#' @param legend.title A title for the legend
+#' @param displayHeatmap Logical, whether to display the plateLayout heatmap
+#' @param saveHeatmap Logical, whether to save the plateLayout heatmap
+#' @param outputDir The directory where the plateLayout heatmap should be saved
+#' @param prefix The prefix to the file name of the saved plateLayout heatmap
+#' @param ... additional arguments for \code{ComplexHeatmap::Heatmap} function
+#' @importFrom platetools fill_plate
+#' @importFrom RColorBrewer brewer.pal
+#' @importFrom ComplexHeatmap Heatmap
+#' @importFrom circlize colorRamp2
+#' @importFrom grid grid.text grid.rect gpar legendGrob gpar
+#' @importFrom grDevices dev.off png
+#' @importFrom graphics title
+#' @export
+plateLayout <- function(
+ plateData, valueVariable, textVariable = valueVariable,
+ breaks = NULL, colours = NULL, colourWellText = "white", textFontSize = 6,
+ layout = c(16, 24), makeContourColours = FALSE, contourVariable = character(),
+ contourColours = c("red", "orange", "seagreen3"),lwdContours = c(1, 1, 1),
+ labelsCategories = c('1', '2', '3'), categories = NULL, plateName = character(),
+ plot.title = character(), legend.title = NULL, legendFontSize = 15,
+ row_split = rep("A", 16), col_split = rep("A", 24), legendFontSizeTitle = 15,
+ displayHeatmap = TRUE, saveHeatmap = FALSE, outputDir = ".", prefix = ""
+) {
+ WellID <- NULL
+ if (!(all(c("WellID", "SampleName") %in% colnames(plateData)))) {
+ stop(" 'WellID' and 'SampleName' column required in plateData object")
+ }
+
+
+ plateData[, WellID := paste0(
+ sub(".*([[:alpha:]]).+", "\\1", plateData$WellID),
+ sprintf(
+ "%02d",
+ as.numeric(sub(".*[[:alpha:]](.+)", "\\1", plateData$WellID))
+ )
+ )]
+
+ plateData <- platetools::fill_plate(plateData, "WellID", plate = 384)
+
+ plateData$column <- factor(
+ sprintf("%02d", as.numeric(
+ sub(".*[[:alpha:]](.+)", "\\1", plateData$WellID)
+ )),
+ levels = sprintf("%02d", seq(1, layout[2]))
+ )
+ plateData$row <- factor(sub(".*([[:alpha:]]).+", "\\1", plateData$WellID),
+ levels = LETTERS[seq(1, layout[1])])
+
+
+ plateValues <- plateLayoutFormat(
+ plateData,
+ varOfInterest = valueVariable,
+ rows = layout[1],
+ cols = layout[2]
+ )
+ if (!is.null(textVariable)) {
+ plateText <- plateLayoutFormat(
+ plateData, varOfInterest = textVariable,
+ rows = layout[1],
+ cols = layout[2]
+ )
+ }
+ plot.title <- gsub(
+ "^([a-z])", "\\U\\1",
+ gsub("([A-Z])", " \\1",
+ plot.title, perl = TRUE), perl = TRUE
+ )
+ mainTitle <- paste0(plot.title, plateName)
+ plateContourColours <- matrix("", nrow = layout[1], ncol = layout[2])
+
+ if (makeContourColours) {
+ contourData <- plateData[WellType %in% c("nonEmpty", "Treated Wells"), ]
+
+ if (is.numeric(contourData[, ..contourVariable][[1]])) {
+ contourData$contours <- cut(
+ contourData[, ..contourVariable][[1]],
+ categories, left = TRUE,
+ right = TRUE,
+ labels = labelsCategories)
+ }
+ else {
+ contourData$contours <- contourData[, ..contourVariable][[1]]
+ }
+ names(contourColours) <- labelsCategories
+ names(lwdContours) <- labelsCategories
+ for (i in seq_len(layout[1])) {
+ for (j in seq_len(layout[2])) {
+ tryCatch({
+ sampleHit <- which(
+ as.character(contourData$WellID) == paste0(
+ LETTERS[i], sprintf("%02d", j)
+ )
+ )
+ if (length(sampleHit) == 1) {
+ plateContourColours[i, j] <- as.character(
+ contourData[sampleHit,'contours'][[1]]
+ )
+ }
+ },
+ error = function(e) {
+ print(paste0(LETTERS[i], sprintf("%02d", j), " is missing."))
+ }
+ )
+ }
+ }
+ }
+
+ plateValues$contours <- plateContourColours
+ colnames(plateValues$values) <- seq_len(ncol(plateValues$values))
+
+ if (is.null(breaks)) {
+ breakValues <- plateValues$values
+ breakValues[which(is.na(breakValues))] <- 0
+ if (all(breakValues >= 0)) {
+ breaks <- computeBreaks(7, max(plateValues$values, na.rm = TRUE))
+ } else {
+ breaks <- quantile(plateValues$values, probs = seq(0, 1, 0.125))
+ }
+ }
+
+ if (is.null(colours)) {
+ colours <- tryCatch({
+ colorRamp2(
+ breaks = breaks,
+ colors = brewer.pal(length(breaks), "Purples")
+ )
+ },
+ error = function(cond) {
+ return(c("#9370DB", "white"))
+ })
+ }
+ ht <- Heatmap(
+ plateValues$values,
+ column_title = mainTitle, column_title_side = "top",
+ rect_gp = gpar(lwd = 0.4),
+ cluster_rows = FALSE, cluster_columns = FALSE,
+ col = colours, row_title = NULL,
+ row_split = row_split, column_split = col_split,
+ row_names_side = "left",
+ cluster_row_slices = FALSE,
+ cluster_column_slices = FALSE,
+ show_heatmap_legend = TRUE,
+ heatmap_legend_param = list(
+ title = ifelse(
+ is.null(legend.title),
+ paste0(valueVariable, "\n"),
+ paste0(legend.title, "\n")
+ ),
+ grid_height = unit(9, "mm"), border = "black",
+ labels_gp = gpar(fontsize = legendFontSize),
+ title_gp = gpar(fontsize = legendFontSizeTitle)
+ ),
+ cell_fun = function(j, i, x, y, width, height, fill) {
+ if (is.na(plateValues$values[i, j])) {
+ grid.rect(
+ x, y, width, height,
+ gp = gpar(fill = "white", alpha = 0.7, lwd = 0.7, col = "white")
+ )
+ }
+ else if (!is.null(textVariable)) {
+ grid.text(
+ plateText$values[i, j], x, y,
+ just = "centre",
+ gp = gpar(fontsize = textFontSize, col = colourWellText)
+ )
+ }
+ if (makeContourColours) {
+ if (!is.na(plateValues$contours[i, j])) {
+ grid.rect(
+ x, y, width, height,
+ gp = gpar(
+ col = contourColours[as.character(plateValues$contours[i, j])],
+ fill = NA,
+ lwd = lwdContours[as.character(plateValues$contours[i, j])]
+ )
+ )
+ }
+ }
+ }
+ )
+
+ if (displayHeatmap) {
+ print(ht)
+ }
+ if (saveHeatmap) {
+ png(
+ file.path(
+ outputDir,
+ paste0(prefix,gsub(" |-", "",plot.title), "_", plateName, ".png")
+ ),
+ width = 30, height = 10, units = "cm", res = 1200
+ )
+ print(ht)
+ dev.off()
+ }
+
+ return(ht)
+}
+
+
+#' Return numerical matrix with number of reads that corresponds to the
+#' plate layout
+#' @param data A data.frame of the values to be visualized with at least
+#' the columnof interest (specified in 'varOfInterest') and a 'WellID' column
+#' indicating the wells in the plate. The WellID is a combination of a
+#' letter (row in the plate) and an integer (column in the plate).
+#' @param varOfInterest The name of the variable in 'data' to be visualized
+#' in a plate layout
+#' @param rows number of rows in a plate layout
+#' @param cols number of columns in a plate layout
+#' @param verbose if \code{TRUE}, samples missing from the plate
+#' will be reported
+#' @export
+plateLayoutFormat <- function(
+ data, varOfInterest,
+ rows = 16, cols = 24,
+ verbose = FALSE
+) {
+ plateValues <- matrix(NA, nrow = rows, ncol = cols)
+ for (i in seq_len(rows)) {
+ for (j in seq_len(cols)) {
+ tryCatch({
+ sampleHit <- which(
+ as.character(data$WellID) == paste0(LETTERS[i], sprintf("%02d", j))
+ )
+ if(length(sampleHit) == 1){
+ plateValues[i, j] <- data[sampleHit, ..varOfInterest][[1]]
+ }
+ },
+ error = function(e) {
+ if (verbose == TRUE) {
+ print(paste0(LETTERS[i], sprintf("%02d", j), " is missing."))
+ }
+ }
+ )
+ }
+ }
+
+ row.names(plateValues) <- LETTERS[1:rows]
+ return(list("values" = plateValues))
+}
+
+
+
+#' Helper function to automate break selection for raw count data
+#'
+#' This function creates an exponentially increasing vector for given number
+#' breaks between zero and some element of choice. It is particularly useful for
+#' raw counts or raw counts per million.
+#'
+#' @param nBreaks Number of breaks to be generated
+#' @param maxElement Maximum value of data entries
+#' @export
+computeBreaks <- function(nBreaks, variable) {
+
+ maxElement <- max(variable, na.rm = TRUE)
+ if (length(unique(variable)) == 1) {
+ breaks <- c(0, 0.5, ifelse(maxElement < 1, 1, maxElement))
+ } else {
+ coefSystem <- solve(
+ rbind(c(1, 1), c(1, (nBreaks - 1)))) %*% c(0, log(maxElement)
+ )
+ coefExp <- c(exp(coefSystem[1]), coefSystem[2])
+ breaks <- coefExp[1] * exp((1:(nBreaks - 1)) * coefExp[2])
+ }
+ return(c(0, breaks))
+}
\ No newline at end of file
diff --git a/src/report/script.R b/src/report/script.R
new file mode 100644
index 00000000..7ab2a467
--- /dev/null
+++ b/src/report/script.R
@@ -0,0 +1,33 @@
+library(whisker)
+library(logger)
+
+log_info("Setting temporary directory to: {meta$temp_dir}")
+Sys.setenv(TMP = meta$temp_dir)
+temp_folder <- tempdir(check = TRUE)
+log_info("Created temporary directory {temp_folder}")
+
+template <- file.path(meta$resources_dir, "template.Rmd")
+
+esets_normalized <- lapply(par$eset, function(eset_path) {
+ return(file.path(normalizePath(dirname(eset_path)), basename(eset_path)))
+})
+
+log_info(paste0(
+ "Rendering markdown {template} to HTML ",
+ "{par$output_report} with esets {paste(esets_normalized, collapse = ', ')}"
+))
+
+rmarkdown::render(
+ normalizePath(template),
+ output_file = basename(par$output_report),
+ output_dir = dirname(par$output_report),
+ runtime = "static",
+ intermediates_dir = par$report_dir,
+ clean = TRUE,
+ params = list(
+ esets = esets_normalized,
+ outputDir = par$report_dir
+ )
+)
+
+log_info("Done")
diff --git a/src/report/template.Rmd b/src/report/template.Rmd
new file mode 100644
index 00000000..20f8c190
--- /dev/null
+++ b/src/report/template.Rmd
@@ -0,0 +1,977 @@
+---
+title: "Exploratory Data Report"
+date: "`r format(Sys.time(), '%d %B, %Y')`"
+editor_options:
+ chunk_output_type: console
+output:
+ oaStyle::html_report
+# parameters which are overwritten by the script
+params:
+ outputDir: 'output/'
+ esets:
+ - sample1.rds
+ - sample2.rds
+---
+
+
+
+
+
+
+
+
+
+```{r params, eval = TRUE, include = FALSE}
+outputDir <- params$outputDir
+esets <- params$esets
+```
+
+
+```{r outputDir, echo = FALSE}
+## Required: ABSOLUTE outputDir
+outputDir <- file.path(outputDir)
+
+# When working on a windows computer it should be
+# "/Users/..." instead of "C:/Users/..."
+if (.Platform$OS.type == "windows") {
+ outputDir <- paste0(
+ "/",
+ paste(
+ unlist(strsplit(outputDir, split = "/"))[-1], collapse = "/"
+ ),
+ "/"
+ )
+}
+```
+
+
+
+
+```{r optionsChunkDoNotModify, echo = FALSE, message = FALSE, warning=FALSE}
+
+## Chunk with options for knitr. This chunk should not be modified.
+knitr::opts_chunk$set(
+ eval = TRUE,
+ echo = FALSE,
+ message = FALSE,
+ cache = FALSE,
+ warning = FALSE,
+ error = FALSE,
+ comment = NA, #"#",
+ tidy = FALSE,
+ collapse = TRUE,
+ out.width = "100%",
+ fig.width = 20,
+ fig.height = 10,
+ results = "asis")
+
+knitr::opts_knit$set(root.dir = getwd())
+
+options(warn = 1, width = 200)
+
+```
+
+```{r libraries_and_functions}
+source("plateLayouts.R")
+library(ComplexHeatmap)
+library(data.table)
+library(ggplot2)
+library(knitr)
+library(Biobase)
+library(gridExtra)
+library(RColorBrewer)
+```
+
+
+```{r dataImport}
+
+# Create esetList
+esetList <- sapply(
+ esets, simplify = FALSE,
+ USE.NAMES = TRUE,
+ function(eset_raw) {
+ if (!file.exists(eset_raw)) {
+ stop(paste0("Provided path '", eset_raw, "' is not a file."))
+ }
+ eset <- readRDS(eset_raw)
+ }
+)
+pools <- sapply(esetList, function(eset) {
+ unique(eset$PoolName)
+})
+names(esetList) <- unlist(pools)
+
+# Create qcData
+pDataList <- lapply(esetList, function(eset) data.table(pData(eset)))
+qcData <- rbindlist(pDataList, fill = TRUE)
+
+textVars <- "SampleName"
+annotationVar <- "PoolName"
+
+if (!"SampleName" %in% names(qcData)) {
+ qcData[, SampleName := paste0(PoolName, "_", WellBC)]
+}
+qcData[, log10LibSize := round(log10(NumberOfInputReads))]
+qcData[, (annotationVar) := lapply(.SD, as.factor), .SDcols = annotationVar]
+
+
+colourList <- list()
+Design_levels <- sort(
+ as.character(unique(qcData[, ..annotationVar][[1]])),
+ decreasing = TRUE
+)
+
+if (length(Design_levels) == 1) {
+ colours <- c("#d6e0ff", "lightgrey")
+ names(colours) <- c(Design_levels, "Empty")
+ colourList[[annotationVar]] <- list(
+ "colours" = colours,
+ "annotVar" = annotationVar,
+ "text" = textVars
+ )
+}else if (length(Design_levels) == 2) {
+ colours <- c("#d6e0ff", "#FF9999")
+
+ names(colours) <- c(Design_levels)
+ colourList[[annotationVar]] <- list(
+ "colours" = colours,
+ "annotVar" = annotationVar,
+ "text" = textVars
+ )
+} else if (length(Design_levels) <= 20) {
+
+ if (length(Design_levels) > 12) {
+ colours <- c(
+ brewer.pal(12, "Set3"),
+ brewer.pal((length(Design_levels) - 12),
+ "Pastel2")
+ )
+ } else {
+ colours <- c(brewer.pal(length(Design_levels), "Set3"))
+ }
+
+ names(colours) <- c(Design_levels)
+ colourList[[annotationVar]] <- list(
+ "colours" = colours,
+ "annotVar" = annotationVar,
+ "text" = textVars
+ )
+} else {
+ colours <- c("#d6e0ff")
+ names(colours) <- c("nonEmpty")
+ colourList[[annotVar]] <- list(
+ "colours" = colours,
+ "annotVar" = annotVar,
+ "text" = annotVar
+ )
+}
+```
+
+# Pool Description
+
+Per pool within this study, there are several pool layout plots shown, based on the
+
+* number of STAR input reads (= library size)
+
+* log10 transformed number of STAR input reads
+
+* number of detected UMIs
+
+* number of detected genes
+
+* number of chromosomal reads
+
+* percentage of ERCC
+
+* percentage of mitochondria
+
+
+> The values for the different samples within each pool is expected to be comparable if the content of the different pools is equally diverse.
+
+```{r plateAnnotation, out.width = "100%",fig.width = 20, fig.height= 10}
+
+plateVars <- c("NumberOfInputReads", "log10LibSize", "NumberOfMappedReads",
+ "NumberOfChromReads", "NumberOfUMIs", "NumberOfGenes",
+ "pctMT", "pctERCC")
+
+breaksVars <- lapply(
+ plateVars,
+ function(var) {
+ computeBreaks(7, qcData[, ..var])
+ }
+)
+names(breaksVars) <- plateVars
+
+for (pool in pools){
+ cat("\n\n")
+ cat(paste0("## ", pool, " {.tabset} \n\n"))
+ poolData <- qcData[PoolName == pool]
+ lapply(plateVars, function(plateVar) {
+ cat("\n\n")
+ cat(sprintf("### %s {.unnumbered}", plateVar))
+ cat("\n\n")
+ plateLayout(
+ poolData, valueVariable = plateVar,
+ textFontSize = 10, legendFontSize = 12,
+ plateName = pool, plot.title = "libSize - ",
+ legend.title = "libSize", breaks = breaksVars[[plateVar]]
+ )
+ cat("\n\n")
+ })
+ cat("\n\n")
+}
+```
+
+
+
+
+# Data Distributions
+
+
+## Reads Distributions {.tabset}
+
+The 4 box plots below represent the distributions per pool of the different samples based on:
+
+* the number of STAR input reads
+
+* the number of STAR mapped reads
+
+* the percentage of STAR mapped reads
+
+* the number of detected genes
+
+> The distributions contribute to the QC metrics mentioned in Par 3. The higher these values, the better.
+> The data range for the different plates is expected to be comparable if the content of the different plates is equally diverse.
+
+
+### Number of Input Reads {.tabset .unnumbered}
+
+```{r settings_1}
+
+nColPlots = 1
+figHeight = 7
+
+```
+
+#### Distribution {.tabset .unnumbered}
+
+
+```{r boxplots_input_plate, fig.height = figHeight}
+ggplot(
+ qcData,
+ aes(
+ x = PoolName,
+ y = NumberOfInputReads, colour = PoolName
+ )
+) + geom_boxplot() + ylab("Number of Input Reads") +
+ ggtitle("Number of Input Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+
+```
+
+
+### Number of Mapped Reads {.tabset .unnumbered}
+
+#### Distribution {.unnumbered}
+
+```{r boxplots_mapped_plate, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = PoolName, y = NumberOfMappedReads, colour = PoolName)
+) + geom_boxplot() + ylab("Number of Mapped Reads") +
+ ggtitle("Number of Mapped Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+
+#### pct Mapped Reads {.unnumbered}
+
+```{r boxplots_pctMapped_plate, fig.height = figHeight}
+ggplot(
+ qcData,
+ aes(x = PoolName, y = PctMappedReads, colour = PoolName)
+) +
+ geom_boxplot() +
+ ylab("pct Mapped Reads") +
+ ggtitle("pct Mapped Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+### Number of Chromosomal Reads {.tabset .unnumbered}
+
+#### Distribution {.unnumbered}
+
+```{r boxplots_chrom_plate, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = PoolName, y = NumberOfChromReads, colour = PoolName)
+) + geom_boxplot() + ylab("Number of Chromosomal Reads") +
+ ggtitle("Number of Chromosomal Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+
+```
+
+#### pct Chromosomal Reads {.unnumbered}
+
+```{r boxplots_pctChrom_plate, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = PoolName, y = pctChrom, colour = PoolName)
+) + geom_boxplot() + ylab("pct Chromosomal Reads") +
+ ggtitle("pct Chromosomal Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+### Number of UMIs {.tabset .unnumbered}
+
+#### Distribution {.tabset .unnumbered}
+
+
+```{r boxplots_umi_plate, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = PoolName, y = NumberOfUMIs, colour = PoolName)
+) + geom_boxplot() + ylab("Number of UMIs") +
+ ggtitle('Number of UMIs') +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+
+```
+
+#### Density distribution {.unnumbered}
+
+```{r density_numberOfUMIs}
+
+## Pre-filtering data exploration
+dt_plot <- melt(
+ qcData,
+ id.vars = c("SampleName", "PoolName", "WellID"),
+ measure.vars = c("NumberOfInputReads", "NumberOfMappedReads", "NumberOfUMIs")
+)
+
+readsDensity_plot <- ggplot(dt_plot, aes(value))
+readsDensity_plot <- readsDensity_plot +
+ geom_density(aes(fill = variable), alpha=0.8) +
+ facet_grid(~ PoolName, scales = "free_x", space = "fixed", drop = TRUE) +
+ geom_vline(
+ xintercept = 5e5,
+ linetype = "dashed",
+ color = "steelblue3", size = 2
+ ) +
+ annotate(
+ "text",
+ x = 3.5e5, y = 2e-6, label = "500k",
+ angle = 90, color = "steelblue3", size = 10
+ ) +
+ geom_vline(
+ xintercept = 1.5e6, linetype = "dashed",
+ color = "forestgreen", size = 2
+ ) +
+ annotate(
+ "text", x = 1.35e6, y = 2e-6, label = "1.5M",
+ angle = 90, color = "forestgreen", size = 10
+ ) +
+ labs(
+ title = "Density plot",
+ subtitle = paste0(
+ "# Samples with NumberOfMappedReads > 1.5M: ",
+ length(which(qcData$NumberOfMappedReads > 1.5e6)),
+ "\n# Samples with NumberOfUMIs > 500k: ",
+ length(which(qcData$NumberOfUMIs > 5e5))
+ ),
+ caption = paste0("# Total samples (after removing empty): ", nrow(qcData)),
+ x = "Count",
+ fill = "Variable"
+ ) +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 5),
+ axis.text.x = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ plot.subtitle = element_text(size = 17),
+ plot.caption = element_text(size = 15),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15),
+ axis.text.y = element_blank(),
+ axis.ticks.y = element_blank(),
+ axis.title.y = element_blank()
+ )
+readsDensity_plot
+
+```
+
+### Number of Genes {.tabset .unnumbered}
+
+#### Distribution {.unnumbered}
+
+```{r boxplots_genes_plate, fig.height = figHeight}
+ggplot(
+ qcData,
+ aes(x = PoolName, y = NumberOfGenes, colour = PoolName)
+) +
+ geom_boxplot() + ylab("Number of Genes") +
+ ggtitle("Number of Genes") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+## {.tabset .toc-ignore .unnumbered}
+
+
+In addition, several plots are shown visualizing the efficiency of the reads-to-genes translation:
+
+* the number of input reads vs the number of mapped reads
+
+* the number of chromosomal reads vs the number of mapped reads
+
+* the number of mapped reads per UMI vs the number of mapped reads
+
+* the number of UNI vs the number of mapped reads
+
+* the number of mapped reads vs the number of genes
+
+* the number of chromosomal reads vs the number of genes
+
+* the number of mapped reads per UMI vs the number of genes
+
+### Mapping Efficiency {.tabset .unnumbered}
+
+#### Number of Input Reads {.unnumbered}
+
+```{r mapping_efficiency_1_plate, fig.height = 7}
+
+ggplot(
+ qcData,
+ aes(x = NumberOfInputReads, y = NumberOfMappedReads, colour = PoolName)
+) +
+ geom_point() +
+ xlab("Number of Input Reads") +
+ ylab("Number of Mapped Reads") +
+ ggtitle("Number of Mapped Reads vs Number of Input Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+
+```
+
+
+#### Number of Chromosomal Reads {.unnumbered}
+
+```{r mapping_efficiency_2_plate, fig.height = 7}
+
+ggplot(
+ qcData,
+ aes(x = NumberOfChromReads, y = NumberOfMappedReads, colour = PoolName)
+) + geom_point() +
+ xlab("Number of Chromosomal Reads") + ylab("Number of Mapped Reads") +
+ ggtitle("Number of Chromosomal Reads vs Number of Mapped Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+)
+
+```
+
+
+#### Number of UMI {.unnumbered}
+
+```{r mapping_efficiency_4_plate, fig.height = 7}
+
+ggplot(
+ qcData,
+ aes(x =NumberOfUMIs, y = NumberOfMappedReads, colour = PoolName)
+) + geom_point() +
+ ylab("Number of Mapped Reads") + xlab("Number of UMIs ") +
+ ggtitle("Number of UMIs vs Number of Mapped Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+
+```
+
+### Counting Efficiency {.tabset .unnumbered}
+
+#### Number of Mapped Reads {.unnumbered}
+
+```{r gene_efficiency_1_plate, fig.height = 7}
+ggplot(
+ qcData,
+ aes(x = NumberOfMappedReads, y = NumberOfGenes, colour = PoolName)
+) + geom_point() +
+ ylab("Number of Genes") + xlab("Number of Mapped Reads") +
+ ggtitle("Number of Genes vs Number of Mapped Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+```
+
+#### Number of Chromosomal Reads {.unnumbered}
+
+```{r gene_efficiency_2_plate, fig.height = 7}
+ggplot(
+ qcData,
+ aes(x = NumberOfChromReads, y = NumberOfGenes, colour = PoolName)
+) + geom_point() +
+ ylab("Number of Genes") + xlab("Number of Chromosomal Reads") +
+ ggtitle("Number of Genes vs Number of Chromosomal Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+```
+
+
+
+## Sequencing Saturation {.tabset}
+
+The barplots below represent the sequencing saturation per sample as determined by STAR, split per pool.
+The HT-RNAseq platform aims for shallow sequencing resulting in relatively low sequencing saturations of 10-20%.
+In addition, the sequencing saturation vs the number of input reads is shown.
+
+### Sequencing Saturation {.unnumbered}
+
+
+
+```{r sequencingSaturation, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = WellID, y = SequencingSaturation, fill = PoolName)
+) + geom_bar(stat = "identity", position = "dodge") +
+ xlab("Samples") + ggtitle("Sequencing Saturation per Sample") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(1, "lines"),
+ text = element_text(size = 10),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.text.y = element_text(size = 15),
+ axis.ticks.x = element_blank()
+ )
+```
+
+### Sequencing Saturation - Input Reads {.unnumbered}
+
+
+```{r sequencingSaturation_inputReads, fig.height = figHeight}
+
+
+ggplot(
+ qcData,
+ aes(x = NumberOfInputReads, y = SequencingSaturation, colour = PoolName)
+) + geom_point() +
+ ggtitle("Sequencing Saturation vs Number of Input Reads") +
+ theme(strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+```
+
+### Sequencing Saturation - Mapped Reads {.unnumbered}
+
+```{r sequencingSaturation_mappedReads, fig.height = figHeight}
+ggplot(
+ qcData,
+ aes(x = NumberOfChromReads, y = SequencingSaturation, colour = PoolName)
+) + geom_point() +
+ ggtitle("Sequencing Saturation vs Number of Chromosomal Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size=10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size=18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+)
+```
+
+
+
+## Genomic Origin {.tabset}
+
+The 3 boxplots below represent, per pool, the distributions of the percentage of reads mapping to:
+
+* chromosomal regions
+
+* mitochondrial regions
+
+* ERCC spike-ins
+
+The 4th plot summarises the above results across samples per pool.
+
+The 5th plot shows the percentage of reads mapped to the transcriptome (as counted by STAR). This measurement serves as a proxy for the percentage of reads mapped to exons.
+
+> The percentage ERCC contributes to the QC metrics mentioned in Par 3. This value is ideally as low as possible (but non-zero to ensure the they have been spiked in) and comparable for the different pools.
+
+
+
+
+### pctChrom {.tabset .unnumbered}
+
+
+```{r genomicOrigin_chrom_plate, fig.height = figHeight}
+
+ggplot(
+ qcData, aes(x = PoolName, y = pctChrom, colour = PoolName)
+) +
+ geom_boxplot() +
+ ggtitle("pctChrom") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+
+### pctMT {.tabset .unnumbered}
+
+```{r genomicOrigin_mt_plate, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = PoolName, y = pctMT, colour = PoolName)
+) +
+ geom_boxplot() + ggtitle("pctMT") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+### pctERCC {.tabset .unnumbered}
+
+
+```{r genomicOrigin_ercc_plate, fig.height = figHeight}
+ggplot(qcData, aes(x = PoolName, y = pctERCC, colour = PoolName)) +
+ geom_boxplot() +
+ ggtitle("pctERCC") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+
+### Genomic Summary {.tabset .unnumbered}
+
+
+
+```{r genomicOrigin_summary_plate}
+meanPctChromMTData <- qcData[, .(
+ "pctChrom" = median(pctChrom),
+ "pctMT" = median(pctMT),
+ "pctERCC" = median(pctERCC)
+), by = PoolName]
+meanPctChromMTDataLong <- melt(
+ meanPctChromMTData,
+ id.vars = "PoolName",
+ measure.vars = c("pctChrom", "pctMT", "pctERCC"),
+ variable.name = "Origin", value.name = "pct"
+)
+ggplot(
+ meanPctChromMTDataLong,
+ aes(fill = Origin, y = pct, x = PoolName)) +
+ geom_bar(position = "stack", stat = "identity") +
+ ggtitle("Genomic Origin") +
+ theme(
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+
+```
+
+
+
+# Depletion {.tabset}
+
+
+```{r depletion}
+
+
+for (eset_name in pools) {
+ cat("\n\n")
+ cat(paste0("## ", eset_name, " {.unnumbered}"))
+ cat("\n\n")
+
+ eset <- esetList[[eset_name]]
+ average_reads <- sort(apply(exprs(eset), 1, mean), decreasing = TRUE)
+ plotData <- data.table(
+ ENSGID = names(average_reads),
+ av_count = average_reads
+ )
+
+ gen_descript <- data.table(
+ ENSGID = eset@featureData@data$gene_id,
+ Description = eset@featureData@data$GENENAME
+ )
+ order_gen_descript <- gen_descript[
+ match(plotData$ENSGID, gen_descript$ENSGID),
+ ]
+
+ g <- ggplot(
+ plotData[c(1:100)],
+ aes(x = reorder(ENSGID, -av_count), y = av_count)
+ ) + geom_bar(stat = "identity") +
+ theme(
+ axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1, size = 12),
+ axis.text.y = element_text(size = 12),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 15),
+ axis.title = element_text(size = 18),
+ plot.title = element_text(size = 20)
+ ) + ylab("Average Counts") + xlab("Genes")
+
+ print(g)
+
+ cat("\n\n")
+ cat("
")
+ cat("
")
+
+ print(htmltools::tagList((DT::datatable(order_gen_descript[1:100, ]))))
+}
+```
+
+
+
+
+
+
+
+
+# Glossary {.unnumbered}
+
+
+## Read {.unlisted .unnumbered}
+
+A read is a oligonucleotide (a short RNA fragment) that has been sequenced. It consists of a fixed number of base pairs (bp) and therefore has a specific read length.
+
+
+
+## Input Read {.unlisted .unnumbered}
+
+Each read of the fastq file used as input to the STAR aligner is considered an input read.
+
+
+
+## Read With Valid Barcode {.unlisted .unnumbered}
+
+A read with a valid barcode is a read for which the barcode matches the white list of barcodes under the given restriction of the number of allowed mismatches. The number of reads with a valid barcode is lower or equal to the number of input reads.
+
+
+
+## Mapped Read {.unlisted .unnumbered}
+
+A read that has been aligned against the reference genome and for which one or more suitable matching locations have been found is a mapped read. Depending on the number of allowed mismatches this might or might not be be an exact match. The number of mapped reads is lower or equal to the number of reads with a valid barcode.
+
+
+
+## Uniquely Mapped Read {.unlisted .unnumbered}
+
+A read for which one and only one suitable matching location in the reference genome was found is an uniquely mapped read. The number of uniquely mapped reads is lower or equal to the number of mapped reads.
+
+
+
+## Counted Read {.unlisted .unnumbered}
+
+A mapped read will only be counted if it overlaps (1 nucleotide or more) with one and only one gene. The number of counted reads is lower or equal to the number of (uniquely) mapped reads.
+
+
+
+## UMIs {.unlisted .unnumbered}
+
+Unique molecular identifiers (UMI) are short sequences in order to uniquely tag each molecule in a sample library. Sequencing with UMIs allows bioinformatics software to filter out duplicate reads and PCR errors with a high level of accuracy and report unique reads.
+
+The reported UMIs is the number of UMIs among the set of reads that map to an unique gene, i.e the number of reads is deduplicated.
+
+
+
+## pctERCC {.unlisted .unnumbered}
+
+The percentage of reads mapping to the ERCC genes among the total number of **mapped** reads.
+
+
+
+## pctMT {.unlisted .unnumbered}
+
+The percentage of reads mapping to the MT genes among the total number of **mapped** reads.
+
+
+
+## Sequencing Saturation {.unlisted .unnumbered}
+
+The sequencing saturation is a measure of the fraction of library complexity. The inverse of one minus the sequencing saturation can be interpreted as the number of additional reads it would take to detect a new transcript. Consequently, a low sequencing saturation indicates a shallow sequencing in which a new transcript could be discovered with a few reads.
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/report/test.R b/src/report/test.R
new file mode 100644
index 00000000..84c15694
--- /dev/null
+++ b/src/report/test.R
@@ -0,0 +1,41 @@
+library(whisker)
+library(testthat)
+library(R.utils)
+
+cat(">> Creating temporary directory \n")
+Sys.setenv(TMP = meta$temp_dir)
+temp_folder <- tempdir(check = TRUE)
+
+cat(">> Running component create_report for test case \n")
+
+input_dir <- file.path(meta$resources_dir, "test_data")
+stopifnot(file.exists(input_dir))
+
+
+out <- processx::run(meta$executable, c(
+ "--eset", file.path(meta$resources_dir, "test_data", "eset.sample_one.rds"),
+ "--eset", file.path(meta$resources_dir, "test_data", "eset.sample_two.rds"),
+ "--output_report", "report.html"
+))
+
+expect_equal(out$status, 0)
+expect_true(file.exists("report.html"))
+
+cat(">> Test succesful \n")
+
+cat(">> Running component create_report with symbolic links \n")
+
+link_sample_1 <- file.path(temp_folder, "eset.sample_one.rds")
+link_sample_2 <- file.path(temp_folder, "eset.sample_two.rds")
+createLink(link = link_sample_1,
+ target = file.path(meta$resources_dir, "test_data", "eset.sample_one.rds"))
+createLink(link = link_sample_2,
+ target = file.path(meta$resources_dir, "test_data", "eset.sample_two.rds"))
+
+out <- processx::run(meta$executable, c(
+ "--eset", link_sample_1,
+ "--eset", link_sample_2,
+ "--output_report", "report2.html"
+))
+
+expect_true(file.exists("report2.html"))
\ No newline at end of file
diff --git a/src/report/test_data/eset.sample_one.rds b/src/report/test_data/eset.sample_one.rds
new file mode 100644
index 00000000..f440362e
Binary files /dev/null and b/src/report/test_data/eset.sample_one.rds differ
diff --git a/src/report/test_data/eset.sample_two.rds b/src/report/test_data/eset.sample_two.rds
new file mode 100644
index 00000000..c622f216
Binary files /dev/null and b/src/report/test_data/eset.sample_two.rds differ
diff --git a/src/stats/combine_star_logs/config.vsh.yaml b/src/stats/combine_star_logs/config.vsh.yaml
index fb3fd831..61cf6c6c 100644
--- a/src/stats/combine_star_logs/config.vsh.yaml
+++ b/src/stats/combine_star_logs/config.vsh.yaml
@@ -1,5 +1,8 @@
name: combine_star_logs
namespace: "stats"
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ author, maintainer ]
argument_groups:
- name: "Arguments"
arguments:
diff --git a/src/stats/generate_pool_statistics/config.vsh.yaml b/src/stats/generate_pool_statistics/config.vsh.yaml
index 68f8fa8b..3c9263bc 100644
--- a/src/stats/generate_pool_statistics/config.vsh.yaml
+++ b/src/stats/generate_pool_statistics/config.vsh.yaml
@@ -1,5 +1,10 @@
name: generate_pool_statistics
namespace: "stats"
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ author, maintainer ]
+ - __merge__: /src/base/authors/marijke_van_moerbeke.yaml
+ roles: [ contributor ]
argument_groups:
- name: "Arguments"
arguments:
diff --git a/src/stats/generate_pool_statistics/script.py b/src/stats/generate_pool_statistics/script.py
index 92c4a4d4..48f68845 100644
--- a/src/stats/generate_pool_statistics/script.py
+++ b/src/stats/generate_pool_statistics/script.py
@@ -9,6 +9,8 @@ par = {
### VIASH END
+INDEX_COL = ["WellBC", "WellID"]
+
if __name__ == "__main__":
#########
# nrReadsNrGenesPerChrom file
@@ -18,17 +20,18 @@ if __name__ == "__main__":
nr_reads_nr_genes_wells.append(pd.read_csv(nr_reads_nr_genes_file,
header=0, delimiter="\t",
dtype={"WellBC": pd.StringDtype(),
+ "WellID": pd.StringDtype(),
"Chr": pd.StringDtype(),
"NumberOfReads": pd.UInt64Dtype(),
"NumberOfGenes": pd.UInt64Dtype()}))
nr_reads_nr_genes_pool = pd.concat(nr_reads_nr_genes_wells, ignore_index=True,)
- total_nr_reads_per_chromosome = nr_reads_nr_genes_pool.pivot_table(index="WellBC", columns="Chr",
+ total_nr_reads_per_chromosome = nr_reads_nr_genes_pool.pivot_table(index=INDEX_COL, columns="Chr",
values=["NumberOfReads"], fill_value=0,
aggfunc="sum").droplevel(0, axis=1)
total_nr_reads_per_chromosome.columns.name = None
##### Total number of genes from all chromosomes
- total_nr_genes = nr_reads_nr_genes_pool.loc[:,['WellBC', 'NumberOfGenes']].groupby("WellBC").sum()
+ total_nr_genes = nr_reads_nr_genes_pool.loc[:, INDEX_COL + ['NumberOfGenes']].groupby(["WellBC", "WellID"]).sum()
##### Total counts across (irrespective of chromosome)
total_sum_of_reads = total_nr_reads_per_chromosome.sum(numeric_only=True, axis=1)
@@ -77,9 +80,9 @@ if __name__ == "__main__":
**cols_to_add
)
- total_nr_reads_per_chromosome.reset_index(names="WellBC")\
+ total_nr_reads_per_chromosome.reset_index(names=INDEX_COL)\
.to_csv(par["nrReadsNrGenesPerChromPool"], sep="\t",
header=True, index=False, float_format="%g",
- columns=("WellBC",) + tuple(chromosome_names) + tuple(cols_to_add.keys())
+ columns=tuple(INDEX_COL) + tuple(chromosome_names) + tuple(cols_to_add.keys())
)
diff --git a/src/stats/generate_pool_statistics/test.py b/src/stats/generate_pool_statistics/test.py
index aa757870..de3a2683 100644
--- a/src/stats/generate_pool_statistics/test.py
+++ b/src/stats/generate_pool_statistics/test.py
@@ -1,6 +1,5 @@
from uuid import uuid4
from textwrap import dedent
-from io import StringIO
import pandas as pd
import pytest
import sys
@@ -35,14 +34,14 @@ def simple_input_file_one(random_tsv_path, request):
contents = dedent(
f"""\
- WellBC Chr NumberOfReads NumberOfGenes
- AGG {prefix}1 2 1
- AGG {prefix}2 3 2
- AGG {prefix}3 4 2
- AGG {mito_name} 4 2
- AGG {prefix}X 2 3
- AGG ERCC-1 1 1
- AGG ERCC-2 1 1
+ WellBC WellID Chr NumberOfReads NumberOfGenes
+ AGG A1 {prefix}1 2 1
+ AGG A1 {prefix}2 3 2
+ AGG A1 {prefix}3 4 2
+ AGG A1 {mito_name} 4 2
+ AGG A1 {prefix}X 2 3
+ AGG A1 ERCC-1 1 1
+ AGG A1 ERCC-2 1 1
""")
output_file = random_tsv_path()
with output_file.open("w") as open_file:
@@ -55,15 +54,15 @@ def simple_input_file_two(random_tsv_path, request):
prefix = request.param
contents = dedent(
f"""\
- WellBC Chr NumberOfReads NumberOfGenes
- CCC {prefix}2 2 1
- CCC {prefix}3 3 2
- CCC {prefix}5 4 2
- CCC {prefix}1 4 2
- CCC {prefix}Y 2 3
- CCC {prefix}X 2 3
- CCC ERCC-3 1 1
- CCC ERCC-2 1 1
+ WellBC WellID Chr NumberOfReads NumberOfGenes
+ CCC B2 {prefix}2 2 1
+ CCC B2 {prefix}3 3 2
+ CCC B2 {prefix}5 4 2
+ CCC B2 {prefix}1 4 2
+ CCC B2 {prefix}Y 2 3
+ CCC B2 {prefix}X 2 3
+ CCC B2 ERCC-3 1 1
+ CCC B2 ERCC-2 1 1
""")
output_file = random_tsv_path()
with output_file.open("w") as open_file:
@@ -85,6 +84,7 @@ def test_generate_pool_statistics_simple(run_component, simple_input_file_one,
mito_name = f"{expected}M{'T' if not expected else ''}"
expected_dict = {
"WellBC": ["AGG", "CCC"],
+ "WellID": ["A1", "B2"],
"ERCC-1": ["1", "0"],
"ERCC-2": ["1", "1"],
"ERCC-3": ["0", "1"],
@@ -118,11 +118,11 @@ def test_only_numerical_chromosomes(run_component, random_tsv_path):
output_path = random_tsv_path()
contents1 = dedent(
f"""\
- WellBC Chr NumberOfReads NumberOfGenes
- CCC 2 2 1
- CCC 3 3 2
- CCC 5 4 2
- CCC 1 4 2
+ WellBC WellID Chr NumberOfReads NumberOfGenes
+ CCC B2 2 2 1
+ CCC B2 3 3 2
+ CCC B2 5 4 2
+ CCC B2 1 4 2
""")
input_file_1 = random_tsv_path()
with input_file_1.open("w") as open_file:
@@ -130,11 +130,11 @@ def test_only_numerical_chromosomes(run_component, random_tsv_path):
contents2 = dedent(
f"""\
- WellBC Chr NumberOfReads NumberOfGenes
- AGG 2 2 1
- AGG 3 3 2
- AGG 5 4 2
- AGG 1 4 2
+ WellBC WellID Chr NumberOfReads NumberOfGenes
+ AGG A1 2 2 1
+ AGG A1 3 3 2
+ AGG A1 5 4 2
+ AGG A1 1 4 2
""")
input_file_2 = random_tsv_path()
with input_file_2.open("w") as open_file:
@@ -148,6 +148,7 @@ def test_only_numerical_chromosomes(run_component, random_tsv_path):
expected_dict = {
"WellBC": ["AGG", "CCC"],
+ "WellID": ["A1", "B2"],
"1": ["4", "4"],
"2": ["2", "2"],
"3": ["3", "3"],
diff --git a/src/stats/generate_well_statistics/config.vsh.yaml b/src/stats/generate_well_statistics/config.vsh.yaml
index c49bca3f..60904be8 100644
--- a/src/stats/generate_well_statistics/config.vsh.yaml
+++ b/src/stats/generate_well_statistics/config.vsh.yaml
@@ -1,6 +1,11 @@
name: generate_well_statistics
namespace: "stats"
description: Generate summary statistics from BAM files generated by STAR solo.
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ author, maintainer ]
+ - __merge__: /src/base/authors/marijke_van_moerbeke.yaml
+ roles: [ contributor ]
argument_groups:
- name: "Arguments"
arguments:
@@ -15,6 +20,11 @@ argument_groups:
The barcode for the well that is being processed. Is only used to add a metadata
column to all output files.
required: true
+ - name: "--well_id"
+ type: string
+ description: |
+ ID of this well. Only used to add a metadata column to the output files.
+ required: true
- name: "--processedBAMFile"
type: file
description: |
diff --git a/src/stats/generate_well_statistics/script.py b/src/stats/generate_well_statistics/script.py
index 95b2ac49..a1bcfff6 100644
--- a/src/stats/generate_well_statistics/script.py
+++ b/src/stats/generate_well_statistics/script.py
@@ -36,11 +36,11 @@ if __name__ == "__main__":
columns=tags_selection)
tag_dataframe_to_write = tag_dataframe.copy()
logger.info("Done reading BAM file. Found %i entries", tag_dataframe.shape[0])
- tag_dataframe.assign(WellBC=par["barcode"])\
+ tag_dataframe.assign(WellBC=par["barcode"], WellID=par["well_id"])\
.reset_index(names="Chr")\
.to_csv(par["processedBAMFile"], sep="\t", na_rep="",
header=True, index=False,
- columns=("WellBC", "Chr") + tags_selection)
+ columns=("WellBC", "WellID", "Chr") + tags_selection)
logger.info("Constructing of dataframe done.")
# Number of genes that had a read mapped to them per chromosome,
# and the number of reads mapped to those genes per chromosome.
@@ -50,19 +50,19 @@ if __name__ == "__main__":
)
logger.info("Done calculating number of reads per gene and per chromesome. Writing to %s",
par['nrReadsNrGenesPerChrom'])
- nr_reads_nr_genes.reset_index(names="Chr").assign(WellBC=par["barcode"])\
+ nr_reads_nr_genes.reset_index(names="Chr").assign(WellBC=par["barcode"], WellID=par["well_id"])\
.to_csv(par["nrReadsNrGenesPerChrom"], sep="\t",
header=True, index=False,
- columns=("WellBC", "Chr", "NumberOfReads", "NumberOfGenes"))
+ columns=("WellBC", "WellID", "Chr", "NumberOfReads", "NumberOfGenes"))
# Number of reads mapped to the reference, grouped by UMI
nr_read_per_umi = tag_dataframe.groupby('UB').size()\
.drop("", errors="ignore").sort_values(ascending=False).head(100)
nr_read_per_umi_df = nr_read_per_umi.to_frame(name="N")
logger.info("Done calculating number of mapped reads per UMI, writing to %s", par["umiFreqTop"])
- nr_read_per_umi_df.assign(WellBC=par["barcode"]).reset_index(names="UB")\
+ nr_read_per_umi_df.assign(WellBC=par["barcode"], WellID=par["well_id"]).reset_index(names="UB")\
.to_csv(par["umiFreqTop"], header=True, sep="\t",
- index=False, columns=("WellBC", "UB", "N"))
+ index=False, columns=("WellBC", "WellID", "UB", "N"))
# Total number of mapped reads and total number of UMIs (not grouped per chromosome)
nr_reads_and_umi_per_barcode = tag_dataframe.groupby(by="CB").agg(
@@ -71,7 +71,7 @@ if __name__ == "__main__":
)
logger.info("Done calculating number of mapped reads and number of UMIs per Cell Barcode, writing to %s",
par["nrReadsNrUMIsPerCB"])
- nr_reads_and_umi_per_barcode.assign(WellBC=par["barcode"]).reset_index(names="CB")\
+ nr_reads_and_umi_per_barcode.assign(WellBC=par["barcode"], WellID=par["well_id"]).reset_index(names="CB")\
.to_csv(par["nrReadsNrUMIsPerCB"], sep="\t", header=True,
- index=False, columns=("WellBC", "CB", "NumberOfReads", "nrUMIs"))
+ index=False, columns=("WellBC", "WellID", "CB", "NumberOfReads", "nrUMIs"))
logger.info("Finished!")
\ No newline at end of file
diff --git a/src/stats/generate_well_statistics/test.py b/src/stats/generate_well_statistics/test.py
index d84a22a2..aa1ad48c 100644
--- a/src/stats/generate_well_statistics/test.py
+++ b/src/stats/generate_well_statistics/test.py
@@ -63,7 +63,8 @@ def test_generate_well_statistics_simple_bam(run_component, input_sam_path, sam_
"--nrReadsNrGenesPerChrom", reads_per_chromosome,
"--nrReadsNrUMIsPerCB", nr_reads_nr_umis_per_cb,
"--umiFreqTop", top_onehundred_umis,
- "--barcode", "ACGT"
+ "--barcode", "ACGT",
+ "--well_id", "A1",
])
for file_path in (processed_bam, reads_per_chromosome,
nr_reads_nr_umis_per_cb, top_onehundred_umis):
@@ -71,33 +72,33 @@ def test_generate_well_statistics_simple_bam(run_component, input_sam_path, sam_
expected_processed_bam = \
dedent("""\
- WellBC Chr CB UB GX GN
- ACGT 1 ACA CGG gene1 gene1
- ACGT 1 ACA CGG gene1 gene1
- ACGT 2 GGG GTT gene2 gene2
- ACGT 2 GGG GTC gene3 gene3
+ WellBC WellID Chr CB UB GX GN
+ ACGT A1 1 ACA CGG gene1 gene1
+ ACGT A1 1 ACA CGG gene1 gene1
+ ACGT A1 2 GGG GTT gene2 gene2
+ ACGT A1 2 GGG GTC gene3 gene3
""")
expected_reads_per_chromosome = \
dedent("""\
- WellBC Chr NumberOfReads NumberOfGenes
- ACGT 1 2 1
- ACGT 2 2 2
+ WellBC WellID Chr NumberOfReads NumberOfGenes
+ ACGT A1 1 2 1
+ ACGT A1 2 2 2
""")
expected_nr_reads_nr_umis_per_cb = \
dedent("""\
- WellBC CB NumberOfReads nrUMIs
- ACGT ACA 2 1
- ACGT GGG 2 2
+ WellBC WellID CB NumberOfReads nrUMIs
+ ACGT A1 ACA 2 1
+ ACGT A1 GGG 2 2
""")
expected_top_onehundred_umis = \
dedent("""\
- WellBC UB N
- ACGT CGG 2
- ACGT GTC 1
- ACGT GTT 1
+ WellBC WellID UB N
+ ACGT A1 CGG 2
+ ACGT A1 GTC 1
+ ACGT A1 GTT 1
""")
assert_file_content_equals(processed_bam, expected_processed_bam)
diff --git a/src/workflows/htrnaseq/config.vsh.yaml b/src/workflows/htrnaseq/config.vsh.yaml
index d4523c77..e92f13ba 100644
--- a/src/workflows/htrnaseq/config.vsh.yaml
+++ b/src/workflows/htrnaseq/config.vsh.yaml
@@ -1,5 +1,8 @@
name: htrnaseq
namespace: workflows
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ maintainer ]
argument_groups:
- name: Input arguments
arguments:
@@ -74,6 +77,11 @@ argument_groups:
direction: output
required: true
default: pData.$id.tsv
+ - name: "--html_report"
+ type: file
+ direction: output
+ required: true
+ default: report.html
resources:
- type: nextflow_script
path: main.nf
@@ -101,6 +109,8 @@ dependencies:
repository: local
- name: eset/create_pdata
repository: local
+ - name: report/create_report
+ repository: local
repositories:
- name: local
type: local
diff --git a/src/workflows/htrnaseq/integration_test.sh b/src/workflows/htrnaseq/integration_test.sh
index 57f83a39..a5f68e1b 100755
--- a/src/workflows/htrnaseq/integration_test.sh
+++ b/src/workflows/htrnaseq/integration_test.sh
@@ -18,4 +18,4 @@ nextflow \
-entry test_wf \
-resume \
-profile docker,local \
- --publish_dir output \
+ --publish_dir output
diff --git a/src/workflows/htrnaseq/main.nf b/src/workflows/htrnaseq/main.nf
index 170b0f49..d6c1d64c 100644
--- a/src/workflows/htrnaseq/main.nf
+++ b/src/workflows/htrnaseq/main.nf
@@ -15,21 +15,6 @@ workflow run_wf {
// Perform mapping of each well. The input here are events per pool,
// the output channel is one event per well.
mapping_ch = input_ch
- | map {id, state ->
- def n_barcodes = state.barcodesFasta.countFasta() as int
- def newState = state + ["n_barcodes": n_barcodes]
- // The header is the full header, the id is the part header up to the first whitespace character
- // We do not allow whitespace in the header of the fasta file, so assert this.
- def fasta_entries = state.barcodesFasta.splitFasta(record: ["id": true, "header": true, "seqString": true])
- assert fasta_entries.every{it.id == it.header}, "The barcodes FASTA headers must not contain any whitespace!"
- // Check if the fasta headers are unique
- def fasta_ids = fasta_entries.collect{it.id}
- assert fasta_ids.clone().unique() == fasta_ids, "The barcodes FASTA entries must have a unique name!"
- // Check if the sequences are unique
- def fasta_sequences = fasta_entries.collect{it.seqString}
- assert fasta_sequences.clone().unique() == fasta_sequences, "The barcodes FASTA sequences must be unique!"
- [id, newState]
- }
| well_demultiplex.run(
fromState: [
"input_r1": "input_r1",
@@ -41,7 +26,7 @@ workflow run_wf {
def filtered_results = result.findAll{!["output_r1", "output_r2"].contains(it.key)}
def new_state = filtered_input + filtered_results + [
"fastq_output_r1": result.output_r1,
- "fastq_output_r2": result.output_r2,
+ "fastq_output_r2": result.output_r2,
]
return new_state
}
@@ -69,6 +54,7 @@ workflow run_wf {
[
"input": state.star_output.resolve('Aligned.sortedByCoord.out.bam'),
"barcode": state.barcode,
+ "well_id": state.well_id,
]
},
toState: [
@@ -79,7 +65,7 @@ workflow run_wf {
// Create a special groupKey, such that groupTuple
// knows when all the barcodes have been grouped into 1 event.
// This way the processing is as distributed as possible.
- def key = groupKey(state.pool, state.n_barcodes)
+ def key = groupKey(state.pool, state.n_wells)
def newEvent = [key, state]
return newEvent
}
@@ -95,10 +81,14 @@ workflow run_wf {
def barcodes = states.collect{it.barcode}
assert barcodes.clone().unique().size() == barcodes.size(), \
"Error when gathering information for pool ${id}, barcodes are not unique!"
+ def well_ids = states.collect{it.well_id}
+ assert well_ids.clone().unique().size() == well_ids.size(), \
+ "Error when gathering information for pool ${id}, well IDs are not unique!"
def custom_state = [
"fastq_output_r1": states.collect{it.fastq_output_r1[0]},
"fastq_output_r2": states.collect{it.fastq_output_r2[0]},
"barcode": barcodes,
+ "well_id": well_ids,
"star_output": states.collect{it.star_output},
"nrReadsNrGenesPerChrom": states.collect{it.nrReadsNrGenesPerChrom},
]
@@ -167,7 +157,7 @@ workflow run_wf {
toState: ["p_data": "output"],
)
- output_ch = p_data_ch.join(f_data_ch, remainder: true)
+ eset_ch = p_data_ch.join(f_data_ch, remainder: true)
| map {id, p_data_state, f_data_state ->
def newState = p_data_state + ["f_data": f_data_state["f_data"]]
[id, newState]
@@ -186,6 +176,36 @@ workflow run_wf {
"eset": "output",
]
)
+
+ report_channel = eset_ch
+ | toSortedList()
+ | map {ids_and_states ->
+ def states = ids_and_states.collect{it[1]}
+ def html_report = states[0].html_report
+ def ids = ids_and_states.collect{it[0]}
+ def esets = states.collect{it.eset}
+ ["report", ["esets": esets, "html_report": html_report, "original_ids": ids]]
+ }
+ | create_report.run(
+ fromState: [
+ "eset": "esets",
+ "output_report": "html_report",
+ ],
+ toState: [
+ "html_report": "output_report"
+ ]
+ )
+ | flatMap {id, state ->
+ state.original_ids.collect{original_id ->
+ [original_id, ["html_report": state.html_report]]
+ }
+ }
+
+ output_ch = eset_ch.join(report_channel)
+ | map {id, state_eset, state_report ->
+ def new_state = state_eset + ["html_report": state_report.html_report]
+ [id, new_state]
+ }
| setState([
"star_output": "star_output",
"fastq_output_r1": "fastq_output_r1",
@@ -195,7 +215,8 @@ workflow run_wf {
"star_qc_metrics": "star_qc_metrics",
"eset": "eset",
"f_data": "f_data",
- "p_data": "p_data"
+ "p_data": "p_data",
+ "html_report": "html_report",
])
diff --git a/src/workflows/htrnaseq/test.nf b/src/workflows/htrnaseq/test.nf
index 2f38249a..808f1bed 100644
--- a/src/workflows/htrnaseq/test.nf
+++ b/src/workflows/htrnaseq/test.nf
@@ -15,7 +15,7 @@ workflow test_wf {
input_r1: resources_test_file.resolve("100k/SRR14730301/VH02001612_S9_R1_001.fastq"),
input_r2: resources_test_file.resolve("100k/SRR14730301/VH02001612_S9_R2_001.fastq"),
genomeDir: resources_test_file.resolve("genomeDir/gencode.v41.star.sparse"),
- barcodesFasta: resources_test_file.resolve("360-wells.fasta"),
+ barcodesFasta: resources_test_file.resolve("360-wells-with-ids.fasta"),
annotation: resources_test_file.resolve("genomeDir/gencode.v41.annotation.gtf.gz")
],
[
@@ -23,7 +23,7 @@ workflow test_wf {
input_r1: resources_test_file.resolve("100k/SRR14730302/VH02001614_S8_R1_001.fastq"),
input_r2: resources_test_file.resolve("100k/SRR14730302/VH02001614_S8_R2_001.fastq"),
genomeDir: resources_test_file.resolve("genomeDir/gencode.v41.star.sparse"),
- barcodesFasta: resources_test_file.resolve("360-wells.fasta"),
+ barcodesFasta: resources_test_file.resolve("360-wells-with-ids.fasta"),
annotation: resources_test_file.resolve("genomeDir/gencode.v41.annotation.gtf.gz")
]
])
diff --git a/src/workflows/parallel_map_wf/config.vsh.yaml b/src/workflows/parallel_map_wf/config.vsh.yaml
index 9181020a..563ae1ce 100644
--- a/src/workflows/parallel_map_wf/config.vsh.yaml
+++ b/src/workflows/parallel_map_wf/config.vsh.yaml
@@ -4,7 +4,10 @@ description: |
Map RNA sequencing data, provided as fastq files (paired-end) to a reference genome using STAR Solo.
Input data must have been demultiplexed beforehand, meaning that a single fastq pair provides data for
one barcode (one well). Multiple wells can be mapped in parallel by providing multiple events to the
- workflow. Output is provided as mapped output per pool, i.e. one output is provided per pool.xx
+ workflow. Output is provided as mapped output per pool, i.e. one output is provided per pool.
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ maintainer ]
argument_groups:
- name: "Arguments"
arguments:
diff --git a/src/workflows/utils/groupWells/config.vsh.yaml b/src/workflows/utils/groupWells/config.vsh.yaml
index fa05a2b8..4cb0db83 100644
--- a/src/workflows/utils/groupWells/config.vsh.yaml
+++ b/src/workflows/utils/groupWells/config.vsh.yaml
@@ -2,6 +2,9 @@ name: groupWells
namespace: workflows/utils
description: |
N/A
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ maintainer ]
argument_groups:
- name: Inputs
arguments:
diff --git a/src/workflows/well_demultiplex/config.vsh.yaml b/src/workflows/well_demultiplex/config.vsh.yaml
index 465f8e2c..2be85f86 100644
--- a/src/workflows/well_demultiplex/config.vsh.yaml
+++ b/src/workflows/well_demultiplex/config.vsh.yaml
@@ -1,6 +1,11 @@
name: well_demultiplex
namespace: workflows
description: Demultiplexing on well level
+authors:
+ - __merge__: /src/base/authors/dries_schaumont.yaml
+ roles: [ maintainer ]
+ - __merge__: /src/base/authors/marijke_van_moerbeke.yaml
+ roles: [ contributor ]
argument_groups:
- name: Input arguments
arguments:
@@ -41,6 +46,9 @@ argument_groups:
type: string
description: The original pool / sample name
direction: output
+ - name: "--well_id"
+ type: string
+ direction: output
- name: "--barcode"
type: string
direction: output
@@ -50,6 +58,10 @@ argument_groups:
- name: "--pair_end"
type: string
direction: output
+ - name: "--n_wells"
+ type: integer
+ direction: output
+ description: The number of wells in the pool is well is a part of.
resources:
- type: nextflow_script
path: main.nf
@@ -60,6 +72,9 @@ test_resources:
- type: nextflow_script
path: test.nf
entrypoint: test_wf
+ - type: nextflow_script
+ path: test.nf
+ entrypoint: test_wf2
dependencies:
- name: cutadapt
diff --git a/src/workflows/well_demultiplex/integration_test.sh b/src/workflows/well_demultiplex/integration_test.sh
index 59080a53..005a3daf 100755
--- a/src/workflows/well_demultiplex/integration_test.sh
+++ b/src/workflows/well_demultiplex/integration_test.sh
@@ -18,4 +18,15 @@ nextflow \
-entry test_wf \
-resume \
-profile docker,local \
- --publish_dir output \
+ --publish_dir output
+
+
+nextflow \
+ run . \
+ -main-script src/workflows/well_demultiplex/test.nf \
+ -config ./src/config/labels.config \
+ -entry test_wf2 \
+ -resume \
+ -profile docker,local \
+ --publish_dir output_2 \
+
diff --git a/src/workflows/well_demultiplex/main.nf b/src/workflows/well_demultiplex/main.nf
index 317535c0..619f6bb6 100644
--- a/src/workflows/well_demultiplex/main.nf
+++ b/src/workflows/well_demultiplex/main.nf
@@ -4,18 +4,73 @@ workflow run_wf {
main:
output_ch = input_ch
+ /*
+ Parse the fasta file containing the barcodes and do the following:
+ - The sequence headers must not contain any whitespaces
+ - The headers (Well IDs) must be unique
+ - The barcodes must be unique
+ - Store the number of barcodes in the state
+ - Add a barcode to well ID (header) mapping to the state,
+ in order to be able to retreive the well ID based on the FASTQ name after well demultiplexing
+ */
+ | map {id, state ->
+ def n_wells = state.barcodesFasta.countFasta() as int
+ // The header is the full header, the id is the part header up to the first whitespace character
+ // We do not allow whitespace in the header of the fasta file, so assert this.
+ def fasta_entries = state.barcodesFasta.splitFasta(
+ record: ["id": true, "header": true, "seqString": true]
+ )
+ assert fasta_entries.every{it.id == it.header}, \
+ "The barcodes FASTA headers must not contain any whitespace!"
+ // Check if the fasta headers are unique
+ def fasta_ids = fasta_entries.collect{it.id}
+ assert fasta_ids.clone().unique() == fasta_ids, \
+ "The barcodes FASTA entries must have a unique name!"
+ // Check if the sequences are unique
+ def fasta_sequences = fasta_entries.collect{it.seqString}
+ assert fasta_sequences.clone().unique() == fasta_sequences, \
+ "The barcodes FASTA sequences must be unique!"
+ def well_id_matcher = /^([A-Za-z]+)0*([1-9]?[0-9]+)$/
+ def entries_corrected_id = fasta_entries.collectEntries { it ->
+ def unformatted_id = it.header
+ def id_matched_to_format = unformatted_id =~ well_id_matcher
+ assert (id_matched_to_format && id_matched_to_format.getCount() == 1), \
+ "The FASTA headers must match the coordinate system of a well plate (e.g. A01, B01, ... or AA1, AB1, ...). Found: ${unformatted_id}"
+ def id_letters = id_matched_to_format[0][1].toUpperCase()
+ def id_numbers = id_matched_to_format[0][2]
+ ["${id_letters}${id_numbers}", it.seqString]
+ }
+ def newState = state + [
+ "n_wells": n_wells,
+ "well_id_barcode_mapping": entries_corrected_id,
+ ]
+ [id, newState]
+ }
+ /*
+ For each pool (i.e. event) in the channel, a list of R1 and R2 input
+ reads is provided which correspond to the lanes. If there are multiple lanes,
+ we can demultiplex into the wells for each lane in parallel. Therefore, cutadapt
+ must be started multiple times and we need an event per lane. The events are
+ created by taking the R1 and R2 pairs from the input lists. The index of the elements
+ in these lists are added to the ID in order to make them unique.
+ */
| flatMap {id, state ->
- assert state.input_r1.size() == state.input_r2.size(), "Expected equal number of inputs for R1 and R2"
+ assert state.input_r1.size() == state.input_r2.size(), \
+ "Expected equal number of inputs for R1 and R2"
+ // Store the number of lanes that were encountered here in order to
+ // group them together in an asynchronous manner later by providing
+ // the expected number of events to be grouped to groupTuple.
+ // see https://www.nextflow.io/docs/latest/reference/operator.html#grouptuple
def n_lanes = state.input_r1.size()
[state.input_r1, state.input_r2].transpose().withIndex().collect{ input_pair, index ->
def single_input_r1 = input_pair[0]
def single_input_r2 = input_pair[1]
- def newState = state + ["input_r1": single_input_r1,
- "input_r2": single_input_r2,
- "pool": id,
+ def newState = state + ["input_r1": single_input_r1,
+ "input_r2": single_input_r2,
+ "pool": id,
"lane_sorting": index,
"n_lanes": n_lanes]
- def newId = id + "_" + index
+ def newId = id + "_" + index
[newId, newState]
}
}
@@ -36,10 +91,12 @@ workflow run_wf {
},
toState: { id, result, state ->
def newState = [
- pool: state.pool,
- n_lanes: state.n_lanes,
- output: result.output,
- lane_sorting: state.lane_sorting,
+ "pool": state.pool,
+ "n_lanes": state.n_lanes,
+ "output": result.output,
+ "lane_sorting": state.lane_sorting,
+ "n_wells": state.n_wells,
+ "well_id_barcode_mapping": state.well_id_barcode_mapping,
]
return newState
}
@@ -48,58 +105,129 @@ workflow run_wf {
| flatMap{ id, state ->
def pool = state.pool
state.output.collect{ p ->
- def barcode = (p =~ /.*\\/([ACTG]*|unknown)_R?.*/)[0][1]
- def pair_end = (p =~ /.*_(R[12])_.*/)[0][1]
- def lane = (p =~ /.*_(L\d+).*/) ? (p =~ /.*_(L\d+).*/)[0][1] : "NA"
- def new_id = pool + "__" + barcode
- def group_key = groupKey(new_id, state.n_lanes * 2)
+ def well_id_matcher = p =~ /.*\\/([A-Za-z0-9]*|unknown)_R?.*/
+ assert well_id_matcher, \
+ "Could not find Well ID in the name of FASTQ file ($p) output from cutadapt."
+ def well_id = well_id_matcher[0][1]
+ // Note: set the barcode to 'null' for reads that were put into 'unknown'
+ def barcode = (well_id != "unknown") ? state.well_id_barcode_mapping[well_id].replaceAll("[^ACGTacgt]", "") : null
+ assert (well_id == "unknown") || (barcode != null), \
+ "After demultiplexing, no Well ID could be retreived for barcode ${barcode}."
+ def pair_end_matcher = p =~ /.*_(R[12])_.*/
+ assert pair_end_matcher, \
+ "Could not find read orientation information in the name of the FASTQ file ($p) output from cutadapt."
+ def pair_end = pair_end_matcher[0][1]
+ def lane_matcher = p =~ /.*_(L\d+).*/
+ def lane = lane_matcher ? lane_matcher[0][1] : "NA"
+ def new_id = pool + "__" + well_id
[
- group_key,
+ new_id,
[
- pool: pool,
- barcode: barcode,
- output: p,
- lane: lane,
- pair_end: pair_end,
- lane_sorting: state.lane_sorting,
- _meta: [ join_id: pool ]
+ "pool": pool,
+ "barcode": barcode,
+ "well_id": well_id,
+ "output": p,
+ "lane": lane,
+ "n_wells": state.n_wells,
+ "pair_end": pair_end,
+ "n_lanes": state.n_lanes,
+ "lane_sorting": state.lane_sorting,
+ "_meta": [ "join_id": pool ]
]
]
}
}
- // Group the outputs from across lanes
- | groupTuple(sort: "hash")
+ /*
+ At this point, the events are provided on the smallest possible level,
+ as each event represents the reads for a certain orientation from a
+ particular lane and a single well. Here, we join these events back together
+ on well level, gathering FASTQS across the lanes and read orientations.
+ In order to make this joining as efficient as possible, the number of
+ lanes which are expected to be gathered were stored in the state earlier.
+ This way, the processing of a well can continue as as soon as all of
+ the lanes have been gathered. The number of lanes times 2 (forward
+ and reverse orientation) represents the total number of FASTQS (events)
+ to be included for a certain well.
+ */
+ | map {id, state ->
+ def group_key = groupKey(id, state.n_lanes * 2)
+ return [group_key, state]
+ }
+ | groupTuple(sort: {a, b ->
+ // Make sure that the grouped states are in order,
+ // meaning forward and reverse FASTQs are paired and the FASTQ
+ // for the forward reads comes before the reverse reads FASTQ.
+ if (a.lane_sorting == b.lane_sorting) {
+ return a.pair_end <=> b.pair_end
+ }
+ return a.lane_sorting <=> b.lane_sorting
+ })
| map {_, states ->
- def r1_output = states.findAll{ it.pair_end == "R1" }.collect{it.output}
- def r2_output = states.findAll{ it.pair_end == "R2" }.collect{it.output}
- def lane_sorting_r1 = states.findAll{ it.pair_end == "R1" }.collect{it.lane_sorting}
- def lane_sorting_r2 = states.findAll{ it.pair_end == "R2" }.collect{it.lane_sorting}
+ // The states are in one long flat list, group them into pairs
+ // This assumes that the FASTQ files are already in order!
+ // (See the 'sort' argument of groupTuple above)
+ def output_pairs = states.collate(2)
- // At this point, the lane_sorting hold the positios the items in r1_output and r2_output
- // should become in a new list.
- def r1_output_sorted = new ArrayList(r1_output.size())
- def r2_output_sorted = new ArrayList(r2_output.size())
-
- lane_sorting_r1.eachWithIndex { pos, index ->
- r1_output_sorted[pos] = r1_output[index]
- }
-
- lane_sorting_r2.eachWithIndex { pos, index ->
- r2_output_sorted[pos] = r2_output[index]
+ // Sanity check the state
+ output_pairs.each{ pair ->
+ assert pair.size() == 2, \
+ "State error: expected FASTQ pairs as output from cutadapt, " +
+ "found output state: $pair"
+ def (first, second) = pair
+ def should_be_the_same = [
+ "barcode",
+ "well_id",
+ "lane",
+ "pool",
+ "lane_sorting",
+ ]
+ should_be_the_same.each { attr_to_check ->
+ first_attr = first.get(attr_to_check)
+ second_attr = second.get(attr_to_check)
+ assert first_attr == second_attr, \
+ "State error: expected FASTQ pairs from cutadapt to have " +
+ "the same detected ${attr_to_check}. Found: " +
+ "$first_attr and $second_attr"
+ }
+ // Forward and reverse reads should be designated
+ // by 'R1' and 'R2', and sorted lexographically.
+ assert first.pair_end == "R1", \
+ "State error: expected first item from FASTQ pair to have " +
+ "orientation 'R1', found $first.pair_end"
+ assert second.pair_end == "R2", \
+ "State error: expected second item from FASTQ pair to have " +
+ "orientation 'R2', found $second.pair_end"
}
+ def r1_output = output_pairs.collect{it[0].output}
+ def r2_output = output_pairs.collect{it[1].output}
assert r1_output.size() == r2_output.size()
+
+ /* The lane sorting represents the order of the FASTQ files
+ as provided by the input. The order of the FASTQ files should
+ remain the same in the well output. This is because the result of STAR
+ can differ based on the order of the reads in the FASTQ file.
+ Even when the same reads are provided, the order of them matters.
+ */
+ def lane_sorting = output_pairs.it[0].lane_sorting
+ def sorting_is_monotonically_increasing = lane_sorting.withIndex().every { i, idx ->
+ idx == 0 || lane_sorting[idx - 1] <= i
+ }
+ assert sorting_is_monotonically_increasing, \
+ "State error: expected the order of the FASTQ files after grouping " +
+ "the cutadapt output to be the same as the order in the input. " +
+ "Found sorting $lane_sorting, R1 output: $r1_output, R2 output: $r2_output."
+
// Here we pick the state from the first item in the list of states
// and overwrite the keys which are different across states
- // TODO: we can assert that these keys are the same
def first_state = states[0]
- def new_id = first_state.pool + "__" + first_state.barcode
- def new_state = first_state + ["output_r1": r1_output_sorted, "output_r2": r2_output_sorted]
+ def new_id = first_state.pool + "__" + first_state.well_id
+ def new_state = first_state + ["output_r1": r1_output, "output_r2": r2_output]
[new_id, new_state]
}
// TODO: Expand this into matching a whitelist/blacklist of barcodes
// ... and turn into separate component
- | filter{ id, state -> state.barcode != "unknown" }
+ | filter{ id, state -> state.well_id != "unknown" }
| concat_text.run(
directives: [label: ["lowmem", "lowcpu"]],
key: "concat_txt_r1",
@@ -132,7 +260,7 @@ workflow run_wf {
return newState
}
)
- | setState(["pool", "barcode", "lane", "_meta", "output_r1", "output_r2"])
+ | setState(["pool", "well_id", "n_wells", "barcode", "lane", "_meta", "output_r1", "output_r2"])
emit:
output_ch
diff --git a/src/workflows/well_demultiplex/test.nf b/src/workflows/well_demultiplex/test.nf
index 03d60a45..cd2c9656 100644
--- a/src/workflows/well_demultiplex/test.nf
+++ b/src/workflows/well_demultiplex/test.nf
@@ -9,13 +9,13 @@ workflow test_wf {
id: "SRR14730301",
input_r1: resources_test_file.resolve("100k/SRR14730301/VH02001612_S9_R1_001.fastq"),
input_r2: resources_test_file.resolve("100k/SRR14730301/VH02001612_S9_R2_001.fastq"),
- barcodesFasta: resources_test_file.resolve("2-wells.fasta"),
+ barcodesFasta: resources_test_file.resolve("2-wells-with-ids.fasta"),
],
[
id: "SRR14730302",
input_r1: resources_test_file.resolve("100k/SRR14730302/VH02001614_S8_R1_001.fastq"),
input_r2: resources_test_file.resolve("100k/SRR14730302/VH02001614_S8_R2_001.fastq"),
- barcodesFasta: resources_test_file.resolve("2-wells.fasta"),
+ barcodesFasta: resources_test_file.resolve("2-wells-with-ids.fasta"),
],
])
| map { state -> [ state.id, state ] }
@@ -40,3 +40,43 @@ workflow test_wf {
}
}
+
+workflow test_wf2 {
+ resources_test_file = file(params.resources_test)
+ output_ch = Channel.fromList([
+ [
+ id: "SRR14730301",
+ input_r1:
+ [
+ resources_test_file.resolve("100k/SRR14730301/VH02001612_S9_R1_001.fastq"),
+ resources_test_file.resolve("100k/SRR14730302/VH02001614_S8_R1_001.fastq"),
+ ],
+ input_r2:
+ [
+ resources_test_file.resolve("100k/SRR14730301/VH02001612_S9_R2_001.fastq"),
+ resources_test_file.resolve("100k/SRR14730302/VH02001614_S8_R2_001.fastq"),
+ ],
+ barcodesFasta: resources_test_file.resolve("2-wells-with-ids.fasta"),
+ ],
+ ])
+ | map { state -> [ state.id, state ] }
+ | well_demultiplex.run(
+ fromState: { id, state ->
+ [
+ input_r1: state.input_r1,
+ input_r2: state.input_r2,
+ barcodesFasta: state.barcodesFasta,
+ ]
+ },
+ toState: { id, output, state ->
+ output }
+ )
+ | view { output ->
+ assert output.size() == 2 : "outputs should contain two elements; [id, file]"
+ "Output: $output"
+ }
+ | toSortedList()
+ | view { output ->
+ assert output.size() == 2 : "1 samples, and two barcodes"
+ }
+}
diff --git a/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/.config.vsh.yaml b/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/.config.vsh.yaml
index ed9ca980..7cbe26aa 100644
--- a/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/.config.vsh.yaml
+++ b/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/.config.vsh.yaml
@@ -740,9 +740,9 @@ build_info:
output: "target/nextflow/cutadapt"
executable: "target/nextflow/cutadapt/main.nf"
viash_version: "0.9.0"
- git_commit: "06005a79b49911f1197ccfddf066fc566d5b1def"
- git_remote: "https://x-access-token:ghs_s2VchCFPnGFkJ2bOWXBcoeam5dPxgi4UR0W2@github.com/viash-hub/biobox"
- git_tag: "v0.2.0-22-g06005a7"
+ git_commit: "952ff0843093b538cbfd6fefdecf2e7a0bc9e70b"
+ git_remote: "https://x-access-token:ghs_EwAUAMYJ0K4VBHlAEMs4ZP2OyQYqJM0PSfEO@github.com/viash-hub/biobox"
+ git_tag: "v0.2.0-27-g952ff08"
package_config:
name: "biobox"
version: "main"
diff --git a/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/main.nf b/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/main.nf
index 1dc4d2ee..a7f02e16 100644
--- a/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/main.nf
+++ b/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/main.nf
@@ -3619,9 +3619,9 @@ meta = [
"engine" : "docker|native",
"output" : "target/nextflow/cutadapt",
"viash_version" : "0.9.0",
- "git_commit" : "06005a79b49911f1197ccfddf066fc566d5b1def",
- "git_remote" : "https://x-access-token:ghs_s2VchCFPnGFkJ2bOWXBcoeam5dPxgi4UR0W2@github.com/viash-hub/biobox",
- "git_tag" : "v0.2.0-22-g06005a7"
+ "git_commit" : "952ff0843093b538cbfd6fefdecf2e7a0bc9e70b",
+ "git_remote" : "https://x-access-token:ghs_EwAUAMYJ0K4VBHlAEMs4ZP2OyQYqJM0PSfEO@github.com/viash-hub/biobox",
+ "git_tag" : "v0.2.0-27-g952ff08"
},
"package_config" : {
"name" : "biobox",
diff --git a/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/nextflow_schema.json b/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/nextflow_schema.json
index 09c66f90..2b7fb1b4 100644
--- a/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/nextflow_schema.json
+++ b/target/dependencies/vsh/vsh/biobox/main/nextflow/cutadapt/nextflow_schema.json
@@ -180,7 +180,7 @@
"description": "Type: `boolean_true`, default: `false`. Treat adapters given with -a/-A etc",
"help_text": "Type: `boolean_true`, default: `false`. Treat adapters given with -a/-A etc. as pairs. Either both\nor none are removed from each read pair.\n"
,
- "default": "False"
+ "default":false
}
@@ -203,7 +203,7 @@
"description": "Type: `boolean_true`, default: `false`. Read and/or write interleaved paired-end reads",
"help_text": "Type: `boolean_true`, default: `false`. Read and/or write interleaved paired-end reads.\n"
,
- "default": "False"
+ "default":false
}
@@ -254,7 +254,7 @@
"description": "Type: `boolean_true`, default: `false`. Allow only mismatches in alignments",
"help_text": "Type: `boolean_true`, default: `false`. Allow only mismatches in alignments.\n"
,
- "default": "False"
+ "default":false
}
@@ -285,7 +285,7 @@
"description": "Type: `boolean_true`, default: `false`. Interpret IUPAC wildcards in reads",
"help_text": "Type: `boolean_true`, default: `false`. Interpret IUPAC wildcards in reads.\n"
,
- "default": "False"
+ "default":false
}
@@ -296,7 +296,7 @@
"description": "Type: `boolean_true`, default: `false`. Do not interpret IUPAC wildcards in adapters",
"help_text": "Type: `boolean_true`, default: `false`. Do not interpret IUPAC wildcards in adapters.\n"
,
- "default": "False"
+ "default":false
}
@@ -319,7 +319,7 @@
"description": "Type: `boolean_true`, default: `false`. Check both the read and its reverse complement for adapter\nmatches",
"help_text": "Type: `boolean_true`, default: `false`. Check both the read and its reverse complement for adapter\nmatches. If match is on reverse-complemented version,\noutput that one.\n"
,
- "default": "False"
+ "default":false
}
@@ -422,7 +422,7 @@
"description": "Type: `boolean_true`, default: `false`. Trim poly-A tails",
"help_text": "Type: `boolean_true`, default: `false`. Trim poly-A tails"
,
- "default": "False"
+ "default":false
}
@@ -443,7 +443,7 @@
"description": "Type: `boolean_true`, default: `false`. Trim N\u0027s on ends of reads",
"help_text": "Type: `boolean_true`, default: `false`. Trim N\u0027s on ends of reads."
,
- "default": "False"
+ "default":false
}
@@ -504,7 +504,7 @@
"description": "Type: `boolean_true`, default: `false`. Change negative quality values to zero",
"help_text": "Type: `boolean_true`, default: `false`. Change negative quality values to zero."
,
- "default": "False"
+ "default":false
}
@@ -575,7 +575,7 @@
"description": "Type: `boolean_true`, default: `false`. Discard reads that contain an adapter",
"help_text": "Type: `boolean_true`, default: `false`. Discard reads that contain an adapter. Use also -O to\navoid discarding too many randomly matching reads.\n"
,
- "default": "False"
+ "default":false
}
@@ -586,7 +586,7 @@
"description": "Type: `boolean_true`, default: `false`. Discard reads that do not contain an adapter",
"help_text": "Type: `boolean_true`, default: `false`. Discard reads that do not contain an adapter.\n"
,
- "default": "False"
+ "default":false
}
@@ -597,7 +597,7 @@
"description": "Type: `boolean_true`, default: `false`. Discard reads that did not pass CASAVA filtering (header\nhas :Y:)",
"help_text": "Type: `boolean_true`, default: `false`. Discard reads that did not pass CASAVA filtering (header\nhas :Y:).\n"
,
- "default": "False"
+ "default":false
}
@@ -630,7 +630,7 @@
"description": "Type: `boolean_true`, default: `false`. Write report in JSON format to this file",
"help_text": "Type: `boolean_true`, default: `false`. Write report in JSON format to this file.\n"
,
- "default": "False"
+ "default":false
}
@@ -641,7 +641,7 @@
"description": "Type: List of `file`, required, default: `$id.$key.output_*.fast[a,q]`, example: `fastq/*_001.fast[a,q]`, multiple_sep: `\";\"`. Glob pattern for matching the expected output files",
"help_text": "Type: List of `file`, required, default: `$id.$key.output_*.fast[a,q]`, example: `fastq/*_001.fast[a,q]`, multiple_sep: `\";\"`. Glob pattern for matching the expected output files.\nShould include `$output_dir`.\n"
,
- "default": "$id.$key.output_*.fast[a,q]"
+ "default":"$id.$key.output_*.fast[a,q]"
}
@@ -652,7 +652,7 @@
"description": "Type: `boolean_true`, default: `false`. Output FASTA to standard output even on FASTQ input",
"help_text": "Type: `boolean_true`, default: `false`. Output FASTA to standard output even on FASTQ input.\n"
,
- "default": "False"
+ "default":false
}
@@ -663,7 +663,7 @@
"description": "Type: `boolean_true`, default: `false`. Write information about each read and its adapter matches\ninto info",
"help_text": "Type: `boolean_true`, default: `false`. Write information about each read and its adapter matches\ninto info.txt in the output directory.\nSee the documentation for the file format.\n"
,
- "default": "False"
+ "default":false
}
@@ -684,7 +684,7 @@
"description": "Type: `boolean_true`, default: `false`. Print debug information",
"help_text": "Type: `boolean_true`, default: `false`. Print debug information"
,
- "default": "False"
+ "default":false
}
diff --git a/target/executable/eset/create_eset/.config.vsh.yaml b/target/executable/eset/create_eset/.config.vsh.yaml
index 26fbe30f..68f8c186 100644
--- a/target/executable/eset/create_eset/.config.vsh.yaml
+++ b/target/executable/eset/create_eset/.config.vsh.yaml
@@ -1,6 +1,32 @@
name: "create_eset"
namespace: "eset"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Marijke Van Moerbeke"
+ roles:
+ - "author"
+ info:
+ links:
+ github: "mvanmoerbeke"
+ orcid: "0000-0002-3097-5621"
+ linkedin: "marijke-van-moerbeke-84303a34"
+ organizations:
+ - name: "OpenAnalytics"
+ href: "https://www.openanalytics.eu"
+ role: "Statistical Consultant"
argument_groups:
- name: "Arguments"
arguments:
@@ -194,8 +220,8 @@ build_info:
output: "target/executable/eset/create_eset"
executable: "target/executable/eset/create_eset/create_eset"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/executable/eset/create_eset/create_eset b/target/executable/eset/create_eset/create_eset
index 6ba70c39..92cb796a 100755
--- a/target/executable/eset/create_eset/create_eset
+++ b/target/executable/eset/create_eset/create_eset
@@ -10,6 +10,10 @@
# authors of this component should specify the license in the header of such
# files, or include a separate license file detailing the licenses of all included
# files.
+#
+# Component authors:
+# * Dries Schaumont (maintainer)
+# * Marijke Van Moerbeke (author)
set -e
@@ -482,10 +486,11 @@ RUN Rscript -e 'if (!requireNamespace("remotes", quietly = TRUE)) install.packag
remotes::install_url("https://cran.r-project.org/src/contrib/Archive/Seurat/Seurat_4.4.0.tar.gz", repos=BiocManager::repositories(), dependencies=TRUE, upgrade_dependencies=FALSE)\
'
+LABEL org.opencontainers.image.authors="Dries Schaumont, Marijke Van Moerbeke"
LABEL org.opencontainers.image.description="Companion container for running component eset create_eset"
-LABEL org.opencontainers.image.created="2024-11-05T15:39:43Z"
+LABEL org.opencontainers.image.created="2024-12-17T13:58:22Z"
LABEL org.opencontainers.image.source="https://github.com/viash-hub/htrnaseq"
-LABEL org.opencontainers.image.revision="65dd41d8b1b4a307735c72320c96c0880c75f17f"
+LABEL org.opencontainers.image.revision="82647a421dae521a9563f7f02050f13a1319eb4a"
LABEL org.opencontainers.image.version="main"
VIASHDOCKER
diff --git a/target/executable/eset/create_eset/nextflow_labels.config b/target/executable/eset/create_eset/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/executable/eset/create_eset/nextflow_labels.config
+++ b/target/executable/eset/create_eset/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/executable/eset/create_fdata/.config.vsh.yaml b/target/executable/eset/create_fdata/.config.vsh.yaml
index d2298f4e..a464b79a 100644
--- a/target/executable/eset/create_fdata/.config.vsh.yaml
+++ b/target/executable/eset/create_fdata/.config.vsh.yaml
@@ -1,6 +1,32 @@
name: "create_fdata"
namespace: "eset"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Marijke Van Moerbeke"
+ roles:
+ - "contributor"
+ info:
+ links:
+ github: "mvanmoerbeke"
+ orcid: "0000-0002-3097-5621"
+ linkedin: "marijke-van-moerbeke-84303a34"
+ organizations:
+ - name: "OpenAnalytics"
+ href: "https://www.openanalytics.eu"
+ role: "Statistical Consultant"
argument_groups:
- name: "Arguments"
arguments:
@@ -151,8 +177,8 @@ build_info:
output: "target/executable/eset/create_fdata"
executable: "target/executable/eset/create_fdata/create_fdata"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/executable/eset/create_fdata/create_fdata b/target/executable/eset/create_fdata/create_fdata
index 2c076b66..2ad25aac 100755
--- a/target/executable/eset/create_fdata/create_fdata
+++ b/target/executable/eset/create_fdata/create_fdata
@@ -10,6 +10,10 @@
# authors of this component should specify the license in the header of such
# files, or include a separate license file detailing the licenses of all included
# files.
+#
+# Component authors:
+# * Dries Schaumont (maintainer)
+# * Marijke Van Moerbeke (contributor)
set -e
@@ -472,10 +476,11 @@ RUN apt-get update && \
RUN pip install --upgrade pip && \
pip install --upgrade --no-cache-dir "pandas"
+LABEL org.opencontainers.image.authors="Dries Schaumont, Marijke Van Moerbeke"
LABEL org.opencontainers.image.description="Companion container for running component eset create_fdata"
-LABEL org.opencontainers.image.created="2024-11-05T15:39:42Z"
+LABEL org.opencontainers.image.created="2024-12-17T13:58:24Z"
LABEL org.opencontainers.image.source="https://github.com/viash-hub/htrnaseq"
-LABEL org.opencontainers.image.revision="65dd41d8b1b4a307735c72320c96c0880c75f17f"
+LABEL org.opencontainers.image.revision="82647a421dae521a9563f7f02050f13a1319eb4a"
LABEL org.opencontainers.image.version="main"
VIASHDOCKER
diff --git a/target/executable/eset/create_fdata/nextflow_labels.config b/target/executable/eset/create_fdata/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/executable/eset/create_fdata/nextflow_labels.config
+++ b/target/executable/eset/create_fdata/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/executable/eset/create_pdata/.config.vsh.yaml b/target/executable/eset/create_pdata/.config.vsh.yaml
index 1025c55e..b8394101 100644
--- a/target/executable/eset/create_pdata/.config.vsh.yaml
+++ b/target/executable/eset/create_pdata/.config.vsh.yaml
@@ -1,6 +1,32 @@
name: "create_pdata"
namespace: "eset"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Marijke Van Moerbeke"
+ roles:
+ - "contributor"
+ info:
+ links:
+ github: "mvanmoerbeke"
+ orcid: "0000-0002-3097-5621"
+ linkedin: "marijke-van-moerbeke-84303a34"
+ organizations:
+ - name: "OpenAnalytics"
+ href: "https://www.openanalytics.eu"
+ role: "Statistical Consultant"
argument_groups:
- name: "Arguments"
arguments:
@@ -165,8 +191,8 @@ build_info:
output: "target/executable/eset/create_pdata"
executable: "target/executable/eset/create_pdata/create_pdata"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/executable/eset/create_pdata/create_pdata b/target/executable/eset/create_pdata/create_pdata
index a88f8505..a2192ba8 100755
--- a/target/executable/eset/create_pdata/create_pdata
+++ b/target/executable/eset/create_pdata/create_pdata
@@ -10,6 +10,10 @@
# authors of this component should specify the license in the header of such
# files, or include a separate license file detailing the licenses of all included
# files.
+#
+# Component authors:
+# * Dries Schaumont (maintainer)
+# * Marijke Van Moerbeke (contributor)
set -e
@@ -482,10 +486,11 @@ RUN apt-get update && \
RUN pip install --upgrade pip && \
pip install --upgrade --no-cache-dir "pandas"
+LABEL org.opencontainers.image.authors="Dries Schaumont, Marijke Van Moerbeke"
LABEL org.opencontainers.image.description="Companion container for running component eset create_pdata"
-LABEL org.opencontainers.image.created="2024-11-05T15:39:43Z"
+LABEL org.opencontainers.image.created="2024-12-17T13:58:22Z"
LABEL org.opencontainers.image.source="https://github.com/viash-hub/htrnaseq"
-LABEL org.opencontainers.image.revision="65dd41d8b1b4a307735c72320c96c0880c75f17f"
+LABEL org.opencontainers.image.revision="82647a421dae521a9563f7f02050f13a1319eb4a"
LABEL org.opencontainers.image.version="main"
VIASHDOCKER
@@ -1104,7 +1109,7 @@ def main(par):
logger.info("Reads per gene and chromosome table contains information for the following barcodes: %s",
", ".join(reads_and_genes_per_chr_stats.index))
logger.info("Filtering mapping statistics file columns.")
- cols_to_keep = ("NumberOfMTReads", "pctMT", "NumberOfERCCReads",
+ cols_to_keep = ("WellID", "NumberOfMTReads", "pctMT", "NumberOfERCCReads",
"pctERCC", "NumberOfChromReads", "pctChrom")
try:
reads_and_genes_per_chr_stats = reads_and_genes_per_chr_stats.loc[:,cols_to_keep]
diff --git a/target/executable/eset/create_pdata/nextflow_labels.config b/target/executable/eset/create_pdata/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/executable/eset/create_pdata/nextflow_labels.config
+++ b/target/executable/eset/create_pdata/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/executable/integration_test_components/htrnaseq/check_eset/.config.vsh.yaml b/target/executable/integration_test_components/htrnaseq/check_eset/.config.vsh.yaml
index 8967ce4b..68fc24ad 100644
--- a/target/executable/integration_test_components/htrnaseq/check_eset/.config.vsh.yaml
+++ b/target/executable/integration_test_components/htrnaseq/check_eset/.config.vsh.yaml
@@ -1,6 +1,21 @@
name: "check_eset"
namespace: "integration_test_components/htrnaseq"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "author"
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
argument_groups:
- name: "Inputs"
arguments:
@@ -133,8 +148,8 @@ build_info:
output: "target/executable/integration_test_components/htrnaseq/check_eset"
executable: "target/executable/integration_test_components/htrnaseq/check_eset/check_eset"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/executable/integration_test_components/htrnaseq/check_eset/check_eset b/target/executable/integration_test_components/htrnaseq/check_eset/check_eset
index 185f19b8..0e483aca 100755
--- a/target/executable/integration_test_components/htrnaseq/check_eset/check_eset
+++ b/target/executable/integration_test_components/htrnaseq/check_eset/check_eset
@@ -10,6 +10,9 @@
# authors of this component should specify the license in the header of such
# files, or include a separate license file detailing the licenses of all included
# files.
+#
+# Component authors:
+# * Dries Schaumont (author, maintainer)
set -e
@@ -465,10 +468,11 @@ RUN Rscript -e 'if (!requireNamespace("remotes", quietly = TRUE)) install.packag
Rscript -e 'if (!requireNamespace("Biobase", quietly = TRUE)) BiocManager::install("Biobase")' && \
Rscript -e 'remotes::install_cran(c("bit64"), repos = "https://cran.rstudio.com")'
+LABEL org.opencontainers.image.authors="Dries Schaumont"
LABEL org.opencontainers.image.description="Companion container for running component integration_test_components/htrnaseq check_eset"
-LABEL org.opencontainers.image.created="2024-11-05T15:39:42Z"
+LABEL org.opencontainers.image.created="2024-12-17T13:58:24Z"
LABEL org.opencontainers.image.source="https://github.com/viash-hub/htrnaseq"
-LABEL org.opencontainers.image.revision="65dd41d8b1b4a307735c72320c96c0880c75f17f"
+LABEL org.opencontainers.image.revision="82647a421dae521a9563f7f02050f13a1319eb4a"
LABEL org.opencontainers.image.version="main"
VIASHDOCKER
@@ -1197,6 +1201,7 @@ stopifnot(identical(sampleNames(sample_1_result), expected_sample_names))
expected_var_labels <- c(
"WellBC",
+ "WellID",
"NumberOfMTReads",
"pctMT",
"NumberOfERCCReads",
diff --git a/target/executable/integration_test_components/htrnaseq/check_eset/nextflow_labels.config b/target/executable/integration_test_components/htrnaseq/check_eset/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/executable/integration_test_components/htrnaseq/check_eset/nextflow_labels.config
+++ b/target/executable/integration_test_components/htrnaseq/check_eset/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/executable/parallel_map/.config.vsh.yaml b/target/executable/parallel_map/.config.vsh.yaml
index 8652642a..137c150d 100644
--- a/target/executable/parallel_map/.config.vsh.yaml
+++ b/target/executable/parallel_map/.config.vsh.yaml
@@ -1,5 +1,32 @@
name: "parallel_map"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Toni Verbeiren"
+ roles:
+ - "author"
+ - "maintainer"
+ info:
+ role: "Core Team Member"
+ links:
+ github: "tverbeiren"
+ linkedin: "verbeiren"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist and CEO"
argument_groups:
- name: "Input arguments"
arguments:
@@ -237,8 +264,8 @@ build_info:
output: "target/executable/parallel_map"
executable: "target/executable/parallel_map/parallel_map"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/executable/parallel_map/nextflow_labels.config b/target/executable/parallel_map/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/executable/parallel_map/nextflow_labels.config
+++ b/target/executable/parallel_map/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/executable/parallel_map/parallel_map b/target/executable/parallel_map/parallel_map
index efef30c2..468d6e29 100755
--- a/target/executable/parallel_map/parallel_map
+++ b/target/executable/parallel_map/parallel_map
@@ -10,6 +10,10 @@
# authors of this component should specify the license in the header of such
# files, or include a separate license file detailing the licenses of all included
# files.
+#
+# Component authors:
+# * Dries Schaumont (maintainer)
+# * Toni Verbeiren (author, maintainer)
set -e
@@ -511,10 +515,11 @@ ENV STAR_TARGET="/app/star-$STAR_V.tar.gz"
ENV STAR_INSTALL_DIR="/app/STAR-$STAR_V"
ENV STAR_BINARY=STAR
COPY STAR /usr/local/bin/$STAR_BINARY
+LABEL org.opencontainers.image.authors="Dries Schaumont, Toni Verbeiren"
LABEL org.opencontainers.image.description="Companion container for running component parallel_map"
-LABEL org.opencontainers.image.created="2024-11-05T15:39:41Z"
+LABEL org.opencontainers.image.created="2024-12-17T13:58:23Z"
LABEL org.opencontainers.image.source="https://github.com/viash-hub/htrnaseq"
-LABEL org.opencontainers.image.revision="65dd41d8b1b4a307735c72320c96c0880c75f17f"
+LABEL org.opencontainers.image.revision="82647a421dae521a9563f7f02050f13a1319eb4a"
LABEL org.opencontainers.image.version="main"
VIASHDOCKER
diff --git a/target/executable/report/create_report/.config.vsh.yaml b/target/executable/report/create_report/.config.vsh.yaml
new file mode 100644
index 00000000..089090ac
--- /dev/null
+++ b/target/executable/report/create_report/.config.vsh.yaml
@@ -0,0 +1,235 @@
+name: "create_report"
+namespace: "report"
+version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Marijke Van Moerbeke"
+ roles:
+ - "author"
+ - "maintainer"
+ info:
+ links:
+ github: "mvanmoerbeke"
+ orcid: "0000-0002-3097-5621"
+ linkedin: "marijke-van-moerbeke-84303a34"
+ organizations:
+ - name: "OpenAnalytics"
+ href: "https://www.openanalytics.eu"
+ role: "Statistical Consultant"
+argument_groups:
+- name: "Arguments"
+ arguments:
+ - type: "file"
+ name: "--eset"
+ info: null
+ must_exist: true
+ create_parent: true
+ required: true
+ direction: "input"
+ multiple: true
+ multiple_sep: ";"
+ - type: "file"
+ name: "--output_report"
+ info: null
+ example:
+ - "report.html"
+ must_exist: true
+ create_parent: true
+ required: true
+ direction: "output"
+ multiple: false
+ multiple_sep: ";"
+resources:
+- type: "r_script"
+ path: "script.R"
+ is_executable: true
+- type: "r_script"
+ path: "template.Rmd"
+ is_executable: true
+- type: "r_script"
+ path: "plateLayouts.R"
+ is_executable: true
+- type: "file"
+ path: "OutputSTARsolo.png"
+- type: "file"
+ path: "nextflow_labels.config"
+ dest: "nextflow_labels.config"
+description: "Create a basic QC report in HTML format based on a number of esets.\n"
+test_resources:
+- type: "r_script"
+ path: "test.R"
+ is_executable: true
+- type: "file"
+ path: "test_data"
+info: null
+status: "enabled"
+requirements:
+ commands:
+ - "ps"
+license: "MIT"
+links:
+ repository: "https://github.com/viash-hub/htrnaseq"
+runners:
+- type: "executable"
+ id: "executable"
+ docker_setup_strategy: "ifneedbepullelsecachedbuild"
+- type: "nextflow"
+ id: "nextflow"
+ directives:
+ tag: "$id"
+ auto:
+ simplifyInput: true
+ simplifyOutput: false
+ transcript: false
+ publish: false
+ config:
+ labels:
+ mem1gb: "memory = 1000000000.B"
+ mem2gb: "memory = 2000000000.B"
+ mem5gb: "memory = 5000000000.B"
+ mem10gb: "memory = 10000000000.B"
+ mem20gb: "memory = 20000000000.B"
+ mem50gb: "memory = 50000000000.B"
+ mem100gb: "memory = 100000000000.B"
+ mem200gb: "memory = 200000000000.B"
+ mem500gb: "memory = 500000000000.B"
+ mem1tb: "memory = 1000000000000.B"
+ mem2tb: "memory = 2000000000000.B"
+ mem5tb: "memory = 5000000000000.B"
+ mem10tb: "memory = 10000000000000.B"
+ mem20tb: "memory = 20000000000000.B"
+ mem50tb: "memory = 50000000000000.B"
+ mem100tb: "memory = 100000000000000.B"
+ mem200tb: "memory = 200000000000000.B"
+ mem500tb: "memory = 500000000000000.B"
+ mem1gib: "memory = 1073741824.B"
+ mem2gib: "memory = 2147483648.B"
+ mem4gib: "memory = 4294967296.B"
+ mem8gib: "memory = 8589934592.B"
+ mem16gib: "memory = 17179869184.B"
+ mem32gib: "memory = 34359738368.B"
+ mem64gib: "memory = 68719476736.B"
+ mem128gib: "memory = 137438953472.B"
+ mem256gib: "memory = 274877906944.B"
+ mem512gib: "memory = 549755813888.B"
+ mem1tib: "memory = 1099511627776.B"
+ mem2tib: "memory = 2199023255552.B"
+ mem4tib: "memory = 4398046511104.B"
+ mem8tib: "memory = 8796093022208.B"
+ mem16tib: "memory = 17592186044416.B"
+ mem32tib: "memory = 35184372088832.B"
+ mem64tib: "memory = 70368744177664.B"
+ mem128tib: "memory = 140737488355328.B"
+ mem256tib: "memory = 281474976710656.B"
+ mem512tib: "memory = 562949953421312.B"
+ cpu1: "cpus = 1"
+ cpu2: "cpus = 2"
+ cpu5: "cpus = 5"
+ cpu10: "cpus = 10"
+ cpu20: "cpus = 20"
+ cpu50: "cpus = 50"
+ cpu100: "cpus = 100"
+ cpu200: "cpus = 200"
+ cpu500: "cpus = 500"
+ cpu1000: "cpus = 1000"
+ script:
+ - "includeConfig(\"nextflow_labels.config\")"
+ debug: false
+ container: "docker"
+engines:
+- type: "docker"
+ id: "docker"
+ image: "rocker/r2u:24.04"
+ target_registry: "images.viash-hub.com"
+ target_tag: "main"
+ namespace_separator: "/"
+ setup:
+ - type: "apt"
+ packages:
+ - "procps"
+ - "pandoc"
+ interactive: false
+ - type: "r"
+ cran:
+ - "ggplot2"
+ - "knitr"
+ - "gridExtra"
+ - "RColorBrewer"
+ - "processx"
+ - "whisker"
+ - "rmarkdown"
+ - "bookdown"
+ - "data.table"
+ - "platetools"
+ - "htmltools"
+ - "DT"
+ - "logger"
+ - "bit64"
+ bioc:
+ - "Biobase"
+ - "ComplexHeatmap"
+ script:
+ - "install.packages(\"oaStyle\", repos = c(rdepot = \"https://repos.openanalytics.eu/repo/public\"\
+ , getOption(\"repos\")))"
+ bioc_force_install: false
+ test_setup:
+ - type: "r"
+ packages:
+ - "testthat"
+ - "R.utils"
+ bioc_force_install: false
+ entrypoint: []
+ cmd: null
+- type: "native"
+ id: "native"
+build_info:
+ config: "src/report/config.vsh.yaml"
+ runner: "executable"
+ engine: "docker|native"
+ output: "target/executable/report/create_report"
+ executable: "target/executable/report/create_report/create_report"
+ viash_version: "0.9.0"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
+package_config:
+ name: "htrnaseq"
+ version: "main"
+ description: "High-throughput pipeline [WIP]\n"
+ info:
+ test_resources:
+ - path: "gs://viash-hub-test-data/htrnaseq/v1/"
+ dest: "resources_test"
+ viash_version: "0.9.0"
+ source: "src"
+ target: "target"
+ config_mods:
+ - ".requirements.commands := ['ps']\n.runners[.type == 'nextflow'].config.script\
+ \ := 'includeConfig(\"nextflow_labels.config\")'\n.resources += {path: '/src/config/labels.config',\
+ \ dest: 'nextflow_labels.config'}\n"
+ - ".engines += { type: \"native\" }"
+ - ".engines[.type == 'docker'].target_registry := 'images.viash-hub.com'"
+ - ".engines[.type == 'docker'].target_tag := 'main'"
+ keywords:
+ - "bioinformatics"
+ - "sequence"
+ - "high-throughput"
+ - "mapping"
+ - "counting"
+ - "pipeline"
+ license: "MIT"
+ organization: "vsh"
+ links:
+ repository: "https://github.com/viash-hub/htrnaseq"
+ issue_tracker: "https://github.com/viash-hub/htrnaseq/issues"
diff --git a/target/executable/report/create_report/OutputSTARsolo.png b/target/executable/report/create_report/OutputSTARsolo.png
new file mode 100644
index 00000000..cb77d8e0
Binary files /dev/null and b/target/executable/report/create_report/OutputSTARsolo.png differ
diff --git a/target/executable/report/create_report/create_report b/target/executable/report/create_report/create_report
new file mode 100755
index 00000000..e0835aad
--- /dev/null
+++ b/target/executable/report/create_report/create_report
@@ -0,0 +1,1162 @@
+#!/usr/bin/env bash
+
+# create_report main
+#
+# This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative
+# work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data
+# Intuitive.
+#
+# The component may contain files which fall under a different license. The
+# authors of this component should specify the license in the header of such
+# files, or include a separate license file detailing the licenses of all included
+# files.
+#
+# Component authors:
+# * Dries Schaumont (maintainer)
+# * Marijke Van Moerbeke (author, maintainer)
+
+set -e
+
+if [ -z "$VIASH_TEMP" ]; then
+ VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMPDIR}
+ VIASH_TEMP=${VIASH_TEMP:-$VIASH_TEMPDIR}
+ VIASH_TEMP=${VIASH_TEMP:-$VIASH_TMP}
+ VIASH_TEMP=${VIASH_TEMP:-$TMPDIR}
+ VIASH_TEMP=${VIASH_TEMP:-$TMP}
+ VIASH_TEMP=${VIASH_TEMP:-$TEMPDIR}
+ VIASH_TEMP=${VIASH_TEMP:-$TEMP}
+ VIASH_TEMP=${VIASH_TEMP:-/tmp}
+fi
+
+# define helper functions
+# ViashQuote: put quotes around non flag values
+# $1 : unquoted string
+# return : possibly quoted string
+# examples:
+# ViashQuote --foo # returns --foo
+# ViashQuote bar # returns 'bar'
+# Viashquote --foo=bar # returns --foo='bar'
+function ViashQuote {
+ if [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+=.+$ ]]; then
+ echo "$1" | sed "s#=\(.*\)#='\1'#"
+ elif [[ "$1" =~ ^-+[a-zA-Z0-9_\-]+$ ]]; then
+ echo "$1"
+ else
+ echo "'$1'"
+ fi
+}
+# ViashRemoveFlags: Remove leading flag
+# $1 : string with a possible leading flag
+# return : string without possible leading flag
+# examples:
+# ViashRemoveFlags --foo=bar # returns bar
+function ViashRemoveFlags {
+ echo "$1" | sed 's/^--*[a-zA-Z0-9_\-]*=//'
+}
+# ViashSourceDir: return the path of a bash file, following symlinks
+# usage : ViashSourceDir ${BASH_SOURCE[0]}
+# $1 : Should always be set to ${BASH_SOURCE[0]}
+# returns : The absolute path of the bash file
+function ViashSourceDir {
+ local source="$1"
+ while [ -h "$source" ]; do
+ local dir="$( cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd )"
+ source="$(readlink "$source")"
+ [[ $source != /* ]] && source="$dir/$source"
+ done
+ cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd
+}
+# ViashFindTargetDir: return the path of the '.build.yaml' file, following symlinks
+# usage : ViashFindTargetDir 'ScriptPath'
+# $1 : The location from where to start the upward search
+# returns : The absolute path of the '.build.yaml' file
+function ViashFindTargetDir {
+ local source="$1"
+ while [[ "$source" != "" && ! -e "$source/.build.yaml" ]]; do
+ source=${source%/*}
+ done
+ echo $source
+}
+# see https://en.wikipedia.org/wiki/Syslog#Severity_level
+VIASH_LOGCODE_EMERGENCY=0
+VIASH_LOGCODE_ALERT=1
+VIASH_LOGCODE_CRITICAL=2
+VIASH_LOGCODE_ERROR=3
+VIASH_LOGCODE_WARNING=4
+VIASH_LOGCODE_NOTICE=5
+VIASH_LOGCODE_INFO=6
+VIASH_LOGCODE_DEBUG=7
+VIASH_VERBOSITY=$VIASH_LOGCODE_NOTICE
+
+# ViashLog: Log events depending on the verbosity level
+# usage: ViashLog 1 alert Oh no something went wrong!
+# $1: required verbosity level
+# $2: display tag
+# $3+: messages to display
+# stdout: Your input, prepended by '[$2] '.
+function ViashLog {
+ local required_level="$1"
+ local display_tag="$2"
+ shift 2
+ if [ $VIASH_VERBOSITY -ge $required_level ]; then
+ >&2 echo "[$display_tag]" "$@"
+ fi
+}
+
+# ViashEmergency: log events when the system is unstable
+# usage: ViashEmergency Oh no something went wrong.
+# stdout: Your input, prepended by '[emergency] '.
+function ViashEmergency {
+ ViashLog $VIASH_LOGCODE_EMERGENCY emergency "$@"
+}
+
+# ViashAlert: log events when actions must be taken immediately (e.g. corrupted system database)
+# usage: ViashAlert Oh no something went wrong.
+# stdout: Your input, prepended by '[alert] '.
+function ViashAlert {
+ ViashLog $VIASH_LOGCODE_ALERT alert "$@"
+}
+
+# ViashCritical: log events when a critical condition occurs
+# usage: ViashCritical Oh no something went wrong.
+# stdout: Your input, prepended by '[critical] '.
+function ViashCritical {
+ ViashLog $VIASH_LOGCODE_CRITICAL critical "$@"
+}
+
+# ViashError: log events when an error condition occurs
+# usage: ViashError Oh no something went wrong.
+# stdout: Your input, prepended by '[error] '.
+function ViashError {
+ ViashLog $VIASH_LOGCODE_ERROR error "$@"
+}
+
+# ViashWarning: log potentially abnormal events
+# usage: ViashWarning Something may have gone wrong.
+# stdout: Your input, prepended by '[warning] '.
+function ViashWarning {
+ ViashLog $VIASH_LOGCODE_WARNING warning "$@"
+}
+
+# ViashNotice: log significant but normal events
+# usage: ViashNotice This just happened.
+# stdout: Your input, prepended by '[notice] '.
+function ViashNotice {
+ ViashLog $VIASH_LOGCODE_NOTICE notice "$@"
+}
+
+# ViashInfo: log normal events
+# usage: ViashInfo This just happened.
+# stdout: Your input, prepended by '[info] '.
+function ViashInfo {
+ ViashLog $VIASH_LOGCODE_INFO info "$@"
+}
+
+# ViashDebug: log all events, for debugging purposes
+# usage: ViashDebug This just happened.
+# stdout: Your input, prepended by '[debug] '.
+function ViashDebug {
+ ViashLog $VIASH_LOGCODE_DEBUG debug "$@"
+}
+
+# find source folder of this component
+VIASH_META_RESOURCES_DIR=`ViashSourceDir ${BASH_SOURCE[0]}`
+
+# find the root of the built components & dependencies
+VIASH_TARGET_DIR=`ViashFindTargetDir $VIASH_META_RESOURCES_DIR`
+
+# define meta fields
+VIASH_META_NAME="create_report"
+VIASH_META_FUNCTIONALITY_NAME="create_report"
+VIASH_META_EXECUTABLE="$VIASH_META_RESOURCES_DIR/$VIASH_META_NAME"
+VIASH_META_CONFIG="$VIASH_META_RESOURCES_DIR/.config.vsh.yaml"
+VIASH_META_TEMP_DIR="$VIASH_TEMP"
+
+
+# ViashHelp: Display helpful explanation about this executable
+function ViashHelp {
+ echo "create_report main"
+ echo ""
+ echo "Create a basic QC report in HTML format based on a number of esets."
+ echo ""
+ echo "Arguments:"
+ echo " --eset"
+ echo " type: file, required parameter, multiple values allowed, file must exist"
+ echo ""
+ echo " --output_report"
+ echo " type: file, required parameter, output, file must exist"
+ echo " example: report.html"
+}
+
+# initialise variables
+VIASH_MODE='run'
+VIASH_ENGINE_ID='docker'
+
+######## Helper functions for setting up Docker images for viash ########
+# expects: ViashDockerBuild
+
+# ViashDockerInstallationCheck: check whether Docker is installed correctly
+#
+# examples:
+# ViashDockerInstallationCheck
+function ViashDockerInstallationCheck {
+ ViashDebug "Checking whether Docker is installed"
+ if [ ! command -v docker &> /dev/null ]; then
+ ViashCritical "Docker doesn't seem to be installed. See 'https://docs.docker.com/get-docker/' for instructions."
+ exit 1
+ fi
+
+ ViashDebug "Checking whether the Docker daemon is running"
+ local save=$-; set +e
+ local docker_version=$(docker version --format '{{.Client.APIVersion}}' 2> /dev/null)
+ local out=$?
+ [[ $save =~ e ]] && set -e
+ if [ $out -ne 0 ]; then
+ ViashCritical "Docker daemon does not seem to be running. Try one of the following:"
+ ViashCritical "- Try running 'dockerd' in the command line"
+ ViashCritical "- See https://docs.docker.com/config/daemon/"
+ exit 1
+ fi
+}
+
+# ViashDockerRemoteTagCheck: check whether a Docker image is available
+# on a remote. Assumes `docker login` has been performed, if relevant.
+#
+# $1 : image identifier with format `[registry/]image[:tag]`
+# exit code $? : whether or not the image was found
+# examples:
+# ViashDockerRemoteTagCheck python:latest
+# echo $? # returns '0'
+# ViashDockerRemoteTagCheck sdaizudceahifu
+# echo $? # returns '1'
+function ViashDockerRemoteTagCheck {
+ docker manifest inspect $1 > /dev/null 2> /dev/null
+}
+
+# ViashDockerLocalTagCheck: check whether a Docker image is available locally
+#
+# $1 : image identifier with format `[registry/]image[:tag]`
+# exit code $? : whether or not the image was found
+# examples:
+# docker pull python:latest
+# ViashDockerLocalTagCheck python:latest
+# echo $? # returns '0'
+# ViashDockerLocalTagCheck sdaizudceahifu
+# echo $? # returns '1'
+function ViashDockerLocalTagCheck {
+ [ -n "$(docker images -q $1)" ]
+}
+
+# ViashDockerPull: pull a Docker image
+#
+# $1 : image identifier with format `[registry/]image[:tag]`
+# exit code $? : whether or not the image was found
+# examples:
+# ViashDockerPull python:latest
+# echo $? # returns '0'
+# ViashDockerPull sdaizudceahifu
+# echo $? # returns '1'
+function ViashDockerPull {
+ ViashNotice "Checking if Docker image is available at '$1'"
+ if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then
+ docker pull $1 && return 0 || return 1
+ else
+ local save=$-; set +e
+ docker pull $1 2> /dev/null > /dev/null
+ local out=$?
+ [[ $save =~ e ]] && set -e
+ if [ $out -ne 0 ]; then
+ ViashWarning "Could not pull from '$1'. Docker image doesn't exist or is not accessible."
+ fi
+ return $out
+ fi
+}
+
+# ViashDockerPush: push a Docker image
+#
+# $1 : image identifier with format `[registry/]image[:tag]`
+# exit code $? : whether or not the image was found
+# examples:
+# ViashDockerPush python:latest
+# echo $? # returns '0'
+# ViashDockerPush sdaizudceahifu
+# echo $? # returns '1'
+function ViashDockerPush {
+ ViashNotice "Pushing image to '$1'"
+ local save=$-; set +e
+ local out
+ if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then
+ docker push $1
+ out=$?
+ else
+ docker push $1 2> /dev/null > /dev/null
+ out=$?
+ fi
+ [[ $save =~ e ]] && set -e
+ if [ $out -eq 0 ]; then
+ ViashNotice "Container '$1' push succeeded."
+ else
+ ViashError "Container '$1' push errored. You might not be logged in or have the necessary permissions."
+ fi
+ return $out
+}
+
+# ViashDockerPullElseBuild: pull a Docker image, else build it
+#
+# $1 : image identifier with format `[registry/]image[:tag]`
+# ViashDockerBuild : a Bash function which builds a docker image, takes image identifier as argument.
+# examples:
+# ViashDockerPullElseBuild mynewcomponent
+function ViashDockerPullElseBuild {
+ local save=$-; set +e
+ ViashDockerPull $1
+ local out=$?
+ [[ $save =~ e ]] && set -e
+ if [ $out -ne 0 ]; then
+ ViashDockerBuild $@
+ fi
+}
+
+# ViashDockerSetup: create a Docker image, according to specified docker setup strategy
+#
+# $1 : image identifier with format `[registry/]image[:tag]`
+# $2 : docker setup strategy, see DockerSetupStrategy.scala
+# examples:
+# ViashDockerSetup mynewcomponent alwaysbuild
+function ViashDockerSetup {
+ local image_id="$1"
+ local setup_strategy="$2"
+ if [ "$setup_strategy" == "alwaysbuild" -o "$setup_strategy" == "build" -o "$setup_strategy" == "b" ]; then
+ ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id")
+ elif [ "$setup_strategy" == "alwayspull" -o "$setup_strategy" == "pull" -o "$setup_strategy" == "p" ]; then
+ ViashDockerPull $image_id
+ elif [ "$setup_strategy" == "alwayspullelsebuild" -o "$setup_strategy" == "pullelsebuild" ]; then
+ ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id")
+ elif [ "$setup_strategy" == "alwayspullelsecachedbuild" -o "$setup_strategy" == "pullelsecachedbuild" ]; then
+ ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id")
+ elif [ "$setup_strategy" == "alwayscachedbuild" -o "$setup_strategy" == "cachedbuild" -o "$setup_strategy" == "cb" ]; then
+ ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id")
+ elif [[ "$setup_strategy" =~ ^ifneedbe ]]; then
+ local save=$-; set +e
+ ViashDockerLocalTagCheck $image_id
+ local outCheck=$?
+ [[ $save =~ e ]] && set -e
+ if [ $outCheck -eq 0 ]; then
+ ViashInfo "Image $image_id already exists"
+ elif [ "$setup_strategy" == "ifneedbebuild" ]; then
+ ViashDockerBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id")
+ elif [ "$setup_strategy" == "ifneedbecachedbuild" ]; then
+ ViashDockerBuild $image_id $(ViashDockerBuildArgs "$engine_id")
+ elif [ "$setup_strategy" == "ifneedbepull" ]; then
+ ViashDockerPull $image_id
+ elif [ "$setup_strategy" == "ifneedbepullelsebuild" ]; then
+ ViashDockerPullElseBuild $image_id --no-cache $(ViashDockerBuildArgs "$engine_id")
+ elif [ "$setup_strategy" == "ifneedbepullelsecachedbuild" ]; then
+ ViashDockerPullElseBuild $image_id $(ViashDockerBuildArgs "$engine_id")
+ else
+ ViashError "Unrecognised Docker strategy: $setup_strategy"
+ exit 1
+ fi
+ elif [ "$setup_strategy" == "push" -o "$setup_strategy" == "forcepush" -o "$setup_strategy" == "alwayspush" ]; then
+ ViashDockerPush "$image_id"
+ elif [ "$setup_strategy" == "pushifnotpresent" -o "$setup_strategy" == "gentlepush" -o "$setup_strategy" == "maybepush" ]; then
+ local save=$-; set +e
+ ViashDockerRemoteTagCheck $image_id
+ local outCheck=$?
+ [[ $save =~ e ]] && set -e
+ if [ $outCheck -eq 0 ]; then
+ ViashNotice "Container '$image_id' exists, doing nothing."
+ else
+ ViashNotice "Container '$image_id' does not yet exist."
+ ViashDockerPush "$image_id"
+ fi
+ elif [ "$setup_strategy" == "donothing" -o "$setup_strategy" == "meh" ]; then
+ ViashNotice "Skipping setup."
+ else
+ ViashError "Unrecognised Docker strategy: $setup_strategy"
+ exit 1
+ fi
+}
+
+# ViashDockerCheckCommands: Check whether a docker container has the required commands
+#
+# $1 : image identifier with format `[registry/]image[:tag]`
+# $@ : commands to verify being present
+# examples:
+# ViashDockerCheckCommands bash:4.0 bash ps foo
+function ViashDockerCheckCommands {
+ local image_id="$1"
+ shift 1
+ local commands="$@"
+ local save=$-; set +e
+ local missing # mark 'missing' as local in advance, otherwise the exit code of the command will be missing and always be '0'
+ missing=$(docker run --rm --entrypoint=sh "$image_id" -c "for command in $commands; do command -v \$command >/dev/null 2>&1; if [ \$? -ne 0 ]; then echo \$command; exit 1; fi; done")
+ local outCheck=$?
+ [[ $save =~ e ]] && set -e
+ if [ $outCheck -ne 0 ]; then
+ ViashError "Docker container '$image_id' does not contain command '$missing'."
+ exit 1
+ fi
+}
+
+# ViashDockerBuild: build a docker image
+# $1 : image identifier with format `[registry/]image[:tag]`
+# $... : additional arguments to pass to docker build
+# $VIASH_META_TEMP_DIR : temporary directory to store dockerfile & optional resources in
+# $VIASH_META_NAME : name of the component
+# $VIASH_META_RESOURCES_DIR : directory containing the resources
+# $VIASH_VERBOSITY : verbosity level
+# exit code $? : whether or not the image was built successfully
+function ViashDockerBuild {
+ local image_id="$1"
+ shift 1
+
+ # create temporary directory to store dockerfile & optional resources in
+ local tmpdir=$(mktemp -d "$VIASH_META_TEMP_DIR/dockerbuild-$VIASH_META_NAME-XXXXXX")
+ local dockerfile="$tmpdir/Dockerfile"
+ function clean_up {
+ rm -rf "$tmpdir"
+ }
+ trap clean_up EXIT
+
+ # store dockerfile and resources
+ ViashDockerfile "$VIASH_ENGINE_ID" > "$dockerfile"
+
+ # generate the build command
+ local docker_build_cmd="docker build -t '$image_id' $@ '$VIASH_META_RESOURCES_DIR' -f '$dockerfile'"
+
+ # build the container
+ ViashNotice "Building container '$image_id' with Dockerfile"
+ ViashInfo "$docker_build_cmd"
+ local save=$-; set +e
+ if [ $VIASH_VERBOSITY -ge $VIASH_LOGCODE_INFO ]; then
+ eval $docker_build_cmd
+ else
+ eval $docker_build_cmd &> "$tmpdir/docker_build.log"
+ fi
+
+ # check exit code
+ local out=$?
+ [[ $save =~ e ]] && set -e
+ if [ $out -ne 0 ]; then
+ ViashError "Error occurred while building container '$image_id'"
+ if [ $VIASH_VERBOSITY -lt $VIASH_LOGCODE_INFO ]; then
+ ViashError "Transcript: --------------------------------"
+ cat "$tmpdir/docker_build.log"
+ ViashError "End of transcript --------------------------"
+ fi
+ exit 1
+ fi
+}
+
+######## End of helper functions for setting up Docker images for viash ########
+
+# ViashDockerFile: print the dockerfile to stdout
+# $1 : engine identifier
+# return : dockerfile required to run this component
+# examples:
+# ViashDockerFile
+function ViashDockerfile {
+ local engine_id="$1"
+
+ if [[ "$engine_id" == "docker" ]]; then
+ cat << 'VIASHDOCKER'
+FROM rocker/r2u:24.04
+ENTRYPOINT []
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get install -y procps pandoc && \
+ rm -rf /var/lib/apt/lists/*
+
+RUN Rscript -e 'if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes")' && \
+ Rscript -e 'if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager")' && \
+ Rscript -e 'if (!requireNamespace("Biobase", quietly = TRUE)) BiocManager::install("Biobase")' && \
+ Rscript -e 'if (!requireNamespace("ComplexHeatmap", quietly = TRUE)) BiocManager::install("ComplexHeatmap")' && \
+ Rscript -e 'remotes::install_cran(c("ggplot2", "knitr", "gridExtra", "RColorBrewer", "processx", "whisker", "rmarkdown", "bookdown", "data.table", "platetools", "htmltools", "DT", "logger", "bit64"), repos = "https://cran.rstudio.com")' && \
+ Rscript -e 'install.packages("oaStyle", repos = c(rdepot = "https://repos.openanalytics.eu/repo/public", getOption("repos")))'
+
+LABEL org.opencontainers.image.authors="Dries Schaumont, Marijke Van Moerbeke"
+LABEL org.opencontainers.image.description="Companion container for running component report create_report"
+LABEL org.opencontainers.image.created="2024-12-17T13:58:23Z"
+LABEL org.opencontainers.image.source="https://github.com/viash-hub/htrnaseq"
+LABEL org.opencontainers.image.revision="82647a421dae521a9563f7f02050f13a1319eb4a"
+LABEL org.opencontainers.image.version="main"
+
+VIASHDOCKER
+ fi
+}
+
+# ViashDockerBuildArgs: return the arguments to pass to docker build
+# $1 : engine identifier
+# return : arguments to pass to docker build
+function ViashDockerBuildArgs {
+ local engine_id="$1"
+
+ if [[ "$engine_id" == "docker" ]]; then
+ echo ""
+ fi
+}
+
+# ViashAbsolutePath: generate absolute path from relative path
+# borrowed from https://stackoverflow.com/a/21951256
+# $1 : relative filename
+# return : absolute path
+# examples:
+# ViashAbsolutePath some_file.txt # returns /path/to/some_file.txt
+# ViashAbsolutePath /foo/bar/.. # returns /foo
+function ViashAbsolutePath {
+ local thePath
+ local parr
+ local outp
+ local len
+ if [[ ! "$1" =~ ^/ ]]; then
+ thePath="$PWD/$1"
+ else
+ thePath="$1"
+ fi
+ echo "$thePath" | (
+ IFS=/
+ read -a parr
+ declare -a outp
+ for i in "${parr[@]}"; do
+ case "$i" in
+ ''|.) continue ;;
+ ..)
+ len=${#outp[@]}
+ if ((len==0)); then
+ continue
+ else
+ unset outp[$((len-1))]
+ fi
+ ;;
+ *)
+ len=${#outp[@]}
+ outp[$len]="$i"
+ ;;
+ esac
+ done
+ echo /"${outp[*]}"
+ )
+}
+# ViashDockerAutodetectMount: auto configuring docker mounts from parameters
+# $1 : The parameter value
+# returns : New parameter
+# $VIASH_DIRECTORY_MOUNTS : Added another parameter to be passed to docker
+# $VIASH_DOCKER_AUTOMOUNT_PREFIX : The prefix to be used for the automounts
+# examples:
+# ViashDockerAutodetectMount /path/to/bar # returns '/viash_automount/path/to/bar'
+# ViashDockerAutodetectMountArg /path/to/bar # returns '--volume="/path/to:/viash_automount/path/to"'
+function ViashDockerAutodetectMount {
+ local abs_path=$(ViashAbsolutePath "$1")
+ local mount_source
+ local base_name
+ if [ -d "$abs_path" ]; then
+ mount_source="$abs_path"
+ base_name=""
+ else
+ mount_source=`dirname "$abs_path"`
+ base_name=`basename "$abs_path"`
+ fi
+ local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source"
+ if [ -z "$base_name" ]; then
+ echo "$mount_target"
+ else
+ echo "$mount_target/$base_name"
+ fi
+}
+function ViashDockerAutodetectMountArg {
+ local abs_path=$(ViashAbsolutePath "$1")
+ local mount_source
+ local base_name
+ if [ -d "$abs_path" ]; then
+ mount_source="$abs_path"
+ base_name=""
+ else
+ mount_source=`dirname "$abs_path"`
+ base_name=`basename "$abs_path"`
+ fi
+ local mount_target="$VIASH_DOCKER_AUTOMOUNT_PREFIX$mount_source"
+ ViashDebug "ViashDockerAutodetectMountArg $1 -> $mount_source -> $mount_target"
+ echo "--volume=\"$mount_source:$mount_target\""
+}
+function ViashDockerStripAutomount {
+ local abs_path=$(ViashAbsolutePath "$1")
+ echo "${abs_path#$VIASH_DOCKER_AUTOMOUNT_PREFIX}"
+}
+# initialise variables
+VIASH_DIRECTORY_MOUNTS=()
+
+# configure default docker automount prefix if it is unset
+if [ -z "${VIASH_DOCKER_AUTOMOUNT_PREFIX+x}" ]; then
+ VIASH_DOCKER_AUTOMOUNT_PREFIX="/viash_automount"
+fi
+
+# initialise docker variables
+VIASH_DOCKER_RUN_ARGS=(-i --rm)
+
+# initialise array
+VIASH_POSITIONAL_ARGS=''
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -h|--help)
+ ViashHelp
+ exit
+ ;;
+ ---v|---verbose)
+ let "VIASH_VERBOSITY=VIASH_VERBOSITY+1"
+ shift 1
+ ;;
+ ---verbosity)
+ VIASH_VERBOSITY="$2"
+ shift 2
+ ;;
+ ---verbosity=*)
+ VIASH_VERBOSITY="$(ViashRemoveFlags "$1")"
+ shift 1
+ ;;
+ --version)
+ echo "create_report main"
+ exit
+ ;;
+ --eset)
+ if [ -z "$VIASH_PAR_ESET" ]; then
+ VIASH_PAR_ESET="$2"
+ else
+ VIASH_PAR_ESET="$VIASH_PAR_ESET;""$2"
+ fi
+ [ $# -lt 2 ] && ViashError Not enough arguments passed to --eset. Use "--help" to get more information on the parameters. && exit 1
+ shift 2
+ ;;
+ --eset=*)
+ if [ -z "$VIASH_PAR_ESET" ]; then
+ VIASH_PAR_ESET=$(ViashRemoveFlags "$1")
+ else
+ VIASH_PAR_ESET="$VIASH_PAR_ESET;"$(ViashRemoveFlags "$1")
+ fi
+ shift 1
+ ;;
+ --output_report)
+ [ -n "$VIASH_PAR_OUTPUT_REPORT" ] && ViashError Bad arguments for option \'--output_report\': \'$VIASH_PAR_OUTPUT_REPORT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1
+ VIASH_PAR_OUTPUT_REPORT="$2"
+ [ $# -lt 2 ] && ViashError Not enough arguments passed to --output_report. Use "--help" to get more information on the parameters. && exit 1
+ shift 2
+ ;;
+ --output_report=*)
+ [ -n "$VIASH_PAR_OUTPUT_REPORT" ] && ViashError Bad arguments for option \'--output_report=*\': \'$VIASH_PAR_OUTPUT_REPORT\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1
+ VIASH_PAR_OUTPUT_REPORT=$(ViashRemoveFlags "$1")
+ shift 1
+ ;;
+ ---engine)
+ VIASH_ENGINE_ID="$2"
+ shift 2
+ ;;
+ ---engine=*)
+ VIASH_ENGINE_ID="$(ViashRemoveFlags "$1")"
+ shift 1
+ ;;
+ ---setup)
+ VIASH_MODE='setup'
+ VIASH_SETUP_STRATEGY="$2"
+ shift 2
+ ;;
+ ---setup=*)
+ VIASH_MODE='setup'
+ VIASH_SETUP_STRATEGY="$(ViashRemoveFlags "$1")"
+ shift 1
+ ;;
+ ---dockerfile)
+ VIASH_MODE='dockerfile'
+ shift 1
+ ;;
+ ---docker_run_args)
+ VIASH_DOCKER_RUN_ARGS+=("$2")
+ shift 2
+ ;;
+ ---docker_run_args=*)
+ VIASH_DOCKER_RUN_ARGS+=("$(ViashRemoveFlags "$1")")
+ shift 1
+ ;;
+ ---docker_image_id)
+ VIASH_MODE='docker_image_id'
+ shift 1
+ ;;
+ ---debug)
+ VIASH_MODE='debug'
+ shift 1
+ ;;
+ ---cpus)
+ [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1
+ VIASH_META_CPUS="$2"
+ [ $# -lt 2 ] && ViashError Not enough arguments passed to ---cpus. Use "--help" to get more information on the parameters. && exit 1
+ shift 2
+ ;;
+ ---cpus=*)
+ [ -n "$VIASH_META_CPUS" ] && ViashError Bad arguments for option \'---cpus=*\': \'$VIASH_META_CPUS\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1
+ VIASH_META_CPUS=$(ViashRemoveFlags "$1")
+ shift 1
+ ;;
+ ---memory)
+ [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1
+ VIASH_META_MEMORY="$2"
+ [ $# -lt 2 ] && ViashError Not enough arguments passed to ---memory. Use "--help" to get more information on the parameters. && exit 1
+ shift 2
+ ;;
+ ---memory=*)
+ [ -n "$VIASH_META_MEMORY" ] && ViashError Bad arguments for option \'---memory=*\': \'$VIASH_META_MEMORY\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1
+ VIASH_META_MEMORY=$(ViashRemoveFlags "$1")
+ shift 1
+ ;;
+ *) # positional arg or unknown option
+ # since the positional args will be eval'd, can we always quote, instead of using ViashQuote
+ VIASH_POSITIONAL_ARGS="$VIASH_POSITIONAL_ARGS '$1'"
+ [[ $1 == -* ]] && ViashWarning $1 looks like a parameter but is not a defined parameter and will instead be treated as a positional argument. Use "--help" to get more information on the parameters.
+ shift # past argument
+ ;;
+ esac
+done
+
+# parse positional parameters
+eval set -- $VIASH_POSITIONAL_ARGS
+
+
+if [ "$VIASH_ENGINE_ID" == "native" ] ; then
+ VIASH_ENGINE_TYPE='native'
+elif [ "$VIASH_ENGINE_ID" == "docker" ] ; then
+ VIASH_ENGINE_TYPE='docker'
+else
+ ViashError "Engine '$VIASH_ENGINE_ID' is not recognized. Options are: docker, native."
+ exit 1
+fi
+
+if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then
+ # check if docker is installed properly
+ ViashDockerInstallationCheck
+
+ # determine docker image id
+ if [[ "$VIASH_ENGINE_ID" == 'docker' ]]; then
+ VIASH_DOCKER_IMAGE_ID='images.viash-hub.com/vsh/htrnaseq/report/create_report:main'
+ fi
+
+ # print dockerfile
+ if [ "$VIASH_MODE" == "dockerfile" ]; then
+ ViashDockerfile "$VIASH_ENGINE_ID"
+ exit 0
+
+ elif [ "$VIASH_MODE" == "docker_image_id" ]; then
+ echo "$VIASH_DOCKER_IMAGE_ID"
+ exit 0
+
+ # enter docker container
+ elif [[ "$VIASH_MODE" == "debug" ]]; then
+ VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} -v '$(pwd)':/pwd --workdir /pwd -t $VIASH_DOCKER_IMAGE_ID"
+ ViashNotice "+ $VIASH_CMD"
+ eval $VIASH_CMD
+ exit
+
+ # build docker image
+ elif [ "$VIASH_MODE" == "setup" ]; then
+ ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" "$VIASH_SETUP_STRATEGY"
+ ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash'
+ exit 0
+ fi
+
+ # check if docker image exists
+ ViashDockerSetup "$VIASH_DOCKER_IMAGE_ID" ifneedbepullelsecachedbuild
+ ViashDockerCheckCommands "$VIASH_DOCKER_IMAGE_ID" 'ps' 'bash'
+fi
+
+# setting computational defaults
+
+# helper function for parsing memory strings
+function ViashMemoryAsBytes {
+ local memory=`echo "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'`
+ local memory_regex='^([0-9]+)([kmgtp]i?b?|b)$'
+ if [[ $memory =~ $memory_regex ]]; then
+ local number=${memory/[^0-9]*/}
+ local symbol=${memory/*[0-9]/}
+
+ case $symbol in
+ b) memory_b=$number ;;
+ kb|k) memory_b=$(( $number * 1000 )) ;;
+ mb|m) memory_b=$(( $number * 1000 * 1000 )) ;;
+ gb|g) memory_b=$(( $number * 1000 * 1000 * 1000 )) ;;
+ tb|t) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 )) ;;
+ pb|p) memory_b=$(( $number * 1000 * 1000 * 1000 * 1000 * 1000 )) ;;
+ kib|ki) memory_b=$(( $number * 1024 )) ;;
+ mib|mi) memory_b=$(( $number * 1024 * 1024 )) ;;
+ gib|gi) memory_b=$(( $number * 1024 * 1024 * 1024 )) ;;
+ tib|ti) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 )) ;;
+ pib|pi) memory_b=$(( $number * 1024 * 1024 * 1024 * 1024 * 1024 )) ;;
+ esac
+ echo "$memory_b"
+ fi
+}
+# compute memory in different units
+if [ ! -z ${VIASH_META_MEMORY+x} ]; then
+ VIASH_META_MEMORY_B=`ViashMemoryAsBytes $VIASH_META_MEMORY`
+ # do not define other variables if memory_b is an empty string
+ if [ ! -z "$VIASH_META_MEMORY_B" ]; then
+ VIASH_META_MEMORY_KB=$(( ($VIASH_META_MEMORY_B+999) / 1000 ))
+ VIASH_META_MEMORY_MB=$(( ($VIASH_META_MEMORY_KB+999) / 1000 ))
+ VIASH_META_MEMORY_GB=$(( ($VIASH_META_MEMORY_MB+999) / 1000 ))
+ VIASH_META_MEMORY_TB=$(( ($VIASH_META_MEMORY_GB+999) / 1000 ))
+ VIASH_META_MEMORY_PB=$(( ($VIASH_META_MEMORY_TB+999) / 1000 ))
+ VIASH_META_MEMORY_KIB=$(( ($VIASH_META_MEMORY_B+1023) / 1024 ))
+ VIASH_META_MEMORY_MIB=$(( ($VIASH_META_MEMORY_KIB+1023) / 1024 ))
+ VIASH_META_MEMORY_GIB=$(( ($VIASH_META_MEMORY_MIB+1023) / 1024 ))
+ VIASH_META_MEMORY_TIB=$(( ($VIASH_META_MEMORY_GIB+1023) / 1024 ))
+ VIASH_META_MEMORY_PIB=$(( ($VIASH_META_MEMORY_TIB+1023) / 1024 ))
+ else
+ # unset memory if string is empty
+ unset $VIASH_META_MEMORY_B
+ fi
+fi
+# unset nproc if string is empty
+if [ -z "$VIASH_META_CPUS" ]; then
+ unset $VIASH_META_CPUS
+fi
+
+
+# check whether required parameters exist
+if [ -z ${VIASH_PAR_ESET+x} ]; then
+ ViashError '--eset' is a required argument. Use "--help" to get more information on the parameters.
+ exit 1
+fi
+if [ -z ${VIASH_PAR_OUTPUT_REPORT+x} ]; then
+ ViashError '--output_report' is a required argument. Use "--help" to get more information on the parameters.
+ exit 1
+fi
+if [ -z ${VIASH_META_NAME+x} ]; then
+ ViashError 'name' is a required argument. Use "--help" to get more information on the parameters.
+ exit 1
+fi
+if [ -z ${VIASH_META_FUNCTIONALITY_NAME+x} ]; then
+ ViashError 'functionality_name' is a required argument. Use "--help" to get more information on the parameters.
+ exit 1
+fi
+if [ -z ${VIASH_META_RESOURCES_DIR+x} ]; then
+ ViashError 'resources_dir' is a required argument. Use "--help" to get more information on the parameters.
+ exit 1
+fi
+if [ -z ${VIASH_META_EXECUTABLE+x} ]; then
+ ViashError 'executable' is a required argument. Use "--help" to get more information on the parameters.
+ exit 1
+fi
+if [ -z ${VIASH_META_CONFIG+x} ]; then
+ ViashError 'config' is a required argument. Use "--help" to get more information on the parameters.
+ exit 1
+fi
+if [ -z ${VIASH_META_TEMP_DIR+x} ]; then
+ ViashError 'temp_dir' is a required argument. Use "--help" to get more information on the parameters.
+ exit 1
+fi
+
+# check whether required files exist
+if [ ! -z "$VIASH_PAR_ESET" ]; then
+ IFS=';'
+ set -f
+ for file in $VIASH_PAR_ESET; do
+ unset IFS
+ if [ ! -e "$file" ]; then
+ ViashError "Input file '$file' does not exist."
+ exit 1
+ fi
+ done
+ set +f
+fi
+
+# check whether parameters values are of the right type
+if [[ -n "$VIASH_META_CPUS" ]]; then
+ if ! [[ "$VIASH_META_CPUS" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'cpus' has to be an integer. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_B" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_B" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_b' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_KB" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_KB" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_kb' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_MB" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_MB" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_mb' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_GB" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_GB" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_gb' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_TB" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_TB" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_tb' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_PB" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_PB" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_pb' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_KIB" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_KIB" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_kib' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_MIB" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_MIB" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_mib' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_GIB" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_GIB" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_gib' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_TIB" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_TIB" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_tib' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+if [[ -n "$VIASH_META_MEMORY_PIB" ]]; then
+ if ! [[ "$VIASH_META_MEMORY_PIB" =~ ^[-+]?[0-9]+$ ]]; then
+ ViashError 'memory_pib' has to be a long. Use "--help" to get more information on the parameters.
+ exit 1
+ fi
+fi
+
+# create parent directories of output files, if so desired
+if [ ! -z "$VIASH_PAR_OUTPUT_REPORT" ] && [ ! -d "$(dirname "$VIASH_PAR_OUTPUT_REPORT")" ]; then
+ mkdir -p "$(dirname "$VIASH_PAR_OUTPUT_REPORT")"
+fi
+
+if [ "$VIASH_ENGINE_ID" == "native" ] ; then
+ if [ "$VIASH_MODE" == "run" ]; then
+ VIASH_CMD="bash"
+ else
+ ViashError "Engine '$VIASH_ENGINE_ID' does not support mode '$VIASH_MODE'."
+ exit 1
+ fi
+fi
+
+if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then
+ # detect volumes from file arguments
+ VIASH_CHOWN_VARS=()
+if [ ! -z "$VIASH_PAR_ESET" ]; then
+ VIASH_TEST_ESET=()
+ IFS=';'
+ for var in $VIASH_PAR_ESET; do
+ unset IFS
+ VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$var")" )
+ var=$(ViashDockerAutodetectMount "$var")
+ VIASH_TEST_ESET+=( "$var" )
+ done
+ VIASH_PAR_ESET=$(IFS=';' ; echo "${VIASH_TEST_ESET[*]}")
+fi
+if [ ! -z "$VIASH_PAR_OUTPUT_REPORT" ]; then
+ VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_PAR_OUTPUT_REPORT")" )
+ VIASH_PAR_OUTPUT_REPORT=$(ViashDockerAutodetectMount "$VIASH_PAR_OUTPUT_REPORT")
+ VIASH_CHOWN_VARS+=( "$VIASH_PAR_OUTPUT_REPORT" )
+fi
+if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then
+ VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_RESOURCES_DIR")" )
+ VIASH_META_RESOURCES_DIR=$(ViashDockerAutodetectMount "$VIASH_META_RESOURCES_DIR")
+fi
+if [ ! -z "$VIASH_META_EXECUTABLE" ]; then
+ VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_EXECUTABLE")" )
+ VIASH_META_EXECUTABLE=$(ViashDockerAutodetectMount "$VIASH_META_EXECUTABLE")
+fi
+if [ ! -z "$VIASH_META_CONFIG" ]; then
+ VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_CONFIG")" )
+ VIASH_META_CONFIG=$(ViashDockerAutodetectMount "$VIASH_META_CONFIG")
+fi
+if [ ! -z "$VIASH_META_TEMP_DIR" ]; then
+ VIASH_DIRECTORY_MOUNTS+=( "$(ViashDockerAutodetectMountArg "$VIASH_META_TEMP_DIR")" )
+ VIASH_META_TEMP_DIR=$(ViashDockerAutodetectMount "$VIASH_META_TEMP_DIR")
+fi
+
+ # get unique mounts
+ VIASH_UNIQUE_MOUNTS=($(for val in "${VIASH_DIRECTORY_MOUNTS[@]}"; do echo "$val"; done | sort -u))
+fi
+
+if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then
+ # change file ownership
+ function ViashPerformChown {
+ if (( ${#VIASH_CHOWN_VARS[@]} )); then
+ set +e
+ VIASH_CMD="docker run --entrypoint=bash --rm ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID -c 'chown $(id -u):$(id -g) --silent --recursive ${VIASH_CHOWN_VARS[@]}'"
+ ViashDebug "+ $VIASH_CMD"
+ eval $VIASH_CMD
+ set -e
+ fi
+ }
+ trap ViashPerformChown EXIT
+fi
+
+if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then
+ # helper function for filling in extra docker args
+ if [ ! -z "$VIASH_META_MEMORY_B" ]; then
+ VIASH_DOCKER_RUN_ARGS+=("--memory=${VIASH_META_MEMORY_B}")
+ fi
+ if [ ! -z "$VIASH_META_CPUS" ]; then
+ VIASH_DOCKER_RUN_ARGS+=("--cpus=${VIASH_META_CPUS}")
+ fi
+fi
+
+if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then
+ VIASH_CMD="docker run --entrypoint=bash ${VIASH_DOCKER_RUN_ARGS[@]} ${VIASH_UNIQUE_MOUNTS[@]} $VIASH_DOCKER_IMAGE_ID"
+fi
+
+
+# set dependency paths
+
+
+ViashDebug "Running command: $(echo $VIASH_CMD)"
+cat << VIASHEOF | eval $VIASH_CMD
+set -e
+tempscript=\$(mktemp "$VIASH_META_TEMP_DIR/viash-run-create_report-XXXXXX").R
+function clean_up {
+ rm "\$tempscript"
+}
+function interrupt {
+ echo -e "\nCTRL-C Pressed..."
+ exit 1
+}
+trap clean_up EXIT
+trap interrupt INT SIGINT
+cat > "\$tempscript" << 'VIASHMAIN'
+## VIASH START
+# The following code has been auto-generated by Viash.
+# treat warnings as errors
+.viash_orig_warn <- options(warn = 2)
+
+par <- list(
+ "eset" = $( if [ ! -z ${VIASH_PAR_ESET+x} ]; then echo -n "strsplit('"; echo -n "$VIASH_PAR_ESET" | sed "s#['\\]#\\\\g"; echo "', split = ';')[[1]]"; else echo NULL; fi ),
+ "output_report" = $( if [ ! -z ${VIASH_PAR_OUTPUT_REPORT+x} ]; then echo -n "'"; echo -n "$VIASH_PAR_OUTPUT_REPORT" | sed "s#['\\]#\\\\g"; echo "'"; else echo NULL; fi )
+)
+meta <- list(
+ "name" = $( if [ ! -z ${VIASH_META_NAME+x} ]; then echo -n "'"; echo -n "$VIASH_META_NAME" | sed "s#['\\]#\\\\g"; echo "'"; else echo NULL; fi ),
+ "functionality_name" = $( if [ ! -z ${VIASH_META_FUNCTIONALITY_NAME+x} ]; then echo -n "'"; echo -n "$VIASH_META_FUNCTIONALITY_NAME" | sed "s#['\\]#\\\\g"; echo "'"; else echo NULL; fi ),
+ "resources_dir" = $( if [ ! -z ${VIASH_META_RESOURCES_DIR+x} ]; then echo -n "'"; echo -n "$VIASH_META_RESOURCES_DIR" | sed "s#['\\]#\\\\g"; echo "'"; else echo NULL; fi ),
+ "executable" = $( if [ ! -z ${VIASH_META_EXECUTABLE+x} ]; then echo -n "'"; echo -n "$VIASH_META_EXECUTABLE" | sed "s#['\\]#\\\\g"; echo "'"; else echo NULL; fi ),
+ "config" = $( if [ ! -z ${VIASH_META_CONFIG+x} ]; then echo -n "'"; echo -n "$VIASH_META_CONFIG" | sed "s#['\\]#\\\\g"; echo "'"; else echo NULL; fi ),
+ "temp_dir" = $( if [ ! -z ${VIASH_META_TEMP_DIR+x} ]; then echo -n "'"; echo -n "$VIASH_META_TEMP_DIR" | sed "s#['\\]#\\\\g"; echo "'"; else echo NULL; fi ),
+ "cpus" = $( if [ ! -z ${VIASH_META_CPUS+x} ]; then echo -n "as.integer('"; echo -n "$VIASH_META_CPUS" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_b" = $( if [ ! -z ${VIASH_META_MEMORY_B+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_B" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_kb" = $( if [ ! -z ${VIASH_META_MEMORY_KB+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_KB" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_mb" = $( if [ ! -z ${VIASH_META_MEMORY_MB+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_MB" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_gb" = $( if [ ! -z ${VIASH_META_MEMORY_GB+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_GB" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_tb" = $( if [ ! -z ${VIASH_META_MEMORY_TB+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_TB" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_pb" = $( if [ ! -z ${VIASH_META_MEMORY_PB+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_PB" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_kib" = $( if [ ! -z ${VIASH_META_MEMORY_KIB+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_KIB" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_mib" = $( if [ ! -z ${VIASH_META_MEMORY_MIB+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_MIB" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_gib" = $( if [ ! -z ${VIASH_META_MEMORY_GIB+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_GIB" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_tib" = $( if [ ! -z ${VIASH_META_MEMORY_TIB+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_TIB" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi ),
+ "memory_pib" = $( if [ ! -z ${VIASH_META_MEMORY_PIB+x} ]; then echo -n "bit64::as.integer64('"; echo -n "$VIASH_META_MEMORY_PIB" | sed "s#['\\]#\\\\g"; echo "')"; else echo NULL; fi )
+)
+dep <- list(
+
+)
+
+
+# restore original warn setting
+options(.viash_orig_warn)
+rm(.viash_orig_warn)
+
+## VIASH END
+library(whisker)
+library(logger)
+
+log_info("Setting temporary directory to: {meta\$temp_dir}")
+Sys.setenv(TMP = meta\$temp_dir)
+temp_folder <- tempdir(check = TRUE)
+log_info("Created temporary directory {temp_folder}")
+
+template <- file.path(meta\$resources_dir, "template.Rmd")
+
+esets_normalized <- lapply(par\$eset, function(eset_path) {
+ return(file.path(normalizePath(dirname(eset_path)), basename(eset_path)))
+})
+
+log_info(paste0(
+ "Rendering markdown {template} to HTML ",
+ "{par\$output_report} with esets {paste(esets_normalized, collapse = ', ')}"
+))
+
+rmarkdown::render(
+ normalizePath(template),
+ output_file = basename(par\$output_report),
+ output_dir = dirname(par\$output_report),
+ runtime = "static",
+ intermediates_dir = par\$report_dir,
+ clean = TRUE,
+ params = list(
+ esets = esets_normalized,
+ outputDir = par\$report_dir
+ )
+)
+
+log_info("Done")
+VIASHMAIN
+Rscript "\$tempscript" &
+wait "\$!"
+
+VIASHEOF
+
+
+if [[ "$VIASH_ENGINE_TYPE" == "docker" ]]; then
+ # strip viash automount from file paths
+
+ if [ ! -z "$VIASH_PAR_ESET" ]; then
+ unset VIASH_TEST_ESET
+ IFS=';'
+ for var in $VIASH_PAR_ESET; do
+ unset IFS
+ if [ -z "$VIASH_TEST_ESET" ]; then
+ VIASH_TEST_ESET="$(ViashDockerStripAutomount "$var")"
+ else
+ VIASH_TEST_ESET="$VIASH_TEST_ESET;""$(ViashDockerStripAutomount "$var")"
+ fi
+ done
+ VIASH_PAR_ESET="$VIASH_TEST_ESET"
+ fi
+ if [ ! -z "$VIASH_PAR_OUTPUT_REPORT" ]; then
+ VIASH_PAR_OUTPUT_REPORT=$(ViashDockerStripAutomount "$VIASH_PAR_OUTPUT_REPORT")
+ fi
+ if [ ! -z "$VIASH_META_RESOURCES_DIR" ]; then
+ VIASH_META_RESOURCES_DIR=$(ViashDockerStripAutomount "$VIASH_META_RESOURCES_DIR")
+ fi
+ if [ ! -z "$VIASH_META_EXECUTABLE" ]; then
+ VIASH_META_EXECUTABLE=$(ViashDockerStripAutomount "$VIASH_META_EXECUTABLE")
+ fi
+ if [ ! -z "$VIASH_META_CONFIG" ]; then
+ VIASH_META_CONFIG=$(ViashDockerStripAutomount "$VIASH_META_CONFIG")
+ fi
+ if [ ! -z "$VIASH_META_TEMP_DIR" ]; then
+ VIASH_META_TEMP_DIR=$(ViashDockerStripAutomount "$VIASH_META_TEMP_DIR")
+ fi
+fi
+
+
+# check whether required files exist
+if [ ! -z "$VIASH_PAR_OUTPUT_REPORT" ] && [ ! -e "$VIASH_PAR_OUTPUT_REPORT" ]; then
+ ViashError "Output file '$VIASH_PAR_OUTPUT_REPORT' does not exist."
+ exit 1
+fi
+
+
+exit 0
diff --git a/target/executable/report/create_report/nextflow_labels.config b/target/executable/report/create_report/nextflow_labels.config
new file mode 100644
index 00000000..2821ec46
--- /dev/null
+++ b/target/executable/report/create_report/nextflow_labels.config
@@ -0,0 +1,108 @@
+executor {
+ $k8s {
+ submitRateLimit = '10sec'
+ pollInterval = '1 sec'
+ }
+}
+
+process {
+ container = 'nextflow/bash:latest'
+
+ // default resources
+ memory = { 8.Gb * task.attempt }
+ cpus = 8
+ maxForks = 36
+
+ // Retry for exit codes that have something to do with memory issues
+ errorStrategy = { task.exitStatus in 137..140 ? 'retry' : 'terminate' }
+ maxRetries = 3
+ maxMemory = 192.GB
+
+ // Resource labels
+ withLabel: verylowcpu { cpus = 2 }
+ withLabel: lowcpu { cpus = 8 }
+ withLabel: midcpu { cpus = 16 }
+ withLabel: highcpu { cpus = 32 }
+
+ withLabel: verylowmem { memory = { get_memory( 4.GB * task.attempt ) } }
+ withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
+ withLabel: midmem { memory = { get_memory( 16.GB * task.attempt ) } }
+ withLabel: highmem { memory = { get_memory( 64.GB * task.attempt ) } }
+
+}
+
+profiles {
+ // detect tempdir
+ tempDir = java.nio.file.Paths.get(
+ System.getenv('NXF_TEMP') ?:
+ System.getenv('VIASH_TEMP') ?:
+ System.getenv('TEMPDIR') ?:
+ System.getenv('TMPDIR') ?:
+ '/tmp'
+ ).toAbsolutePath()
+
+ mount_temp {
+ docker.temp = tempDir
+ podman.temp = tempDir
+ charliecloud.temp = tempDir
+ }
+
+ no_publish {
+ process {
+ withName: '.*' {
+ publishDir = [
+ enabled: false
+ ]
+ }
+ }
+ }
+
+ docker {
+ docker.fixOwnership = true
+ docker.enabled = true
+ // docker.userEmulation = true
+ singularity.enabled = false
+ podman.enabled = false
+ shifter.enabled = false
+ charliecloud.enabled = false
+ }
+
+ local {
+ // This config is for local processing.
+ process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
+ maxMemory = 25.GB
+ withLabel: verylowcpu { cpus = 2 }
+ withLabel: lowcpu { cpus = 4 }
+ withLabel: midcpu { cpus = 6 }
+ withLabel: highcpu { cpus = 8 }
+
+ withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
+ withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
+ withLabel: highmem { memory = { get_memory( 20.GB * task.attempt ) } }
+ }
+ }
+}
+
+def get_memory(to_compare) {
+ if (!process.containsKey("maxMemory") || !process.maxMemory) {
+ return to_compare
+ }
+
+ try {
+ if (process.containsKey("maxRetries") && process.maxRetries && task.attempt == (process.maxRetries as int)) {
+ return process.maxMemory
+ }
+ else if (to_compare.compareTo(process.maxMemory as nextflow.util.MemoryUnit) == 1) {
+ return max_memory as nextflow.util.MemoryUnit
+ }
+ else {
+ return to_compare
+ }
+ } catch (all) {
+ println "Error processing memory resources. Please check that process.maxMemory '${process.maxMemory}' and process.maxRetries '${process.maxRetries}' are valid!"
+ System.exit(1)
+ }
+ }
diff --git a/target/executable/report/create_report/plateLayouts.R b/target/executable/report/create_report/plateLayouts.R
new file mode 100755
index 00000000..c8b16cff
--- /dev/null
+++ b/target/executable/report/create_report/plateLayouts.R
@@ -0,0 +1,424 @@
+
+#' Displays the annotation of the wells in a plateLayout
+#' @param plateData a data.table object containing the information
+#' of the plate. This must contain a "WellID".
+#' @param plateName The plate name
+#' @param valueVariable The name of the variable in 'plateData' to
+#' be visualized in a plate layout.
+#' @param textVariable The name of the variable in 'plateData' to be
+#' shown in the wells of the plate layout. If NULL, the valueVariable
+#' is shown.
+#' @param colours A named character vector containing the colours
+#' for the different levels of the valuevariable. The names should
+#' correspond to the dose levels. if not specified, a scheme of blues
+#' will be provided.
+#' @param breaks Numeric vector indicating breaks for plot coloring.
+#' @param colourWellText Colour to display the text in the wells.
+#' @param layout Integer vector of length two with number of rows and
+#' colums in a plate, e.g. \code{c(16,24)}
+#' @param legend.title A title for the legend
+#' @param plot.title A title for the plot, will be contracted
+#' with the plate name
+#' @param ... additional arguments for \code{plateLayout.default} function
+#' @import data.table
+#' @importFrom platetools fill_plate
+#' @export
+plateLayout.annotation <- function(
+ plateData,
+ plateName = character(),
+ valueVariable = "Dose",
+ textVariable = NULL,
+ breaks = NULL, colours = NULL,
+ colourWellText = "black",
+ layout = c(16, 24),
+ legend.title = "Dose",
+ plot.title = "Plate Annotation - ",
+ textFontSize = 9, ...
+) {
+ WellID <- Label <- NULL
+
+ if (!(all(c("WellID", "SampleName") %in% colnames(plateData)))) {
+ stop(" 'WellID' and 'SampleName' column required in plateData object")
+ }
+
+
+ plateData[, WellID := paste0(
+ sub(".*([[:alpha:]]).+", "\\1", plateData$WellID),
+ sprintf(
+ "%02d", as.numeric(sub(".*[[:alpha:]](.+)", "\\1", plateData$WellID))
+ )
+ )]
+
+ plateData <- platetools::fill_plate(plateData, "WellID", plate = 384)
+
+ plateData$column <- factor(
+ sprintf(
+ "%02d",
+ as.numeric(sub(".*[[:alpha:]](.+)", "\\1", plateData$WellID))
+ ),
+ levels = sprintf("%02d", seq(1, layout[2]))
+ )
+ plateData$row <- factor(sub(".*([[:alpha:]]).+", "\\1", plateData$WellID),
+ levels = LETTERS[seq(1, layout[1])])
+
+ if (!is.null(valueVariable)){
+ plateData[, values := as.character(plateData[, ..valueVariable][[1]])]
+ valueVar <- "values"
+ }else{
+ plateData[, values := "grey"]
+ valueVar <- "values"
+ colours <- setNames("grey", "grey")
+ }
+
+
+ if (is.null(colours)) {
+
+ blues <- colorRampPalette(c("#d6e0ff", "#2171B5"))
+ greens <- colorRampPalette(c("light green", "dark green"))
+
+ numLevels <- sort(as.numeric(as.character(unique(plateData[, values])[
+ grepl(
+ "^[[:digit:]]+([.][[:digit:]]+)?$",
+ trimws(unique(plateData[, values]))
+ )
+ ])))
+ otherLevels <- sort(as.character(unique(plateData[, values])[
+ !grepl(
+ "^[[:digit:]]+([.][[:digit:]]+)?$",
+ trimws(unique(plateData[,values]))
+ )
+ ]))
+
+ colours <- c(blues(length(numLevels)), greens(length(otherLevels)), "red")
+ names(colours) <- c(numLevels, otherLevels, "failed")
+ }
+
+ if (!is.null(textVariable)) {
+ plateData[,
+ Label := do.call(paste, c(.SD, sep = "\n ")),
+ .SDcols = textVariable
+ ]
+ plateData[, Label := gsub("-", "-\n", Label)]
+ plateData[, Label := gsub("_", "_\n", Label)]
+ textVar <- "Label"
+ } else {
+ textVar <- NULL
+ }
+
+
+ if (is.null(breaks)){
+ breaks <- seq_len(length(colours))
+ }
+
+ plateLayout(
+ plateData = plateData, valueVariable = valueVar,
+ textVariable = textVar, plateName = plateName,
+ breaks = breaks, colourWellText = colourWellText,
+ legend.title = legend.title, layout = layout,
+ colours = colours, plot.title = plot.title,
+ textFontSize = textFontSize, ...
+ )
+}
+
+
+
+#' Create a heatmap of values in a plateLayout view. The values can be
+#' library sizes, number of genes, qcScore (0/1) or a factor.
+#' @param plateData A data.table of the values to be visualized with
+#' at least the column of interest (specified in 'varOfInterest')
+#' and a 'WellID' column indicating the wells in the plate. The WellID
+#' is a combination of a letter (row in the plate) and an integer
+#' (column in the plate).
+#' @param valueVariable The name of the variable in 'plateData'
+#' to be visualized in a plate layout
+#' @param textVariable The name of the variable in 'plateData'
+#' to be shown in the wells of the plate layout. Defaults to the
+#' valueVariable and if NULL, no text will be displayed.
+#' @param breaks Numeric vector indicating breaks for plot coloring.
+#' @param colours Colours to be used for levels specified by
+#' the breaks. If NULL, a colour scheme of purples is shown.
+#' @param colourWellText Colour to display the text in the wells.
+#' @param layout Integer vector of length two with number of rows
+#' and colums in a plate, e.g. \code{c(16,24)}
+#' @param makeContourColours Logical, whether or not the plate
+#' layout will contain a contour colours for the wells based on the
+#' parameters in 'contourColours' and 'categories'
+#' @param contourVariable The variable used for the contour colouring
+#' @param contourColours Character vector specifying a colour for
+#' each range in 'categories'
+#' @param labelsCategories Character vector specifying the names
+#' (labels) for each range in 'categories'
+#' @param categories if contour Variable is not a factor, a numeric
+#' vector specifying the categories to divide the 'varOfInterest',
+#' including the lower and upper limits.
+#' @param plateName The plate name
+#' @param plot.title A title for the plot, will be contracted with
+#' the plate name
+#' @param legend.title A title for the legend
+#' @param displayHeatmap Logical, whether to display the plateLayout heatmap
+#' @param saveHeatmap Logical, whether to save the plateLayout heatmap
+#' @param outputDir The directory where the plateLayout heatmap should be saved
+#' @param prefix The prefix to the file name of the saved plateLayout heatmap
+#' @param ... additional arguments for \code{ComplexHeatmap::Heatmap} function
+#' @importFrom platetools fill_plate
+#' @importFrom RColorBrewer brewer.pal
+#' @importFrom ComplexHeatmap Heatmap
+#' @importFrom circlize colorRamp2
+#' @importFrom grid grid.text grid.rect gpar legendGrob gpar
+#' @importFrom grDevices dev.off png
+#' @importFrom graphics title
+#' @export
+plateLayout <- function(
+ plateData, valueVariable, textVariable = valueVariable,
+ breaks = NULL, colours = NULL, colourWellText = "white", textFontSize = 6,
+ layout = c(16, 24), makeContourColours = FALSE, contourVariable = character(),
+ contourColours = c("red", "orange", "seagreen3"),lwdContours = c(1, 1, 1),
+ labelsCategories = c('1', '2', '3'), categories = NULL, plateName = character(),
+ plot.title = character(), legend.title = NULL, legendFontSize = 15,
+ row_split = rep("A", 16), col_split = rep("A", 24), legendFontSizeTitle = 15,
+ displayHeatmap = TRUE, saveHeatmap = FALSE, outputDir = ".", prefix = ""
+) {
+ WellID <- NULL
+ if (!(all(c("WellID", "SampleName") %in% colnames(plateData)))) {
+ stop(" 'WellID' and 'SampleName' column required in plateData object")
+ }
+
+
+ plateData[, WellID := paste0(
+ sub(".*([[:alpha:]]).+", "\\1", plateData$WellID),
+ sprintf(
+ "%02d",
+ as.numeric(sub(".*[[:alpha:]](.+)", "\\1", plateData$WellID))
+ )
+ )]
+
+ plateData <- platetools::fill_plate(plateData, "WellID", plate = 384)
+
+ plateData$column <- factor(
+ sprintf("%02d", as.numeric(
+ sub(".*[[:alpha:]](.+)", "\\1", plateData$WellID)
+ )),
+ levels = sprintf("%02d", seq(1, layout[2]))
+ )
+ plateData$row <- factor(sub(".*([[:alpha:]]).+", "\\1", plateData$WellID),
+ levels = LETTERS[seq(1, layout[1])])
+
+
+ plateValues <- plateLayoutFormat(
+ plateData,
+ varOfInterest = valueVariable,
+ rows = layout[1],
+ cols = layout[2]
+ )
+ if (!is.null(textVariable)) {
+ plateText <- plateLayoutFormat(
+ plateData, varOfInterest = textVariable,
+ rows = layout[1],
+ cols = layout[2]
+ )
+ }
+ plot.title <- gsub(
+ "^([a-z])", "\\U\\1",
+ gsub("([A-Z])", " \\1",
+ plot.title, perl = TRUE), perl = TRUE
+ )
+ mainTitle <- paste0(plot.title, plateName)
+ plateContourColours <- matrix("", nrow = layout[1], ncol = layout[2])
+
+ if (makeContourColours) {
+ contourData <- plateData[WellType %in% c("nonEmpty", "Treated Wells"), ]
+
+ if (is.numeric(contourData[, ..contourVariable][[1]])) {
+ contourData$contours <- cut(
+ contourData[, ..contourVariable][[1]],
+ categories, left = TRUE,
+ right = TRUE,
+ labels = labelsCategories)
+ }
+ else {
+ contourData$contours <- contourData[, ..contourVariable][[1]]
+ }
+ names(contourColours) <- labelsCategories
+ names(lwdContours) <- labelsCategories
+ for (i in seq_len(layout[1])) {
+ for (j in seq_len(layout[2])) {
+ tryCatch({
+ sampleHit <- which(
+ as.character(contourData$WellID) == paste0(
+ LETTERS[i], sprintf("%02d", j)
+ )
+ )
+ if (length(sampleHit) == 1) {
+ plateContourColours[i, j] <- as.character(
+ contourData[sampleHit,'contours'][[1]]
+ )
+ }
+ },
+ error = function(e) {
+ print(paste0(LETTERS[i], sprintf("%02d", j), " is missing."))
+ }
+ )
+ }
+ }
+ }
+
+ plateValues$contours <- plateContourColours
+ colnames(plateValues$values) <- seq_len(ncol(plateValues$values))
+
+ if (is.null(breaks)) {
+ breakValues <- plateValues$values
+ breakValues[which(is.na(breakValues))] <- 0
+ if (all(breakValues >= 0)) {
+ breaks <- computeBreaks(7, max(plateValues$values, na.rm = TRUE))
+ } else {
+ breaks <- quantile(plateValues$values, probs = seq(0, 1, 0.125))
+ }
+ }
+
+ if (is.null(colours)) {
+ colours <- tryCatch({
+ colorRamp2(
+ breaks = breaks,
+ colors = brewer.pal(length(breaks), "Purples")
+ )
+ },
+ error = function(cond) {
+ return(c("#9370DB", "white"))
+ })
+ }
+ ht <- Heatmap(
+ plateValues$values,
+ column_title = mainTitle, column_title_side = "top",
+ rect_gp = gpar(lwd = 0.4),
+ cluster_rows = FALSE, cluster_columns = FALSE,
+ col = colours, row_title = NULL,
+ row_split = row_split, column_split = col_split,
+ row_names_side = "left",
+ cluster_row_slices = FALSE,
+ cluster_column_slices = FALSE,
+ show_heatmap_legend = TRUE,
+ heatmap_legend_param = list(
+ title = ifelse(
+ is.null(legend.title),
+ paste0(valueVariable, "\n"),
+ paste0(legend.title, "\n")
+ ),
+ grid_height = unit(9, "mm"), border = "black",
+ labels_gp = gpar(fontsize = legendFontSize),
+ title_gp = gpar(fontsize = legendFontSizeTitle)
+ ),
+ cell_fun = function(j, i, x, y, width, height, fill) {
+ if (is.na(plateValues$values[i, j])) {
+ grid.rect(
+ x, y, width, height,
+ gp = gpar(fill = "white", alpha = 0.7, lwd = 0.7, col = "white")
+ )
+ }
+ else if (!is.null(textVariable)) {
+ grid.text(
+ plateText$values[i, j], x, y,
+ just = "centre",
+ gp = gpar(fontsize = textFontSize, col = colourWellText)
+ )
+ }
+ if (makeContourColours) {
+ if (!is.na(plateValues$contours[i, j])) {
+ grid.rect(
+ x, y, width, height,
+ gp = gpar(
+ col = contourColours[as.character(plateValues$contours[i, j])],
+ fill = NA,
+ lwd = lwdContours[as.character(plateValues$contours[i, j])]
+ )
+ )
+ }
+ }
+ }
+ )
+
+ if (displayHeatmap) {
+ print(ht)
+ }
+ if (saveHeatmap) {
+ png(
+ file.path(
+ outputDir,
+ paste0(prefix,gsub(" |-", "",plot.title), "_", plateName, ".png")
+ ),
+ width = 30, height = 10, units = "cm", res = 1200
+ )
+ print(ht)
+ dev.off()
+ }
+
+ return(ht)
+}
+
+
+#' Return numerical matrix with number of reads that corresponds to the
+#' plate layout
+#' @param data A data.frame of the values to be visualized with at least
+#' the columnof interest (specified in 'varOfInterest') and a 'WellID' column
+#' indicating the wells in the plate. The WellID is a combination of a
+#' letter (row in the plate) and an integer (column in the plate).
+#' @param varOfInterest The name of the variable in 'data' to be visualized
+#' in a plate layout
+#' @param rows number of rows in a plate layout
+#' @param cols number of columns in a plate layout
+#' @param verbose if \code{TRUE}, samples missing from the plate
+#' will be reported
+#' @export
+plateLayoutFormat <- function(
+ data, varOfInterest,
+ rows = 16, cols = 24,
+ verbose = FALSE
+) {
+ plateValues <- matrix(NA, nrow = rows, ncol = cols)
+ for (i in seq_len(rows)) {
+ for (j in seq_len(cols)) {
+ tryCatch({
+ sampleHit <- which(
+ as.character(data$WellID) == paste0(LETTERS[i], sprintf("%02d", j))
+ )
+ if(length(sampleHit) == 1){
+ plateValues[i, j] <- data[sampleHit, ..varOfInterest][[1]]
+ }
+ },
+ error = function(e) {
+ if (verbose == TRUE) {
+ print(paste0(LETTERS[i], sprintf("%02d", j), " is missing."))
+ }
+ }
+ )
+ }
+ }
+
+ row.names(plateValues) <- LETTERS[1:rows]
+ return(list("values" = plateValues))
+}
+
+
+
+#' Helper function to automate break selection for raw count data
+#'
+#' This function creates an exponentially increasing vector for given number
+#' breaks between zero and some element of choice. It is particularly useful for
+#' raw counts or raw counts per million.
+#'
+#' @param nBreaks Number of breaks to be generated
+#' @param maxElement Maximum value of data entries
+#' @export
+computeBreaks <- function(nBreaks, variable) {
+
+ maxElement <- max(variable, na.rm = TRUE)
+ if (length(unique(variable)) == 1) {
+ breaks <- c(0, 0.5, ifelse(maxElement < 1, 1, maxElement))
+ } else {
+ coefSystem <- solve(
+ rbind(c(1, 1), c(1, (nBreaks - 1)))) %*% c(0, log(maxElement)
+ )
+ coefExp <- c(exp(coefSystem[1]), coefSystem[2])
+ breaks <- coefExp[1] * exp((1:(nBreaks - 1)) * coefExp[2])
+ }
+ return(c(0, breaks))
+}
\ No newline at end of file
diff --git a/target/executable/report/create_report/template.Rmd b/target/executable/report/create_report/template.Rmd
new file mode 100755
index 00000000..20f8c190
--- /dev/null
+++ b/target/executable/report/create_report/template.Rmd
@@ -0,0 +1,977 @@
+---
+title: "Exploratory Data Report"
+date: "`r format(Sys.time(), '%d %B, %Y')`"
+editor_options:
+ chunk_output_type: console
+output:
+ oaStyle::html_report
+# parameters which are overwritten by the script
+params:
+ outputDir: 'output/'
+ esets:
+ - sample1.rds
+ - sample2.rds
+---
+
+
+
+
+
+
+
+
+
+```{r params, eval = TRUE, include = FALSE}
+outputDir <- params$outputDir
+esets <- params$esets
+```
+
+
+```{r outputDir, echo = FALSE}
+## Required: ABSOLUTE outputDir
+outputDir <- file.path(outputDir)
+
+# When working on a windows computer it should be
+# "/Users/..." instead of "C:/Users/..."
+if (.Platform$OS.type == "windows") {
+ outputDir <- paste0(
+ "/",
+ paste(
+ unlist(strsplit(outputDir, split = "/"))[-1], collapse = "/"
+ ),
+ "/"
+ )
+}
+```
+
+
+
+
+```{r optionsChunkDoNotModify, echo = FALSE, message = FALSE, warning=FALSE}
+
+## Chunk with options for knitr. This chunk should not be modified.
+knitr::opts_chunk$set(
+ eval = TRUE,
+ echo = FALSE,
+ message = FALSE,
+ cache = FALSE,
+ warning = FALSE,
+ error = FALSE,
+ comment = NA, #"#",
+ tidy = FALSE,
+ collapse = TRUE,
+ out.width = "100%",
+ fig.width = 20,
+ fig.height = 10,
+ results = "asis")
+
+knitr::opts_knit$set(root.dir = getwd())
+
+options(warn = 1, width = 200)
+
+```
+
+```{r libraries_and_functions}
+source("plateLayouts.R")
+library(ComplexHeatmap)
+library(data.table)
+library(ggplot2)
+library(knitr)
+library(Biobase)
+library(gridExtra)
+library(RColorBrewer)
+```
+
+
+```{r dataImport}
+
+# Create esetList
+esetList <- sapply(
+ esets, simplify = FALSE,
+ USE.NAMES = TRUE,
+ function(eset_raw) {
+ if (!file.exists(eset_raw)) {
+ stop(paste0("Provided path '", eset_raw, "' is not a file."))
+ }
+ eset <- readRDS(eset_raw)
+ }
+)
+pools <- sapply(esetList, function(eset) {
+ unique(eset$PoolName)
+})
+names(esetList) <- unlist(pools)
+
+# Create qcData
+pDataList <- lapply(esetList, function(eset) data.table(pData(eset)))
+qcData <- rbindlist(pDataList, fill = TRUE)
+
+textVars <- "SampleName"
+annotationVar <- "PoolName"
+
+if (!"SampleName" %in% names(qcData)) {
+ qcData[, SampleName := paste0(PoolName, "_", WellBC)]
+}
+qcData[, log10LibSize := round(log10(NumberOfInputReads))]
+qcData[, (annotationVar) := lapply(.SD, as.factor), .SDcols = annotationVar]
+
+
+colourList <- list()
+Design_levels <- sort(
+ as.character(unique(qcData[, ..annotationVar][[1]])),
+ decreasing = TRUE
+)
+
+if (length(Design_levels) == 1) {
+ colours <- c("#d6e0ff", "lightgrey")
+ names(colours) <- c(Design_levels, "Empty")
+ colourList[[annotationVar]] <- list(
+ "colours" = colours,
+ "annotVar" = annotationVar,
+ "text" = textVars
+ )
+}else if (length(Design_levels) == 2) {
+ colours <- c("#d6e0ff", "#FF9999")
+
+ names(colours) <- c(Design_levels)
+ colourList[[annotationVar]] <- list(
+ "colours" = colours,
+ "annotVar" = annotationVar,
+ "text" = textVars
+ )
+} else if (length(Design_levels) <= 20) {
+
+ if (length(Design_levels) > 12) {
+ colours <- c(
+ brewer.pal(12, "Set3"),
+ brewer.pal((length(Design_levels) - 12),
+ "Pastel2")
+ )
+ } else {
+ colours <- c(brewer.pal(length(Design_levels), "Set3"))
+ }
+
+ names(colours) <- c(Design_levels)
+ colourList[[annotationVar]] <- list(
+ "colours" = colours,
+ "annotVar" = annotationVar,
+ "text" = textVars
+ )
+} else {
+ colours <- c("#d6e0ff")
+ names(colours) <- c("nonEmpty")
+ colourList[[annotVar]] <- list(
+ "colours" = colours,
+ "annotVar" = annotVar,
+ "text" = annotVar
+ )
+}
+```
+
+# Pool Description
+
+Per pool within this study, there are several pool layout plots shown, based on the
+
+* number of STAR input reads (= library size)
+
+* log10 transformed number of STAR input reads
+
+* number of detected UMIs
+
+* number of detected genes
+
+* number of chromosomal reads
+
+* percentage of ERCC
+
+* percentage of mitochondria
+
+
+> The values for the different samples within each pool is expected to be comparable if the content of the different pools is equally diverse.
+
+```{r plateAnnotation, out.width = "100%",fig.width = 20, fig.height= 10}
+
+plateVars <- c("NumberOfInputReads", "log10LibSize", "NumberOfMappedReads",
+ "NumberOfChromReads", "NumberOfUMIs", "NumberOfGenes",
+ "pctMT", "pctERCC")
+
+breaksVars <- lapply(
+ plateVars,
+ function(var) {
+ computeBreaks(7, qcData[, ..var])
+ }
+)
+names(breaksVars) <- plateVars
+
+for (pool in pools){
+ cat("\n\n")
+ cat(paste0("## ", pool, " {.tabset} \n\n"))
+ poolData <- qcData[PoolName == pool]
+ lapply(plateVars, function(plateVar) {
+ cat("\n\n")
+ cat(sprintf("### %s {.unnumbered}", plateVar))
+ cat("\n\n")
+ plateLayout(
+ poolData, valueVariable = plateVar,
+ textFontSize = 10, legendFontSize = 12,
+ plateName = pool, plot.title = "libSize - ",
+ legend.title = "libSize", breaks = breaksVars[[plateVar]]
+ )
+ cat("\n\n")
+ })
+ cat("\n\n")
+}
+```
+
+
+
+
+# Data Distributions
+
+
+## Reads Distributions {.tabset}
+
+The 4 box plots below represent the distributions per pool of the different samples based on:
+
+* the number of STAR input reads
+
+* the number of STAR mapped reads
+
+* the percentage of STAR mapped reads
+
+* the number of detected genes
+
+> The distributions contribute to the QC metrics mentioned in Par 3. The higher these values, the better.
+> The data range for the different plates is expected to be comparable if the content of the different plates is equally diverse.
+
+
+### Number of Input Reads {.tabset .unnumbered}
+
+```{r settings_1}
+
+nColPlots = 1
+figHeight = 7
+
+```
+
+#### Distribution {.tabset .unnumbered}
+
+
+```{r boxplots_input_plate, fig.height = figHeight}
+ggplot(
+ qcData,
+ aes(
+ x = PoolName,
+ y = NumberOfInputReads, colour = PoolName
+ )
+) + geom_boxplot() + ylab("Number of Input Reads") +
+ ggtitle("Number of Input Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+
+```
+
+
+### Number of Mapped Reads {.tabset .unnumbered}
+
+#### Distribution {.unnumbered}
+
+```{r boxplots_mapped_plate, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = PoolName, y = NumberOfMappedReads, colour = PoolName)
+) + geom_boxplot() + ylab("Number of Mapped Reads") +
+ ggtitle("Number of Mapped Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+
+#### pct Mapped Reads {.unnumbered}
+
+```{r boxplots_pctMapped_plate, fig.height = figHeight}
+ggplot(
+ qcData,
+ aes(x = PoolName, y = PctMappedReads, colour = PoolName)
+) +
+ geom_boxplot() +
+ ylab("pct Mapped Reads") +
+ ggtitle("pct Mapped Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+### Number of Chromosomal Reads {.tabset .unnumbered}
+
+#### Distribution {.unnumbered}
+
+```{r boxplots_chrom_plate, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = PoolName, y = NumberOfChromReads, colour = PoolName)
+) + geom_boxplot() + ylab("Number of Chromosomal Reads") +
+ ggtitle("Number of Chromosomal Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+
+```
+
+#### pct Chromosomal Reads {.unnumbered}
+
+```{r boxplots_pctChrom_plate, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = PoolName, y = pctChrom, colour = PoolName)
+) + geom_boxplot() + ylab("pct Chromosomal Reads") +
+ ggtitle("pct Chromosomal Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+### Number of UMIs {.tabset .unnumbered}
+
+#### Distribution {.tabset .unnumbered}
+
+
+```{r boxplots_umi_plate, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = PoolName, y = NumberOfUMIs, colour = PoolName)
+) + geom_boxplot() + ylab("Number of UMIs") +
+ ggtitle('Number of UMIs') +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+
+```
+
+#### Density distribution {.unnumbered}
+
+```{r density_numberOfUMIs}
+
+## Pre-filtering data exploration
+dt_plot <- melt(
+ qcData,
+ id.vars = c("SampleName", "PoolName", "WellID"),
+ measure.vars = c("NumberOfInputReads", "NumberOfMappedReads", "NumberOfUMIs")
+)
+
+readsDensity_plot <- ggplot(dt_plot, aes(value))
+readsDensity_plot <- readsDensity_plot +
+ geom_density(aes(fill = variable), alpha=0.8) +
+ facet_grid(~ PoolName, scales = "free_x", space = "fixed", drop = TRUE) +
+ geom_vline(
+ xintercept = 5e5,
+ linetype = "dashed",
+ color = "steelblue3", size = 2
+ ) +
+ annotate(
+ "text",
+ x = 3.5e5, y = 2e-6, label = "500k",
+ angle = 90, color = "steelblue3", size = 10
+ ) +
+ geom_vline(
+ xintercept = 1.5e6, linetype = "dashed",
+ color = "forestgreen", size = 2
+ ) +
+ annotate(
+ "text", x = 1.35e6, y = 2e-6, label = "1.5M",
+ angle = 90, color = "forestgreen", size = 10
+ ) +
+ labs(
+ title = "Density plot",
+ subtitle = paste0(
+ "# Samples with NumberOfMappedReads > 1.5M: ",
+ length(which(qcData$NumberOfMappedReads > 1.5e6)),
+ "\n# Samples with NumberOfUMIs > 500k: ",
+ length(which(qcData$NumberOfUMIs > 5e5))
+ ),
+ caption = paste0("# Total samples (after removing empty): ", nrow(qcData)),
+ x = "Count",
+ fill = "Variable"
+ ) +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 5),
+ axis.text.x = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ plot.subtitle = element_text(size = 17),
+ plot.caption = element_text(size = 15),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15),
+ axis.text.y = element_blank(),
+ axis.ticks.y = element_blank(),
+ axis.title.y = element_blank()
+ )
+readsDensity_plot
+
+```
+
+### Number of Genes {.tabset .unnumbered}
+
+#### Distribution {.unnumbered}
+
+```{r boxplots_genes_plate, fig.height = figHeight}
+ggplot(
+ qcData,
+ aes(x = PoolName, y = NumberOfGenes, colour = PoolName)
+) +
+ geom_boxplot() + ylab("Number of Genes") +
+ ggtitle("Number of Genes") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+## {.tabset .toc-ignore .unnumbered}
+
+
+In addition, several plots are shown visualizing the efficiency of the reads-to-genes translation:
+
+* the number of input reads vs the number of mapped reads
+
+* the number of chromosomal reads vs the number of mapped reads
+
+* the number of mapped reads per UMI vs the number of mapped reads
+
+* the number of UNI vs the number of mapped reads
+
+* the number of mapped reads vs the number of genes
+
+* the number of chromosomal reads vs the number of genes
+
+* the number of mapped reads per UMI vs the number of genes
+
+### Mapping Efficiency {.tabset .unnumbered}
+
+#### Number of Input Reads {.unnumbered}
+
+```{r mapping_efficiency_1_plate, fig.height = 7}
+
+ggplot(
+ qcData,
+ aes(x = NumberOfInputReads, y = NumberOfMappedReads, colour = PoolName)
+) +
+ geom_point() +
+ xlab("Number of Input Reads") +
+ ylab("Number of Mapped Reads") +
+ ggtitle("Number of Mapped Reads vs Number of Input Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+
+```
+
+
+#### Number of Chromosomal Reads {.unnumbered}
+
+```{r mapping_efficiency_2_plate, fig.height = 7}
+
+ggplot(
+ qcData,
+ aes(x = NumberOfChromReads, y = NumberOfMappedReads, colour = PoolName)
+) + geom_point() +
+ xlab("Number of Chromosomal Reads") + ylab("Number of Mapped Reads") +
+ ggtitle("Number of Chromosomal Reads vs Number of Mapped Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+)
+
+```
+
+
+#### Number of UMI {.unnumbered}
+
+```{r mapping_efficiency_4_plate, fig.height = 7}
+
+ggplot(
+ qcData,
+ aes(x =NumberOfUMIs, y = NumberOfMappedReads, colour = PoolName)
+) + geom_point() +
+ ylab("Number of Mapped Reads") + xlab("Number of UMIs ") +
+ ggtitle("Number of UMIs vs Number of Mapped Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+
+```
+
+### Counting Efficiency {.tabset .unnumbered}
+
+#### Number of Mapped Reads {.unnumbered}
+
+```{r gene_efficiency_1_plate, fig.height = 7}
+ggplot(
+ qcData,
+ aes(x = NumberOfMappedReads, y = NumberOfGenes, colour = PoolName)
+) + geom_point() +
+ ylab("Number of Genes") + xlab("Number of Mapped Reads") +
+ ggtitle("Number of Genes vs Number of Mapped Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+```
+
+#### Number of Chromosomal Reads {.unnumbered}
+
+```{r gene_efficiency_2_plate, fig.height = 7}
+ggplot(
+ qcData,
+ aes(x = NumberOfChromReads, y = NumberOfGenes, colour = PoolName)
+) + geom_point() +
+ ylab("Number of Genes") + xlab("Number of Chromosomal Reads") +
+ ggtitle("Number of Genes vs Number of Chromosomal Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+```
+
+
+
+## Sequencing Saturation {.tabset}
+
+The barplots below represent the sequencing saturation per sample as determined by STAR, split per pool.
+The HT-RNAseq platform aims for shallow sequencing resulting in relatively low sequencing saturations of 10-20%.
+In addition, the sequencing saturation vs the number of input reads is shown.
+
+### Sequencing Saturation {.unnumbered}
+
+
+
+```{r sequencingSaturation, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = WellID, y = SequencingSaturation, fill = PoolName)
+) + geom_bar(stat = "identity", position = "dodge") +
+ xlab("Samples") + ggtitle("Sequencing Saturation per Sample") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(1, "lines"),
+ text = element_text(size = 10),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.text.y = element_text(size = 15),
+ axis.ticks.x = element_blank()
+ )
+```
+
+### Sequencing Saturation - Input Reads {.unnumbered}
+
+
+```{r sequencingSaturation_inputReads, fig.height = figHeight}
+
+
+ggplot(
+ qcData,
+ aes(x = NumberOfInputReads, y = SequencingSaturation, colour = PoolName)
+) + geom_point() +
+ ggtitle("Sequencing Saturation vs Number of Input Reads") +
+ theme(strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+```
+
+### Sequencing Saturation - Mapped Reads {.unnumbered}
+
+```{r sequencingSaturation_mappedReads, fig.height = figHeight}
+ggplot(
+ qcData,
+ aes(x = NumberOfChromReads, y = SequencingSaturation, colour = PoolName)
+) + geom_point() +
+ ggtitle("Sequencing Saturation vs Number of Chromosomal Reads") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size=10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size=18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+)
+```
+
+
+
+## Genomic Origin {.tabset}
+
+The 3 boxplots below represent, per pool, the distributions of the percentage of reads mapping to:
+
+* chromosomal regions
+
+* mitochondrial regions
+
+* ERCC spike-ins
+
+The 4th plot summarises the above results across samples per pool.
+
+The 5th plot shows the percentage of reads mapped to the transcriptome (as counted by STAR). This measurement serves as a proxy for the percentage of reads mapped to exons.
+
+> The percentage ERCC contributes to the QC metrics mentioned in Par 3. This value is ideally as low as possible (but non-zero to ensure the they have been spiked in) and comparable for the different pools.
+
+
+
+
+### pctChrom {.tabset .unnumbered}
+
+
+```{r genomicOrigin_chrom_plate, fig.height = figHeight}
+
+ggplot(
+ qcData, aes(x = PoolName, y = pctChrom, colour = PoolName)
+) +
+ geom_boxplot() +
+ ggtitle("pctChrom") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+
+### pctMT {.tabset .unnumbered}
+
+```{r genomicOrigin_mt_plate, fig.height = figHeight}
+
+ggplot(
+ qcData,
+ aes(x = PoolName, y = pctMT, colour = PoolName)
+) +
+ geom_boxplot() + ggtitle("pctMT") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+### pctERCC {.tabset .unnumbered}
+
+
+```{r genomicOrigin_ercc_plate, fig.height = figHeight}
+ggplot(qcData, aes(x = PoolName, y = pctERCC, colour = PoolName)) +
+ geom_boxplot() +
+ ggtitle("pctERCC") +
+ theme(
+ strip.text.x = element_text(size = 20),
+ panel.spacing = unit(2, "lines"),
+ text = element_text(size = 10),
+ axis.text.y = element_text(angle = 90, size = 14),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title.y = element_text(size = 15),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank()
+ )
+```
+
+
+### Genomic Summary {.tabset .unnumbered}
+
+
+
+```{r genomicOrigin_summary_plate}
+meanPctChromMTData <- qcData[, .(
+ "pctChrom" = median(pctChrom),
+ "pctMT" = median(pctMT),
+ "pctERCC" = median(pctERCC)
+), by = PoolName]
+meanPctChromMTDataLong <- melt(
+ meanPctChromMTData,
+ id.vars = "PoolName",
+ measure.vars = c("pctChrom", "pctMT", "pctERCC"),
+ variable.name = "Origin", value.name = "pct"
+)
+ggplot(
+ meanPctChromMTDataLong,
+ aes(fill = Origin, y = pct, x = PoolName)) +
+ geom_bar(position = "stack", stat = "identity") +
+ ggtitle("Genomic Origin") +
+ theme(
+ text = element_text(size = 10),
+ axis.text = element_text(angle = 90, size = 15),
+ plot.title = element_text(size = 18),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 17),
+ axis.title = element_text(size = 15)
+ )
+
+```
+
+
+
+# Depletion {.tabset}
+
+
+```{r depletion}
+
+
+for (eset_name in pools) {
+ cat("\n\n")
+ cat(paste0("## ", eset_name, " {.unnumbered}"))
+ cat("\n\n")
+
+ eset <- esetList[[eset_name]]
+ average_reads <- sort(apply(exprs(eset), 1, mean), decreasing = TRUE)
+ plotData <- data.table(
+ ENSGID = names(average_reads),
+ av_count = average_reads
+ )
+
+ gen_descript <- data.table(
+ ENSGID = eset@featureData@data$gene_id,
+ Description = eset@featureData@data$GENENAME
+ )
+ order_gen_descript <- gen_descript[
+ match(plotData$ENSGID, gen_descript$ENSGID),
+ ]
+
+ g <- ggplot(
+ plotData[c(1:100)],
+ aes(x = reorder(ENSGID, -av_count), y = av_count)
+ ) + geom_bar(stat = "identity") +
+ theme(
+ axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1, size = 12),
+ axis.text.y = element_text(size = 12),
+ legend.text = element_text(size = 15),
+ legend.title = element_text(size = 15),
+ axis.title = element_text(size = 18),
+ plot.title = element_text(size = 20)
+ ) + ylab("Average Counts") + xlab("Genes")
+
+ print(g)
+
+ cat("\n\n")
+ cat("
")
+ cat("
")
+
+ print(htmltools::tagList((DT::datatable(order_gen_descript[1:100, ]))))
+}
+```
+
+
+
+
+
+
+
+
+# Glossary {.unnumbered}
+
+
+## Read {.unlisted .unnumbered}
+
+A read is a oligonucleotide (a short RNA fragment) that has been sequenced. It consists of a fixed number of base pairs (bp) and therefore has a specific read length.
+
+
+
+## Input Read {.unlisted .unnumbered}
+
+Each read of the fastq file used as input to the STAR aligner is considered an input read.
+
+
+
+## Read With Valid Barcode {.unlisted .unnumbered}
+
+A read with a valid barcode is a read for which the barcode matches the white list of barcodes under the given restriction of the number of allowed mismatches. The number of reads with a valid barcode is lower or equal to the number of input reads.
+
+
+
+## Mapped Read {.unlisted .unnumbered}
+
+A read that has been aligned against the reference genome and for which one or more suitable matching locations have been found is a mapped read. Depending on the number of allowed mismatches this might or might not be be an exact match. The number of mapped reads is lower or equal to the number of reads with a valid barcode.
+
+
+
+## Uniquely Mapped Read {.unlisted .unnumbered}
+
+A read for which one and only one suitable matching location in the reference genome was found is an uniquely mapped read. The number of uniquely mapped reads is lower or equal to the number of mapped reads.
+
+
+
+## Counted Read {.unlisted .unnumbered}
+
+A mapped read will only be counted if it overlaps (1 nucleotide or more) with one and only one gene. The number of counted reads is lower or equal to the number of (uniquely) mapped reads.
+
+
+
+## UMIs {.unlisted .unnumbered}
+
+Unique molecular identifiers (UMI) are short sequences in order to uniquely tag each molecule in a sample library. Sequencing with UMIs allows bioinformatics software to filter out duplicate reads and PCR errors with a high level of accuracy and report unique reads.
+
+The reported UMIs is the number of UMIs among the set of reads that map to an unique gene, i.e the number of reads is deduplicated.
+
+
+
+## pctERCC {.unlisted .unnumbered}
+
+The percentage of reads mapping to the ERCC genes among the total number of **mapped** reads.
+
+
+
+## pctMT {.unlisted .unnumbered}
+
+The percentage of reads mapping to the MT genes among the total number of **mapped** reads.
+
+
+
+## Sequencing Saturation {.unlisted .unnumbered}
+
+The sequencing saturation is a measure of the fraction of library complexity. The inverse of one minus the sequencing saturation can be interpreted as the number of additional reads it would take to detect a new transcript. Consequently, a low sequencing saturation indicates a shallow sequencing in which a new transcript could be discovered with a few reads.
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/target/executable/stats/combine_star_logs/.config.vsh.yaml b/target/executable/stats/combine_star_logs/.config.vsh.yaml
index e87340e2..061a43f6 100644
--- a/target/executable/stats/combine_star_logs/.config.vsh.yaml
+++ b/target/executable/stats/combine_star_logs/.config.vsh.yaml
@@ -1,6 +1,21 @@
name: "combine_star_logs"
namespace: "stats"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "author"
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
argument_groups:
- name: "Arguments"
arguments:
@@ -183,8 +198,8 @@ build_info:
output: "target/executable/stats/combine_star_logs"
executable: "target/executable/stats/combine_star_logs/combine_star_logs"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/executable/stats/combine_star_logs/combine_star_logs b/target/executable/stats/combine_star_logs/combine_star_logs
index 7c36dead..84326014 100755
--- a/target/executable/stats/combine_star_logs/combine_star_logs
+++ b/target/executable/stats/combine_star_logs/combine_star_logs
@@ -10,6 +10,9 @@
# authors of this component should specify the license in the header of such
# files, or include a separate license file detailing the licenses of all included
# files.
+#
+# Component authors:
+# * Dries Schaumont (author, maintainer)
set -e
@@ -485,10 +488,11 @@ RUN apt-get update && \
RUN pip install --upgrade pip && \
pip install --upgrade --no-cache-dir "pandas"
+LABEL org.opencontainers.image.authors="Dries Schaumont"
LABEL org.opencontainers.image.description="Companion container for running component stats combine_star_logs"
-LABEL org.opencontainers.image.created="2024-11-05T15:39:41Z"
+LABEL org.opencontainers.image.created="2024-12-17T13:58:22Z"
LABEL org.opencontainers.image.source="https://github.com/viash-hub/htrnaseq"
-LABEL org.opencontainers.image.revision="65dd41d8b1b4a307735c72320c96c0880c75f17f"
+LABEL org.opencontainers.image.revision="82647a421dae521a9563f7f02050f13a1319eb4a"
LABEL org.opencontainers.image.version="main"
VIASHDOCKER
diff --git a/target/executable/stats/combine_star_logs/nextflow_labels.config b/target/executable/stats/combine_star_logs/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/executable/stats/combine_star_logs/nextflow_labels.config
+++ b/target/executable/stats/combine_star_logs/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/executable/stats/generate_pool_statistics/.config.vsh.yaml b/target/executable/stats/generate_pool_statistics/.config.vsh.yaml
index 09b52aef..1fb63c0c 100644
--- a/target/executable/stats/generate_pool_statistics/.config.vsh.yaml
+++ b/target/executable/stats/generate_pool_statistics/.config.vsh.yaml
@@ -1,6 +1,33 @@
name: "generate_pool_statistics"
namespace: "stats"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "author"
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Marijke Van Moerbeke"
+ roles:
+ - "contributor"
+ info:
+ links:
+ github: "mvanmoerbeke"
+ orcid: "0000-0002-3097-5621"
+ linkedin: "marijke-van-moerbeke-84303a34"
+ organizations:
+ - name: "OpenAnalytics"
+ href: "https://www.openanalytics.eu"
+ role: "Statistical Consultant"
argument_groups:
- name: "Arguments"
arguments:
@@ -155,8 +182,8 @@ build_info:
output: "target/executable/stats/generate_pool_statistics"
executable: "target/executable/stats/generate_pool_statistics/generate_pool_statistics"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/executable/stats/generate_pool_statistics/generate_pool_statistics b/target/executable/stats/generate_pool_statistics/generate_pool_statistics
index 2b6b0a02..7e70eae6 100755
--- a/target/executable/stats/generate_pool_statistics/generate_pool_statistics
+++ b/target/executable/stats/generate_pool_statistics/generate_pool_statistics
@@ -10,6 +10,10 @@
# authors of this component should specify the license in the header of such
# files, or include a separate license file detailing the licenses of all included
# files.
+#
+# Component authors:
+# * Dries Schaumont (author, maintainer)
+# * Marijke Van Moerbeke (contributor)
set -e
@@ -477,10 +481,11 @@ RUN apt-get update && \
RUN pip install --upgrade pip && \
pip install --upgrade --no-cache-dir "pandas"
+LABEL org.opencontainers.image.authors="Dries Schaumont, Marijke Van Moerbeke"
LABEL org.opencontainers.image.description="Companion container for running component stats generate_pool_statistics"
-LABEL org.opencontainers.image.created="2024-11-05T15:39:43Z"
+LABEL org.opencontainers.image.created="2024-12-17T13:58:22Z"
LABEL org.opencontainers.image.source="https://github.com/viash-hub/htrnaseq"
-LABEL org.opencontainers.image.revision="65dd41d8b1b4a307735c72320c96c0880c75f17f"
+LABEL org.opencontainers.image.revision="82647a421dae521a9563f7f02050f13a1319eb4a"
LABEL org.opencontainers.image.version="main"
VIASHDOCKER
@@ -1073,6 +1078,8 @@ dep = {
### VIASH END
+INDEX_COL = ["WellBC", "WellID"]
+
if __name__ == "__main__":
#########
# nrReadsNrGenesPerChrom file
@@ -1082,17 +1089,18 @@ if __name__ == "__main__":
nr_reads_nr_genes_wells.append(pd.read_csv(nr_reads_nr_genes_file,
header=0, delimiter="\\t",
dtype={"WellBC": pd.StringDtype(),
+ "WellID": pd.StringDtype(),
"Chr": pd.StringDtype(),
"NumberOfReads": pd.UInt64Dtype(),
"NumberOfGenes": pd.UInt64Dtype()}))
nr_reads_nr_genes_pool = pd.concat(nr_reads_nr_genes_wells, ignore_index=True,)
- total_nr_reads_per_chromosome = nr_reads_nr_genes_pool.pivot_table(index="WellBC", columns="Chr",
+ total_nr_reads_per_chromosome = nr_reads_nr_genes_pool.pivot_table(index=INDEX_COL, columns="Chr",
values=["NumberOfReads"], fill_value=0,
aggfunc="sum").droplevel(0, axis=1)
total_nr_reads_per_chromosome.columns.name = None
##### Total number of genes from all chromosomes
- total_nr_genes = nr_reads_nr_genes_pool.loc[:,['WellBC', 'NumberOfGenes']].groupby("WellBC").sum()
+ total_nr_genes = nr_reads_nr_genes_pool.loc[:, INDEX_COL + ['NumberOfGenes']].groupby(["WellBC", "WellID"]).sum()
##### Total counts across (irrespective of chromosome)
total_sum_of_reads = total_nr_reads_per_chromosome.sum(numeric_only=True, axis=1)
@@ -1141,10 +1149,10 @@ if __name__ == "__main__":
**cols_to_add
)
- total_nr_reads_per_chromosome.reset_index(names="WellBC")\\
+ total_nr_reads_per_chromosome.reset_index(names=INDEX_COL)\\
.to_csv(par["nrReadsNrGenesPerChromPool"], sep="\\t",
header=True, index=False, float_format="%g",
- columns=("WellBC",) + tuple(chromosome_names) + tuple(cols_to_add.keys())
+ columns=tuple(INDEX_COL) + tuple(chromosome_names) + tuple(cols_to_add.keys())
)
VIASHMAIN
python -B "\$tempscript" &
diff --git a/target/executable/stats/generate_pool_statistics/nextflow_labels.config b/target/executable/stats/generate_pool_statistics/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/executable/stats/generate_pool_statistics/nextflow_labels.config
+++ b/target/executable/stats/generate_pool_statistics/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/executable/stats/generate_well_statistics/.config.vsh.yaml b/target/executable/stats/generate_well_statistics/.config.vsh.yaml
index 87ae083e..394cca74 100644
--- a/target/executable/stats/generate_well_statistics/.config.vsh.yaml
+++ b/target/executable/stats/generate_well_statistics/.config.vsh.yaml
@@ -1,6 +1,33 @@
name: "generate_well_statistics"
namespace: "stats"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "author"
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Marijke Van Moerbeke"
+ roles:
+ - "contributor"
+ info:
+ links:
+ github: "mvanmoerbeke"
+ orcid: "0000-0002-3097-5621"
+ linkedin: "marijke-van-moerbeke-84303a34"
+ organizations:
+ - name: "OpenAnalytics"
+ href: "https://www.openanalytics.eu"
+ role: "Statistical Consultant"
argument_groups:
- name: "Arguments"
arguments:
@@ -25,6 +52,15 @@ argument_groups:
direction: "input"
multiple: false
multiple_sep: ";"
+ - type: "string"
+ name: "--well_id"
+ description: "ID of this well. Only used to add a metadata column to the output\
+ \ files.\n"
+ info: null
+ required: true
+ direction: "input"
+ multiple: false
+ multiple_sep: ";"
- type: "file"
name: "--processedBAMFile"
description: "Path to a .tsv file listing, per read in the BAM file,\nthe value\
@@ -226,8 +262,8 @@ build_info:
output: "target/executable/stats/generate_well_statistics"
executable: "target/executable/stats/generate_well_statistics/generate_well_statistics"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/executable/stats/generate_well_statistics/generate_well_statistics b/target/executable/stats/generate_well_statistics/generate_well_statistics
index d0b797e2..add70704 100755
--- a/target/executable/stats/generate_well_statistics/generate_well_statistics
+++ b/target/executable/stats/generate_well_statistics/generate_well_statistics
@@ -10,6 +10,10 @@
# authors of this component should specify the license in the header of such
# files, or include a separate license file detailing the licenses of all included
# files.
+#
+# Component authors:
+# * Dries Schaumont (author, maintainer)
+# * Marijke Van Moerbeke (contributor)
set -e
@@ -187,6 +191,10 @@ function ViashHelp {
echo " metadata"
echo " column to all output files."
echo ""
+ echo " --well_id"
+ echo " type: string, required parameter"
+ echo " ID of this well. Only used to add a metadata column to the output files."
+ echo ""
echo " --processedBAMFile"
echo " type: file, output, file must exist"
echo " default: processedBamFile.txt"
@@ -510,10 +518,11 @@ RUN apt-get update && \
RUN pip install --upgrade pip && \
pip install --upgrade --no-cache-dir "pysam" "pandas"
+LABEL org.opencontainers.image.authors="Dries Schaumont, Marijke Van Moerbeke"
LABEL org.opencontainers.image.description="Companion container for running component stats generate_well_statistics"
-LABEL org.opencontainers.image.created="2024-11-05T15:39:43Z"
+LABEL org.opencontainers.image.created="2024-12-17T13:58:23Z"
LABEL org.opencontainers.image.source="https://github.com/viash-hub/htrnaseq"
-LABEL org.opencontainers.image.revision="65dd41d8b1b4a307735c72320c96c0880c75f17f"
+LABEL org.opencontainers.image.revision="82647a421dae521a9563f7f02050f13a1319eb4a"
LABEL org.opencontainers.image.version="main"
VIASHDOCKER
@@ -675,6 +684,17 @@ while [[ $# -gt 0 ]]; do
VIASH_PAR_BARCODE=$(ViashRemoveFlags "$1")
shift 1
;;
+ --well_id)
+ [ -n "$VIASH_PAR_WELL_ID" ] && ViashError Bad arguments for option \'--well_id\': \'$VIASH_PAR_WELL_ID\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1
+ VIASH_PAR_WELL_ID="$2"
+ [ $# -lt 2 ] && ViashError Not enough arguments passed to --well_id. Use "--help" to get more information on the parameters. && exit 1
+ shift 2
+ ;;
+ --well_id=*)
+ [ -n "$VIASH_PAR_WELL_ID" ] && ViashError Bad arguments for option \'--well_id=*\': \'$VIASH_PAR_WELL_ID\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1
+ VIASH_PAR_WELL_ID=$(ViashRemoveFlags "$1")
+ shift 1
+ ;;
--processedBAMFile)
[ -n "$VIASH_PAR_PROCESSEDBAMFILE" ] && ViashError Bad arguments for option \'--processedBAMFile\': \'$VIASH_PAR_PROCESSEDBAMFILE\' \& \'$2\' - you should provide exactly one argument for this option. && exit 1
VIASH_PAR_PROCESSEDBAMFILE="$2"
@@ -906,6 +926,10 @@ if [ -z ${VIASH_PAR_BARCODE+x} ]; then
ViashError '--barcode' is a required argument. Use "--help" to get more information on the parameters.
exit 1
fi
+if [ -z ${VIASH_PAR_WELL_ID+x} ]; then
+ ViashError '--well_id' is a required argument. Use "--help" to get more information on the parameters.
+ exit 1
+fi
if [ -z ${VIASH_META_NAME+x} ]; then
ViashError 'name' is a required argument. Use "--help" to get more information on the parameters.
exit 1
@@ -1164,6 +1188,7 @@ import logging
par = {
'input': $( if [ ! -z ${VIASH_PAR_INPUT+x} ]; then echo "r'${VIASH_PAR_INPUT//\'/\'\"\'\"r\'}'"; else echo None; fi ),
'barcode': $( if [ ! -z ${VIASH_PAR_BARCODE+x} ]; then echo "r'${VIASH_PAR_BARCODE//\'/\'\"\'\"r\'}'"; else echo None; fi ),
+ 'well_id': $( if [ ! -z ${VIASH_PAR_WELL_ID+x} ]; then echo "r'${VIASH_PAR_WELL_ID//\'/\'\"\'\"r\'}'"; else echo None; fi ),
'processedBAMFile': $( if [ ! -z ${VIASH_PAR_PROCESSEDBAMFILE+x} ]; then echo "r'${VIASH_PAR_PROCESSEDBAMFILE//\'/\'\"\'\"r\'}'"; else echo None; fi ),
'nrReadsNrGenesPerChrom': $( if [ ! -z ${VIASH_PAR_NRREADSNRGENESPERCHROM+x} ]; then echo "r'${VIASH_PAR_NRREADSNRGENESPERCHROM//\'/\'\"\'\"r\'}'"; else echo None; fi ),
'nrReadsNrUMIsPerCB': $( if [ ! -z ${VIASH_PAR_NRREADSNRUMISPERCB+x} ]; then echo "r'${VIASH_PAR_NRREADSNRUMISPERCB//\'/\'\"\'\"r\'}'"; else echo None; fi ),
@@ -1218,11 +1243,11 @@ if __name__ == "__main__":
columns=tags_selection)
tag_dataframe_to_write = tag_dataframe.copy()
logger.info("Done reading BAM file. Found %i entries", tag_dataframe.shape[0])
- tag_dataframe.assign(WellBC=par["barcode"])\\
+ tag_dataframe.assign(WellBC=par["barcode"], WellID=par["well_id"])\\
.reset_index(names="Chr")\\
.to_csv(par["processedBAMFile"], sep="\\t", na_rep="",
header=True, index=False,
- columns=("WellBC", "Chr") + tags_selection)
+ columns=("WellBC", "WellID", "Chr") + tags_selection)
logger.info("Constructing of dataframe done.")
# Number of genes that had a read mapped to them per chromosome,
# and the number of reads mapped to those genes per chromosome.
@@ -1232,19 +1257,19 @@ if __name__ == "__main__":
)
logger.info("Done calculating number of reads per gene and per chromesome. Writing to %s",
par['nrReadsNrGenesPerChrom'])
- nr_reads_nr_genes.reset_index(names="Chr").assign(WellBC=par["barcode"])\\
+ nr_reads_nr_genes.reset_index(names="Chr").assign(WellBC=par["barcode"], WellID=par["well_id"])\\
.to_csv(par["nrReadsNrGenesPerChrom"], sep="\\t",
header=True, index=False,
- columns=("WellBC", "Chr", "NumberOfReads", "NumberOfGenes"))
+ columns=("WellBC", "WellID", "Chr", "NumberOfReads", "NumberOfGenes"))
# Number of reads mapped to the reference, grouped by UMI
nr_read_per_umi = tag_dataframe.groupby('UB').size()\\
.drop("", errors="ignore").sort_values(ascending=False).head(100)
nr_read_per_umi_df = nr_read_per_umi.to_frame(name="N")
logger.info("Done calculating number of mapped reads per UMI, writing to %s", par["umiFreqTop"])
- nr_read_per_umi_df.assign(WellBC=par["barcode"]).reset_index(names="UB")\\
+ nr_read_per_umi_df.assign(WellBC=par["barcode"], WellID=par["well_id"]).reset_index(names="UB")\\
.to_csv(par["umiFreqTop"], header=True, sep="\\t",
- index=False, columns=("WellBC", "UB", "N"))
+ index=False, columns=("WellBC", "WellID", "UB", "N"))
# Total number of mapped reads and total number of UMIs (not grouped per chromosome)
nr_reads_and_umi_per_barcode = tag_dataframe.groupby(by="CB").agg(
@@ -1253,9 +1278,9 @@ if __name__ == "__main__":
)
logger.info("Done calculating number of mapped reads and number of UMIs per Cell Barcode, writing to %s",
par["nrReadsNrUMIsPerCB"])
- nr_reads_and_umi_per_barcode.assign(WellBC=par["barcode"]).reset_index(names="CB")\\
+ nr_reads_and_umi_per_barcode.assign(WellBC=par["barcode"], WellID=par["well_id"]).reset_index(names="CB")\\
.to_csv(par["nrReadsNrUMIsPerCB"], sep="\\t", header=True,
- index=False, columns=("WellBC", "CB", "NumberOfReads", "nrUMIs"))
+ index=False, columns=("WellBC", "WellID", "CB", "NumberOfReads", "nrUMIs"))
logger.info("Finished!")
VIASHMAIN
python -B "\$tempscript" &
diff --git a/target/executable/stats/generate_well_statistics/nextflow_labels.config b/target/executable/stats/generate_well_statistics/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/executable/stats/generate_well_statistics/nextflow_labels.config
+++ b/target/executable/stats/generate_well_statistics/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/nextflow/eset/create_eset/.config.vsh.yaml b/target/nextflow/eset/create_eset/.config.vsh.yaml
index a54d5449..fcc19fad 100644
--- a/target/nextflow/eset/create_eset/.config.vsh.yaml
+++ b/target/nextflow/eset/create_eset/.config.vsh.yaml
@@ -1,6 +1,32 @@
name: "create_eset"
namespace: "eset"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Marijke Van Moerbeke"
+ roles:
+ - "author"
+ info:
+ links:
+ github: "mvanmoerbeke"
+ orcid: "0000-0002-3097-5621"
+ linkedin: "marijke-van-moerbeke-84303a34"
+ organizations:
+ - name: "OpenAnalytics"
+ href: "https://www.openanalytics.eu"
+ role: "Statistical Consultant"
argument_groups:
- name: "Arguments"
arguments:
@@ -194,8 +220,8 @@ build_info:
output: "target/nextflow/eset/create_eset"
executable: "target/nextflow/eset/create_eset/main.nf"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/nextflow/eset/create_eset/main.nf b/target/nextflow/eset/create_eset/main.nf
index bebb5acc..921c8dd8 100644
--- a/target/nextflow/eset/create_eset/main.nf
+++ b/target/nextflow/eset/create_eset/main.nf
@@ -8,6 +8,10 @@
// authors of this component should specify the license in the header of such
// files, or include a separate license file detailing the licenses of all included
// files.
+//
+// Component authors:
+// * Dries Schaumont (maintainer)
+// * Marijke Van Moerbeke (author)
////////////////////////////
// VDSL3 helper functions //
@@ -2807,6 +2811,49 @@ meta = [
"name" : "create_eset",
"namespace" : "eset",
"version" : "main",
+ "authors" : [
+ {
+ "name" : "Dries Schaumont",
+ "roles" : [
+ "maintainer"
+ ],
+ "info" : {
+ "links" : {
+ "email" : "dries@data-intuitive.com",
+ "github" : "DriesSchaumont",
+ "orcid" : "0000-0002-4389-0440",
+ "linkedin" : "dries-schaumont"
+ },
+ "organizations" : [
+ {
+ "name" : "Data Intuitive",
+ "href" : "https://www.data-intuitive.com",
+ "role" : "Data Scientist"
+ }
+ ]
+ }
+ },
+ {
+ "name" : "Marijke Van Moerbeke",
+ "roles" : [
+ "author"
+ ],
+ "info" : {
+ "links" : {
+ "github" : "mvanmoerbeke",
+ "orcid" : "0000-0002-3097-5621",
+ "linkedin" : "marijke-van-moerbeke-84303a34"
+ },
+ "organizations" : [
+ {
+ "name" : "OpenAnalytics",
+ "href" : "https://www.openanalytics.eu",
+ "role" : "Statistical Consultant"
+ }
+ ]
+ }
+ }
+ ],
"argument_groups" : [
{
"name" : "Arguments",
@@ -3043,8 +3090,8 @@ meta = [
"engine" : "docker|native",
"output" : "target/nextflow/eset/create_eset",
"viash_version" : "0.9.0",
- "git_commit" : "65dd41d8b1b4a307735c72320c96c0880c75f17f",
- "git_remote" : "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ "git_commit" : "82647a421dae521a9563f7f02050f13a1319eb4a",
+ "git_remote" : "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
},
"package_config" : {
"name" : "htrnaseq",
diff --git a/target/nextflow/eset/create_eset/nextflow.config b/target/nextflow/eset/create_eset/nextflow.config
index 224ef5ea..25f89fd7 100644
--- a/target/nextflow/eset/create_eset/nextflow.config
+++ b/target/nextflow/eset/create_eset/nextflow.config
@@ -3,6 +3,7 @@ manifest {
mainScript = 'main.nf'
nextflowVersion = '!>=20.12.1-edge'
version = 'main'
+ author = 'Dries Schaumont, Marijke Van Moerbeke'
}
process.container = 'nextflow/bash:latest'
diff --git a/target/nextflow/eset/create_eset/nextflow_labels.config b/target/nextflow/eset/create_eset/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/nextflow/eset/create_eset/nextflow_labels.config
+++ b/target/nextflow/eset/create_eset/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/nextflow/eset/create_eset/nextflow_schema.json b/target/nextflow/eset/create_eset/nextflow_schema.json
index 84b5f12d..1e6f217e 100644
--- a/target/nextflow/eset/create_eset/nextflow_schema.json
+++ b/target/nextflow/eset/create_eset/nextflow_schema.json
@@ -60,7 +60,7 @@
"description": "Type: `file`, required, default: `$id.$key.output.rds`. ",
"help_text": "Type: `file`, required, default: `$id.$key.output.rds`. "
,
- "default": "$id.$key.output.rds"
+ "default":"$id.$key.output.rds"
}
diff --git a/target/nextflow/eset/create_fdata/.config.vsh.yaml b/target/nextflow/eset/create_fdata/.config.vsh.yaml
index 99a19dcc..29aceed1 100644
--- a/target/nextflow/eset/create_fdata/.config.vsh.yaml
+++ b/target/nextflow/eset/create_fdata/.config.vsh.yaml
@@ -1,6 +1,32 @@
name: "create_fdata"
namespace: "eset"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Marijke Van Moerbeke"
+ roles:
+ - "contributor"
+ info:
+ links:
+ github: "mvanmoerbeke"
+ orcid: "0000-0002-3097-5621"
+ linkedin: "marijke-van-moerbeke-84303a34"
+ organizations:
+ - name: "OpenAnalytics"
+ href: "https://www.openanalytics.eu"
+ role: "Statistical Consultant"
argument_groups:
- name: "Arguments"
arguments:
@@ -151,8 +177,8 @@ build_info:
output: "target/nextflow/eset/create_fdata"
executable: "target/nextflow/eset/create_fdata/main.nf"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/nextflow/eset/create_fdata/main.nf b/target/nextflow/eset/create_fdata/main.nf
index 0948b6b0..5b08c223 100644
--- a/target/nextflow/eset/create_fdata/main.nf
+++ b/target/nextflow/eset/create_fdata/main.nf
@@ -8,6 +8,10 @@
// authors of this component should specify the license in the header of such
// files, or include a separate license file detailing the licenses of all included
// files.
+//
+// Component authors:
+// * Dries Schaumont (maintainer)
+// * Marijke Van Moerbeke (contributor)
////////////////////////////
// VDSL3 helper functions //
@@ -2807,6 +2811,49 @@ meta = [
"name" : "create_fdata",
"namespace" : "eset",
"version" : "main",
+ "authors" : [
+ {
+ "name" : "Dries Schaumont",
+ "roles" : [
+ "maintainer"
+ ],
+ "info" : {
+ "links" : {
+ "email" : "dries@data-intuitive.com",
+ "github" : "DriesSchaumont",
+ "orcid" : "0000-0002-4389-0440",
+ "linkedin" : "dries-schaumont"
+ },
+ "organizations" : [
+ {
+ "name" : "Data Intuitive",
+ "href" : "https://www.data-intuitive.com",
+ "role" : "Data Scientist"
+ }
+ ]
+ }
+ },
+ {
+ "name" : "Marijke Van Moerbeke",
+ "roles" : [
+ "contributor"
+ ],
+ "info" : {
+ "links" : {
+ "github" : "mvanmoerbeke",
+ "orcid" : "0000-0002-3097-5621",
+ "linkedin" : "marijke-van-moerbeke-84303a34"
+ },
+ "organizations" : [
+ {
+ "name" : "OpenAnalytics",
+ "href" : "https://www.openanalytics.eu",
+ "role" : "Statistical Consultant"
+ }
+ ]
+ }
+ }
+ ],
"argument_groups" : [
{
"name" : "Arguments",
@@ -2997,8 +3044,8 @@ meta = [
"engine" : "docker|native",
"output" : "target/nextflow/eset/create_fdata",
"viash_version" : "0.9.0",
- "git_commit" : "65dd41d8b1b4a307735c72320c96c0880c75f17f",
- "git_remote" : "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ "git_commit" : "82647a421dae521a9563f7f02050f13a1319eb4a",
+ "git_remote" : "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
},
"package_config" : {
"name" : "htrnaseq",
diff --git a/target/nextflow/eset/create_fdata/nextflow.config b/target/nextflow/eset/create_fdata/nextflow.config
index 9487f5c3..755e3ee5 100644
--- a/target/nextflow/eset/create_fdata/nextflow.config
+++ b/target/nextflow/eset/create_fdata/nextflow.config
@@ -4,6 +4,7 @@ manifest {
nextflowVersion = '!>=20.12.1-edge'
version = 'main'
description = 'Create a fdata file\n'
+ author = 'Dries Schaumont, Marijke Van Moerbeke'
}
process.container = 'nextflow/bash:latest'
diff --git a/target/nextflow/eset/create_fdata/nextflow_labels.config b/target/nextflow/eset/create_fdata/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/nextflow/eset/create_fdata/nextflow_labels.config
+++ b/target/nextflow/eset/create_fdata/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/nextflow/eset/create_fdata/nextflow_schema.json b/target/nextflow/eset/create_fdata/nextflow_schema.json
index 1917415c..cde29031 100644
--- a/target/nextflow/eset/create_fdata/nextflow_schema.json
+++ b/target/nextflow/eset/create_fdata/nextflow_schema.json
@@ -30,7 +30,7 @@
"description": "Type: `file`, default: `$id.$key.output.txt`. Tab-delimited text file containing information about the \u0027gene\u0027 or \u0027transcript\u0027\nentries from the input GTF file",
"help_text": "Type: `file`, default: `$id.$key.output.txt`. Tab-delimited text file containing information about the \u0027gene\u0027 or \u0027transcript\u0027\nentries from the input GTF file. The \u0027transcript\u0027 entries are used in case the source\nof the GTF was \u0027refGene\u0027 or \u0027ncbiRefSeq\u0027. \n"
,
- "default": "$id.$key.output.txt"
+ "default":"$id.$key.output.txt"
}
diff --git a/target/nextflow/eset/create_pdata/.config.vsh.yaml b/target/nextflow/eset/create_pdata/.config.vsh.yaml
index 64fab900..3e7dc011 100644
--- a/target/nextflow/eset/create_pdata/.config.vsh.yaml
+++ b/target/nextflow/eset/create_pdata/.config.vsh.yaml
@@ -1,6 +1,32 @@
name: "create_pdata"
namespace: "eset"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Marijke Van Moerbeke"
+ roles:
+ - "contributor"
+ info:
+ links:
+ github: "mvanmoerbeke"
+ orcid: "0000-0002-3097-5621"
+ linkedin: "marijke-van-moerbeke-84303a34"
+ organizations:
+ - name: "OpenAnalytics"
+ href: "https://www.openanalytics.eu"
+ role: "Statistical Consultant"
argument_groups:
- name: "Arguments"
arguments:
@@ -165,8 +191,8 @@ build_info:
output: "target/nextflow/eset/create_pdata"
executable: "target/nextflow/eset/create_pdata/main.nf"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/nextflow/eset/create_pdata/main.nf b/target/nextflow/eset/create_pdata/main.nf
index 6c0a3e8f..12c25cb5 100644
--- a/target/nextflow/eset/create_pdata/main.nf
+++ b/target/nextflow/eset/create_pdata/main.nf
@@ -8,6 +8,10 @@
// authors of this component should specify the license in the header of such
// files, or include a separate license file detailing the licenses of all included
// files.
+//
+// Component authors:
+// * Dries Schaumont (maintainer)
+// * Marijke Van Moerbeke (contributor)
////////////////////////////
// VDSL3 helper functions //
@@ -2807,6 +2811,49 @@ meta = [
"name" : "create_pdata",
"namespace" : "eset",
"version" : "main",
+ "authors" : [
+ {
+ "name" : "Dries Schaumont",
+ "roles" : [
+ "maintainer"
+ ],
+ "info" : {
+ "links" : {
+ "email" : "dries@data-intuitive.com",
+ "github" : "DriesSchaumont",
+ "orcid" : "0000-0002-4389-0440",
+ "linkedin" : "dries-schaumont"
+ },
+ "organizations" : [
+ {
+ "name" : "Data Intuitive",
+ "href" : "https://www.data-intuitive.com",
+ "role" : "Data Scientist"
+ }
+ ]
+ }
+ },
+ {
+ "name" : "Marijke Van Moerbeke",
+ "roles" : [
+ "contributor"
+ ],
+ "info" : {
+ "links" : {
+ "github" : "mvanmoerbeke",
+ "orcid" : "0000-0002-3097-5621",
+ "linkedin" : "marijke-van-moerbeke-84303a34"
+ },
+ "organizations" : [
+ {
+ "name" : "OpenAnalytics",
+ "href" : "https://www.openanalytics.eu",
+ "role" : "Statistical Consultant"
+ }
+ ]
+ }
+ }
+ ],
"argument_groups" : [
{
"name" : "Arguments",
@@ -3011,8 +3058,8 @@ meta = [
"engine" : "docker|native",
"output" : "target/nextflow/eset/create_pdata",
"viash_version" : "0.9.0",
- "git_commit" : "65dd41d8b1b4a307735c72320c96c0880c75f17f",
- "git_remote" : "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ "git_commit" : "82647a421dae521a9563f7f02050f13a1319eb4a",
+ "git_remote" : "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
},
"package_config" : {
"name" : "htrnaseq",
@@ -3117,7 +3164,7 @@ def main(par):
logger.info("Reads per gene and chromosome table contains information for the following barcodes: %s",
", ".join(reads_and_genes_per_chr_stats.index))
logger.info("Filtering mapping statistics file columns.")
- cols_to_keep = ("NumberOfMTReads", "pctMT", "NumberOfERCCReads",
+ cols_to_keep = ("WellID", "NumberOfMTReads", "pctMT", "NumberOfERCCReads",
"pctERCC", "NumberOfChromReads", "pctChrom")
try:
reads_and_genes_per_chr_stats = reads_and_genes_per_chr_stats.loc[:,cols_to_keep]
diff --git a/target/nextflow/eset/create_pdata/nextflow.config b/target/nextflow/eset/create_pdata/nextflow.config
index b61caab6..1264db0a 100644
--- a/target/nextflow/eset/create_pdata/nextflow.config
+++ b/target/nextflow/eset/create_pdata/nextflow.config
@@ -4,6 +4,7 @@ manifest {
nextflowVersion = '!>=20.12.1-edge'
version = 'main'
description = 'Create a pdata file by combining the mapping statistics \n'
+ author = 'Dries Schaumont, Marijke Van Moerbeke'
}
process.container = 'nextflow/bash:latest'
diff --git a/target/nextflow/eset/create_pdata/nextflow_labels.config b/target/nextflow/eset/create_pdata/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/nextflow/eset/create_pdata/nextflow_labels.config
+++ b/target/nextflow/eset/create_pdata/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/nextflow/eset/create_pdata/nextflow_schema.json b/target/nextflow/eset/create_pdata/nextflow_schema.json
index fd9b1cbb..e7a40906 100644
--- a/target/nextflow/eset/create_pdata/nextflow_schema.json
+++ b/target/nextflow/eset/create_pdata/nextflow_schema.json
@@ -40,7 +40,7 @@
"description": "Type: `file`, default: `$id.$key.output.txt`. ",
"help_text": "Type: `file`, default: `$id.$key.output.txt`. "
,
- "default": "$id.$key.output.txt"
+ "default":"$id.$key.output.txt"
}
diff --git a/target/nextflow/integration_test_components/htrnaseq/check_eset/.config.vsh.yaml b/target/nextflow/integration_test_components/htrnaseq/check_eset/.config.vsh.yaml
index 61f654fb..7e160cdc 100644
--- a/target/nextflow/integration_test_components/htrnaseq/check_eset/.config.vsh.yaml
+++ b/target/nextflow/integration_test_components/htrnaseq/check_eset/.config.vsh.yaml
@@ -1,6 +1,21 @@
name: "check_eset"
namespace: "integration_test_components/htrnaseq"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "author"
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
argument_groups:
- name: "Inputs"
arguments:
@@ -133,8 +148,8 @@ build_info:
output: "target/nextflow/integration_test_components/htrnaseq/check_eset"
executable: "target/nextflow/integration_test_components/htrnaseq/check_eset/main.nf"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/nextflow/integration_test_components/htrnaseq/check_eset/main.nf b/target/nextflow/integration_test_components/htrnaseq/check_eset/main.nf
index c3f99e44..d20465e6 100644
--- a/target/nextflow/integration_test_components/htrnaseq/check_eset/main.nf
+++ b/target/nextflow/integration_test_components/htrnaseq/check_eset/main.nf
@@ -8,6 +8,9 @@
// authors of this component should specify the license in the header of such
// files, or include a separate license file detailing the licenses of all included
// files.
+//
+// Component authors:
+// * Dries Schaumont (author, maintainer)
////////////////////////////
// VDSL3 helper functions //
@@ -2807,6 +2810,30 @@ meta = [
"name" : "check_eset",
"namespace" : "integration_test_components/htrnaseq",
"version" : "main",
+ "authors" : [
+ {
+ "name" : "Dries Schaumont",
+ "roles" : [
+ "author",
+ "maintainer"
+ ],
+ "info" : {
+ "links" : {
+ "email" : "dries@data-intuitive.com",
+ "github" : "DriesSchaumont",
+ "orcid" : "0000-0002-4389-0440",
+ "linkedin" : "dries-schaumont"
+ },
+ "organizations" : [
+ {
+ "name" : "Data Intuitive",
+ "href" : "https://www.data-intuitive.com",
+ "role" : "Data Scientist"
+ }
+ ]
+ }
+ }
+ ],
"argument_groups" : [
{
"name" : "Inputs",
@@ -2970,8 +2997,8 @@ meta = [
"engine" : "docker|native",
"output" : "target/nextflow/integration_test_components/htrnaseq/check_eset",
"viash_version" : "0.9.0",
- "git_commit" : "65dd41d8b1b4a307735c72320c96c0880c75f17f",
- "git_remote" : "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ "git_commit" : "82647a421dae521a9563f7f02050f13a1319eb4a",
+ "git_remote" : "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
},
"package_config" : {
"name" : "htrnaseq",
@@ -3191,6 +3218,7 @@ stopifnot(identical(sampleNames(sample_1_result), expected_sample_names))
expected_var_labels <- c(
"WellBC",
+ "WellID",
"NumberOfMTReads",
"pctMT",
"NumberOfERCCReads",
diff --git a/target/nextflow/integration_test_components/htrnaseq/check_eset/nextflow.config b/target/nextflow/integration_test_components/htrnaseq/check_eset/nextflow.config
index be8d457d..be0865e9 100644
--- a/target/nextflow/integration_test_components/htrnaseq/check_eset/nextflow.config
+++ b/target/nextflow/integration_test_components/htrnaseq/check_eset/nextflow.config
@@ -4,6 +4,7 @@ manifest {
nextflowVersion = '!>=20.12.1-edge'
version = 'main'
description = 'This component test the ExpressionSet object as output by the main pipeline.'
+ author = 'Dries Schaumont'
}
process.container = 'nextflow/bash:latest'
diff --git a/target/nextflow/integration_test_components/htrnaseq/check_eset/nextflow_labels.config b/target/nextflow/integration_test_components/htrnaseq/check_eset/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/nextflow/integration_test_components/htrnaseq/check_eset/nextflow_labels.config
+++ b/target/nextflow/integration_test_components/htrnaseq/check_eset/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/nextflow/parallel_map/.config.vsh.yaml b/target/nextflow/parallel_map/.config.vsh.yaml
index 59270876..0b62070c 100644
--- a/target/nextflow/parallel_map/.config.vsh.yaml
+++ b/target/nextflow/parallel_map/.config.vsh.yaml
@@ -1,5 +1,32 @@
name: "parallel_map"
version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Toni Verbeiren"
+ roles:
+ - "author"
+ - "maintainer"
+ info:
+ role: "Core Team Member"
+ links:
+ github: "tverbeiren"
+ linkedin: "verbeiren"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist and CEO"
argument_groups:
- name: "Input arguments"
arguments:
@@ -237,8 +264,8 @@ build_info:
output: "target/nextflow/parallel_map"
executable: "target/nextflow/parallel_map/main.nf"
viash_version: "0.9.0"
- git_commit: "65dd41d8b1b4a307735c72320c96c0880c75f17f"
- git_remote: "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
package_config:
name: "htrnaseq"
version: "main"
diff --git a/target/nextflow/parallel_map/main.nf b/target/nextflow/parallel_map/main.nf
index ffc031e8..d2a91168 100644
--- a/target/nextflow/parallel_map/main.nf
+++ b/target/nextflow/parallel_map/main.nf
@@ -8,6 +8,10 @@
// authors of this component should specify the license in the header of such
// files, or include a separate license file detailing the licenses of all included
// files.
+//
+// Component authors:
+// * Dries Schaumont (maintainer)
+// * Toni Verbeiren (author, maintainer)
////////////////////////////
// VDSL3 helper functions //
@@ -2806,6 +2810,50 @@ meta = [
"config": processConfig(readJsonBlob('''{
"name" : "parallel_map",
"version" : "main",
+ "authors" : [
+ {
+ "name" : "Dries Schaumont",
+ "roles" : [
+ "maintainer"
+ ],
+ "info" : {
+ "links" : {
+ "email" : "dries@data-intuitive.com",
+ "github" : "DriesSchaumont",
+ "orcid" : "0000-0002-4389-0440",
+ "linkedin" : "dries-schaumont"
+ },
+ "organizations" : [
+ {
+ "name" : "Data Intuitive",
+ "href" : "https://www.data-intuitive.com",
+ "role" : "Data Scientist"
+ }
+ ]
+ }
+ },
+ {
+ "name" : "Toni Verbeiren",
+ "roles" : [
+ "author",
+ "maintainer"
+ ],
+ "info" : {
+ "role" : "Core Team Member",
+ "links" : {
+ "github" : "tverbeiren",
+ "linkedin" : "verbeiren"
+ },
+ "organizations" : [
+ {
+ "name" : "Data Intuitive",
+ "href" : "https://www.data-intuitive.com",
+ "role" : "Data Scientist and CEO"
+ }
+ ]
+ }
+ }
+ ],
"argument_groups" : [
{
"name" : "Input arguments",
@@ -3100,8 +3148,8 @@ meta = [
"engine" : "docker|native",
"output" : "target/nextflow/parallel_map",
"viash_version" : "0.9.0",
- "git_commit" : "65dd41d8b1b4a307735c72320c96c0880c75f17f",
- "git_remote" : "https://x-access-token:ghs_McZDF0yobnnHmOEb2Q4JaaB3pzr9mz1VbIOs@github.com/viash-hub/htrnaseq"
+ "git_commit" : "82647a421dae521a9563f7f02050f13a1319eb4a",
+ "git_remote" : "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
},
"package_config" : {
"name" : "htrnaseq",
diff --git a/target/nextflow/parallel_map/nextflow.config b/target/nextflow/parallel_map/nextflow.config
index c54fbac9..278861d4 100644
--- a/target/nextflow/parallel_map/nextflow.config
+++ b/target/nextflow/parallel_map/nextflow.config
@@ -4,6 +4,7 @@ manifest {
nextflowVersion = '!>=20.12.1-edge'
version = 'main'
description = 'Map wells in batch, using STAR\nSpliced Transcripts Alignment to a Reference (C) Alexander Dobin\nhttps://github.com/alexdobin/STAR\n'
+ author = 'Dries Schaumont, Toni Verbeiren'
}
process.container = 'nextflow/bash:latest'
diff --git a/target/nextflow/parallel_map/nextflow_labels.config b/target/nextflow/parallel_map/nextflow_labels.config
index 66f5e21c..2821ec46 100644
--- a/target/nextflow/parallel_map/nextflow_labels.config
+++ b/target/nextflow/parallel_map/nextflow_labels.config
@@ -70,11 +70,14 @@ profiles {
local {
// This config is for local processing.
process {
+ withName: ".*parallel_map_process" {
+ maxForks = 1
+ }
maxMemory = 25.GB
withLabel: verylowcpu { cpus = 2 }
withLabel: lowcpu { cpus = 4 }
withLabel: midcpu { cpus = 6 }
- withLabel: highcpu { cpus = 12 }
+ withLabel: highcpu { cpus = 8 }
withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
withLabel: midmem { memory = { get_memory( 12.GB * task.attempt ) } }
diff --git a/target/nextflow/parallel_map/nextflow_schema.json b/target/nextflow/parallel_map/nextflow_schema.json
index 1830bf16..98abd686 100644
--- a/target/nextflow/parallel_map/nextflow_schema.json
+++ b/target/nextflow/parallel_map/nextflow_schema.json
@@ -90,7 +90,7 @@
"description": "Type: `string`, default: `10000000000`. ",
"help_text": "Type: `string`, default: `10000000000`. "
,
- "default": "10000000000"
+ "default":"10000000000"
}
@@ -111,7 +111,7 @@
"description": "Type: `integer`, default: `1`. Number of threads to use for a single STAR execution",
"help_text": "Type: `integer`, default: `1`. Number of threads to use for a single STAR execution."
,
- "default": "1"
+ "default":1
}
@@ -132,7 +132,7 @@
"description": "Type: List of `file`, required, default: `$id.$key.output_*./*`, multiple_sep: `\";\"`. Location of the output folders, 1 folder per barcode",
"help_text": "Type: List of `file`, required, default: `$id.$key.output_*./*`, multiple_sep: `\";\"`. Location of the output folders, 1 folder per barcode. The value used\nfor this argument must contain a \u0027*\u0027, which will be replaced with the\nbarcode to form the final output location for that barcode.\n"
,
- "default": "$id.$key.output_*./*"
+ "default":"$id.$key.output_*./*"
}
@@ -143,7 +143,7 @@
"description": "Type: `file`, default: `$id.$key.joblog.txt`. Where to store the log file listing all the jobs",
"help_text": "Type: `file`, default: `$id.$key.joblog.txt`. Where to store the log file listing all the jobs."
,
- "default": "$id.$key.joblog.txt"
+ "default":"$id.$key.joblog.txt"
}
diff --git a/target/nextflow/report/create_report/.config.vsh.yaml b/target/nextflow/report/create_report/.config.vsh.yaml
new file mode 100644
index 00000000..fff208e5
--- /dev/null
+++ b/target/nextflow/report/create_report/.config.vsh.yaml
@@ -0,0 +1,235 @@
+name: "create_report"
+namespace: "report"
+version: "main"
+authors:
+- name: "Dries Schaumont"
+ roles:
+ - "maintainer"
+ info:
+ links:
+ email: "dries@data-intuitive.com"
+ github: "DriesSchaumont"
+ orcid: "0000-0002-4389-0440"
+ linkedin: "dries-schaumont"
+ organizations:
+ - name: "Data Intuitive"
+ href: "https://www.data-intuitive.com"
+ role: "Data Scientist"
+- name: "Marijke Van Moerbeke"
+ roles:
+ - "author"
+ - "maintainer"
+ info:
+ links:
+ github: "mvanmoerbeke"
+ orcid: "0000-0002-3097-5621"
+ linkedin: "marijke-van-moerbeke-84303a34"
+ organizations:
+ - name: "OpenAnalytics"
+ href: "https://www.openanalytics.eu"
+ role: "Statistical Consultant"
+argument_groups:
+- name: "Arguments"
+ arguments:
+ - type: "file"
+ name: "--eset"
+ info: null
+ must_exist: true
+ create_parent: true
+ required: true
+ direction: "input"
+ multiple: true
+ multiple_sep: ";"
+ - type: "file"
+ name: "--output_report"
+ info: null
+ example:
+ - "report.html"
+ must_exist: true
+ create_parent: true
+ required: true
+ direction: "output"
+ multiple: false
+ multiple_sep: ";"
+resources:
+- type: "r_script"
+ path: "script.R"
+ is_executable: true
+- type: "r_script"
+ path: "template.Rmd"
+ is_executable: true
+- type: "r_script"
+ path: "plateLayouts.R"
+ is_executable: true
+- type: "file"
+ path: "OutputSTARsolo.png"
+- type: "file"
+ path: "nextflow_labels.config"
+ dest: "nextflow_labels.config"
+description: "Create a basic QC report in HTML format based on a number of esets.\n"
+test_resources:
+- type: "r_script"
+ path: "test.R"
+ is_executable: true
+- type: "file"
+ path: "test_data"
+info: null
+status: "enabled"
+requirements:
+ commands:
+ - "ps"
+license: "MIT"
+links:
+ repository: "https://github.com/viash-hub/htrnaseq"
+runners:
+- type: "executable"
+ id: "executable"
+ docker_setup_strategy: "ifneedbepullelsecachedbuild"
+- type: "nextflow"
+ id: "nextflow"
+ directives:
+ tag: "$id"
+ auto:
+ simplifyInput: true
+ simplifyOutput: false
+ transcript: false
+ publish: false
+ config:
+ labels:
+ mem1gb: "memory = 1000000000.B"
+ mem2gb: "memory = 2000000000.B"
+ mem5gb: "memory = 5000000000.B"
+ mem10gb: "memory = 10000000000.B"
+ mem20gb: "memory = 20000000000.B"
+ mem50gb: "memory = 50000000000.B"
+ mem100gb: "memory = 100000000000.B"
+ mem200gb: "memory = 200000000000.B"
+ mem500gb: "memory = 500000000000.B"
+ mem1tb: "memory = 1000000000000.B"
+ mem2tb: "memory = 2000000000000.B"
+ mem5tb: "memory = 5000000000000.B"
+ mem10tb: "memory = 10000000000000.B"
+ mem20tb: "memory = 20000000000000.B"
+ mem50tb: "memory = 50000000000000.B"
+ mem100tb: "memory = 100000000000000.B"
+ mem200tb: "memory = 200000000000000.B"
+ mem500tb: "memory = 500000000000000.B"
+ mem1gib: "memory = 1073741824.B"
+ mem2gib: "memory = 2147483648.B"
+ mem4gib: "memory = 4294967296.B"
+ mem8gib: "memory = 8589934592.B"
+ mem16gib: "memory = 17179869184.B"
+ mem32gib: "memory = 34359738368.B"
+ mem64gib: "memory = 68719476736.B"
+ mem128gib: "memory = 137438953472.B"
+ mem256gib: "memory = 274877906944.B"
+ mem512gib: "memory = 549755813888.B"
+ mem1tib: "memory = 1099511627776.B"
+ mem2tib: "memory = 2199023255552.B"
+ mem4tib: "memory = 4398046511104.B"
+ mem8tib: "memory = 8796093022208.B"
+ mem16tib: "memory = 17592186044416.B"
+ mem32tib: "memory = 35184372088832.B"
+ mem64tib: "memory = 70368744177664.B"
+ mem128tib: "memory = 140737488355328.B"
+ mem256tib: "memory = 281474976710656.B"
+ mem512tib: "memory = 562949953421312.B"
+ cpu1: "cpus = 1"
+ cpu2: "cpus = 2"
+ cpu5: "cpus = 5"
+ cpu10: "cpus = 10"
+ cpu20: "cpus = 20"
+ cpu50: "cpus = 50"
+ cpu100: "cpus = 100"
+ cpu200: "cpus = 200"
+ cpu500: "cpus = 500"
+ cpu1000: "cpus = 1000"
+ script:
+ - "includeConfig(\"nextflow_labels.config\")"
+ debug: false
+ container: "docker"
+engines:
+- type: "docker"
+ id: "docker"
+ image: "rocker/r2u:24.04"
+ target_registry: "images.viash-hub.com"
+ target_tag: "main"
+ namespace_separator: "/"
+ setup:
+ - type: "apt"
+ packages:
+ - "procps"
+ - "pandoc"
+ interactive: false
+ - type: "r"
+ cran:
+ - "ggplot2"
+ - "knitr"
+ - "gridExtra"
+ - "RColorBrewer"
+ - "processx"
+ - "whisker"
+ - "rmarkdown"
+ - "bookdown"
+ - "data.table"
+ - "platetools"
+ - "htmltools"
+ - "DT"
+ - "logger"
+ - "bit64"
+ bioc:
+ - "Biobase"
+ - "ComplexHeatmap"
+ script:
+ - "install.packages(\"oaStyle\", repos = c(rdepot = \"https://repos.openanalytics.eu/repo/public\"\
+ , getOption(\"repos\")))"
+ bioc_force_install: false
+ test_setup:
+ - type: "r"
+ packages:
+ - "testthat"
+ - "R.utils"
+ bioc_force_install: false
+ entrypoint: []
+ cmd: null
+- type: "native"
+ id: "native"
+build_info:
+ config: "src/report/config.vsh.yaml"
+ runner: "nextflow"
+ engine: "docker|native"
+ output: "target/nextflow/report/create_report"
+ executable: "target/nextflow/report/create_report/main.nf"
+ viash_version: "0.9.0"
+ git_commit: "82647a421dae521a9563f7f02050f13a1319eb4a"
+ git_remote: "https://x-access-token:ghs_GvoC19gNBNw8DS3yDc8aa44laHZP4K2GBiY3@github.com/viash-hub/htrnaseq"
+package_config:
+ name: "htrnaseq"
+ version: "main"
+ description: "High-throughput pipeline [WIP]\n"
+ info:
+ test_resources:
+ - path: "gs://viash-hub-test-data/htrnaseq/v1/"
+ dest: "resources_test"
+ viash_version: "0.9.0"
+ source: "src"
+ target: "target"
+ config_mods:
+ - ".requirements.commands := ['ps']\n.runners[.type == 'nextflow'].config.script\
+ \ := 'includeConfig(\"nextflow_labels.config\")'\n.resources += {path: '/src/config/labels.config',\
+ \ dest: 'nextflow_labels.config'}\n"
+ - ".engines += { type: \"native\" }"
+ - ".engines[.type == 'docker'].target_registry := 'images.viash-hub.com'"
+ - ".engines[.type == 'docker'].target_tag := 'main'"
+ keywords:
+ - "bioinformatics"
+ - "sequence"
+ - "high-throughput"
+ - "mapping"
+ - "counting"
+ - "pipeline"
+ license: "MIT"
+ organization: "vsh"
+ links:
+ repository: "https://github.com/viash-hub/htrnaseq"
+ issue_tracker: "https://github.com/viash-hub/htrnaseq/issues"
diff --git a/target/nextflow/report/create_report/OutputSTARsolo.png b/target/nextflow/report/create_report/OutputSTARsolo.png
new file mode 100644
index 00000000..cb77d8e0
Binary files /dev/null and b/target/nextflow/report/create_report/OutputSTARsolo.png differ
diff --git a/target/nextflow/report/create_report/main.nf b/target/nextflow/report/create_report/main.nf
new file mode 100644
index 00000000..b282fcf7
--- /dev/null
+++ b/target/nextflow/report/create_report/main.nf
@@ -0,0 +1,3683 @@
+// create_report main
+//
+// This wrapper script is auto-generated by viash 0.9.0 and is thus a derivative
+// work thereof. This software comes with ABSOLUTELY NO WARRANTY from Data
+// Intuitive.
+//
+// The component may contain files which fall under a different license. The
+// authors of this component should specify the license in the header of such
+// files, or include a separate license file detailing the licenses of all included
+// files.
+//
+// Component authors:
+// * Dries Schaumont (maintainer)
+// * Marijke Van Moerbeke (author, maintainer)
+
+////////////////////////////
+// VDSL3 helper functions //
+////////////////////////////
+
+// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_checkArgumentType.nf'
+class UnexpectedArgumentTypeException extends Exception {
+ String errorIdentifier
+ String stage
+ String plainName
+ String expectedClass
+ String foundClass
+
+ // ${key ? " in module '$key'" : ""}${id ? " id '$id'" : ""}
+ UnexpectedArgumentTypeException(String errorIdentifier, String stage, String plainName, String expectedClass, String foundClass) {
+ super("Error${errorIdentifier ? " $errorIdentifier" : ""}:${stage ? " $stage" : "" } argument '${plainName}' has the wrong type. " +
+ "Expected type: ${expectedClass}. Found type: ${foundClass}")
+ this.errorIdentifier = errorIdentifier
+ this.stage = stage
+ this.plainName = plainName
+ this.expectedClass = expectedClass
+ this.foundClass = foundClass
+ }
+}
+
+/**
+ * Checks if the given value is of the expected type. If not, an exception is thrown.
+ *
+ * @param stage The stage of the argument (input or output)
+ * @param par The parameter definition
+ * @param value The value to check
+ * @param errorIdentifier The identifier to use in the error message
+ * @return The value, if it is of the expected type
+ * @throws UnexpectedArgumentTypeException If the value is not of the expected type
+*/
+def _checkArgumentType(String stage, Map par, Object value, String errorIdentifier) {
+ // expectedClass will only be != null if value is not of the expected type
+ def expectedClass = null
+ def foundClass = null
+
+ // todo: split if need be
+
+ if (!par.required && value == null) {
+ expectedClass = null
+ } else if (par.multiple) {
+ if (value !instanceof Collection) {
+ value = [value]
+ }
+
+ // split strings
+ value = value.collectMany{ val ->
+ if (val instanceof String) {
+ // collect() to ensure that the result is a List and not simply an array
+ val.split(par.multiple_sep).collect()
+ } else {
+ [val]
+ }
+ }
+
+ // process globs
+ if (par.type == "file" && par.direction == "input") {
+ value = value.collect{ it instanceof String ? file(it, hidden: true) : it }.flatten()
+ }
+
+ // check types of elements in list
+ try {
+ value = value.collect { listVal ->
+ _checkArgumentType(stage, par + [multiple: false], listVal, errorIdentifier)
+ }
+ } catch (UnexpectedArgumentTypeException e) {
+ expectedClass = "List[${e.expectedClass}]"
+ foundClass = "List[${e.foundClass}]"
+ }
+ } else if (par.type == "string") {
+ // cast to string if need be
+ if (value instanceof GString) {
+ value = value.toString()
+ }
+ expectedClass = value instanceof String ? null : "String"
+ } else if (par.type == "integer") {
+ // cast to integer if need be
+ if (value instanceof String) {
+ try {
+ value = value.toInteger()
+ } catch (NumberFormatException e) {
+ // do nothing
+ }
+ }
+ if (value instanceof java.math.BigInteger) {
+ value = value.intValue()
+ }
+ expectedClass = value instanceof Integer ? null : "Integer"
+ } else if (par.type == "long") {
+ // cast to long if need be
+ if (value instanceof String) {
+ try {
+ value = value.toLong()
+ } catch (NumberFormatException e) {
+ // do nothing
+ }
+ }
+ if (value instanceof Integer) {
+ value = value.toLong()
+ }
+ expectedClass = value instanceof Long ? null : "Long"
+ } else if (par.type == "double") {
+ // cast to double if need be
+ if (value instanceof String) {
+ try {
+ value = value.toDouble()
+ } catch (NumberFormatException e) {
+ // do nothing
+ }
+ }
+ if (value instanceof java.math.BigDecimal) {
+ value = value.doubleValue()
+ }
+ if (value instanceof Float) {
+ value = value.toDouble()
+ }
+ expectedClass = value instanceof Double ? null : "Double"
+ } else if (par.type == "boolean" | par.type == "boolean_true" | par.type == "boolean_false") {
+ // cast to boolean if need be
+ if (value instanceof String) {
+ def valueLower = value.toLowerCase()
+ if (valueLower == "true") {
+ value = true
+ } else if (valueLower == "false") {
+ value = false
+ }
+ }
+ expectedClass = value instanceof Boolean ? null : "Boolean"
+ } else if (par.type == "file" && (par.direction == "input" || stage == "output")) {
+ // cast to path if need be
+ if (value instanceof String) {
+ value = file(value, hidden: true)
+ }
+ if (value instanceof File) {
+ value = value.toPath()
+ }
+ expectedClass = value instanceof Path ? null : "Path"
+ } else if (par.type == "file" && stage == "input" && par.direction == "output") {
+ // cast to string if need be
+ if (value instanceof GString) {
+ value = value.toString()
+ }
+ expectedClass = value instanceof String ? null : "String"
+ } else {
+ // didn't find a match for par.type
+ expectedClass = par.type
+ }
+
+ if (expectedClass != null) {
+ if (foundClass == null) {
+ foundClass = value.getClass().getName()
+ }
+ throw new UnexpectedArgumentTypeException(errorIdentifier, stage, par.plainName, expectedClass, foundClass)
+ }
+
+ return value
+}
+// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processInputValues.nf'
+Map _processInputValues(Map inputs, Map config, String id, String key) {
+ if (!workflow.stubRun) {
+ config.allArguments.each { arg ->
+ if (arg.required) {
+ assert inputs.containsKey(arg.plainName) && inputs.get(arg.plainName) != null :
+ "Error in module '${key}' id '${id}': required input argument '${arg.plainName}' is missing"
+ }
+ }
+
+ inputs = inputs.collectEntries { name, value ->
+ def par = config.allArguments.find { it.plainName == name && (it.direction == "input" || it.type == "file") }
+ assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid input argument"
+
+ value = _checkArgumentType("input", par, value, "in module '$key' id '$id'")
+
+ [ name, value ]
+ }
+ }
+ return inputs
+}
+
+// helper file: 'src/main/resources/io/viash/runners/nextflow/arguments/_processOutputValues.nf'
+Map _processOutputValues(Map outputs, Map config, String id, String key) {
+ if (!workflow.stubRun) {
+ config.allArguments.each { arg ->
+ if (arg.direction == "output" && arg.required) {
+ assert outputs.containsKey(arg.plainName) && outputs.get(arg.plainName) != null :
+ "Error in module '${key}' id '${id}': required output argument '${arg.plainName}' is missing"
+ }
+ }
+
+ outputs = outputs.collectEntries { name, value ->
+ def par = config.allArguments.find { it.plainName == name && it.direction == "output" }
+ assert par != null : "Error in module '${key}' id '${id}': '${name}' is not a valid output argument"
+
+ value = _checkArgumentType("output", par, value, "in module '$key' id '$id'")
+
+ [ name, value ]
+ }
+ }
+ return outputs
+}
+
+// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/IDChecker.nf'
+class IDChecker {
+ final def items = [] as Set
+
+ @groovy.transform.WithWriteLock
+ boolean observe(String item) {
+ if (items.contains(item)) {
+ return false
+ } else {
+ items << item
+ return true
+ }
+ }
+
+ @groovy.transform.WithReadLock
+ boolean contains(String item) {
+ return items.contains(item)
+ }
+
+ @groovy.transform.WithReadLock
+ Set getItems() {
+ return items.clone()
+ }
+}
+// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_checkUniqueIds.nf'
+
+/**
+ * Check if the ids are unique across parameter sets
+ *
+ * @param parameterSets a list of parameter sets.
+ */
+private void _checkUniqueIds(List>> parameterSets) {
+ def ppIds = parameterSets.collect{it[0]}
+ assert ppIds.size() == ppIds.unique().size() : "All argument sets should have unique ids. Detected ids: $ppIds"
+}
+
+// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_getChild.nf'
+
+// helper functions for reading params from file //
+def _getChild(parent, child) {
+ if (child.contains("://") || java.nio.file.Paths.get(child).isAbsolute()) {
+ child
+ } else {
+ def parentAbsolute = java.nio.file.Paths.get(parent).toAbsolutePath().toString()
+ parentAbsolute.replaceAll('/[^/]*$', "/") + child
+ }
+}
+
+// helper file: 'src/main/resources/io/viash/runners/nextflow/channel/_parseParamList.nf'
+/**
+ * Figure out the param list format based on the file extension
+ *
+ * @param param_list A String containing the path to the parameter list file.
+ *
+ * @return A String containing the format of the parameter list file.
+ */
+def _paramListGuessFormat(param_list) {
+ if (param_list !instanceof String) {
+ "asis"
+ } else if (param_list.endsWith(".csv")) {
+ "csv"
+ } else if (param_list.endsWith(".json") || param_list.endsWith(".jsn")) {
+ "json"
+ } else if (param_list.endsWith(".yaml") || param_list.endsWith(".yml")) {
+ "yaml"
+ } else {
+ "yaml_blob"
+ }
+}
+
+
+/**
+ * Read the param list
+ *
+ * @param param_list One of the following:
+ * - A String containing the path to the parameter list file (csv, json or yaml),
+ * - A yaml blob of a list of maps (yaml_blob),
+ * - Or a groovy list of maps (asis).
+ * @param config A Map of the Viash configuration.
+ *
+ * @return A List of Maps containing the parameters.
+ */
+def _parseParamList(param_list, Map config) {
+ // first determine format by extension
+ def paramListFormat = _paramListGuessFormat(param_list)
+
+ def paramListPath = (paramListFormat != "asis" && paramListFormat != "yaml_blob") ?
+ file(param_list, hidden: true) :
+ null
+
+ // get the correct parser function for the detected params_list format
+ def paramSets = []
+ if (paramListFormat == "asis") {
+ paramSets = param_list
+ } else if (paramListFormat == "yaml_blob") {
+ paramSets = readYamlBlob(param_list)
+ } else if (paramListFormat == "yaml") {
+ paramSets = readYaml(paramListPath)
+ } else if (paramListFormat == "json") {
+ paramSets = readJson(paramListPath)
+ } else if (paramListFormat == "csv") {
+ paramSets = readCsv(paramListPath)
+ } else {
+ error "Format of provided --param_list not recognised.\n" +
+ "Found: '$paramListFormat'.\n" +
+ "Expected: a csv file, a json file, a yaml file,\n" +
+ "a yaml blob or a groovy list of maps."
+ }
+
+ // data checks
+ assert paramSets instanceof List: "--param_list should contain a list of maps"
+ for (value in paramSets) {
+ assert value instanceof Map: "--param_list should contain a list of maps"
+ }
+
+ // id is argument
+ def idIsArgument = config.allArguments.any{it.plainName == "id"}
+
+ // Reformat from List