Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Chore

- Clear all `nextflow lint` warnings (use `channel` factory API, explicit closure parameters, unused-parameter prefixes). ([#542](https://github.com/nf-core/scrnaseq/pull/542))
- Template update for nf-core/tools v3.5.1 ([#509](https://github.com/nf-core/scrnaseq/pull/509))
- Template update for nf-core/tools v4.0.2 ([#541](https://github.com/nf-core/scrnaseq/pull/541))

Expand Down
2 changes: 1 addition & 1 deletion conf/modules.config
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ process {
publishDir = [
path: { "${params.outdir}/${params.aligner}/${meta.id}" },
mode: params.publish_dir_mode,
saveAs: { (!it.endsWith('.bam') || params.save_align_intermeds) ? it : null }
saveAs: { filename -> (!filename.endsWith('.bam') || params.save_align_intermeds) ? filename : null }
]
}

Expand Down
8 changes: 4 additions & 4 deletions subworkflows/local/align_cellranger.nf
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ workflow CELLRANGER_ALIGN {
ch_matrices_raw =
CELLRANGER_COUNT.out.outs.map { meta, mtx_files ->
def desired_files = []
mtx_files.each{
if ( it.toString().contains("raw_feature_bc_matrix") ) { desired_files.add( it ) }
mtx_files.each{ path ->
if ( path.toString().contains("raw_feature_bc_matrix") ) { desired_files.add( path ) }
}
[ meta + [input_type: 'raw'], desired_files ]
}

ch_matrices_filtered =
CELLRANGER_COUNT.out.outs.map { meta, mtx_files ->
def desired_files = []
mtx_files.each{
if ( it.toString().contains("filtered_feature_bc_matrix") ) { desired_files.add( it ) }
mtx_files.each{ path ->
if ( path.toString().contains("filtered_feature_bc_matrix") ) { desired_files.add( path ) }
}
[ meta + [input_type: 'filtered'], desired_files ]
}
Expand Down
2 changes: 1 addition & 1 deletion subworkflows/local/align_cellrangerarc.nf
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def parse_demultiplexed_output_channels(in_ch, pattern) {
meta_clone.input_type = pattern.contains('raw_') ? 'raw' : 'filtered'
// Iterate over the matrix files and add the ones matching the pattern to the desired files list
def desired_files = []
mtx_files.each{ if ( it.toString().contains("${pattern}") ) { desired_files.add( it ) } }
mtx_files.each{ path -> if ( path.toString().contains("${pattern}") ) { desired_files.add( path ) } }
[ meta_clone, desired_files ]
}

Expand Down
27 changes: 13 additions & 14 deletions subworkflows/local/align_cellrangermulti.nf
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ workflow CELLRANGER_MULTI_ALIGN {
.flatten()
.map{ meta ->
def meta_clone = meta.clone()
def data_dict = meta_clone.find{ it.key == "${meta_clone.feature_type}" }
def data_dict = meta_clone.find{ entry -> entry.key == "${meta_clone.feature_type}" }
def fastqs = data_dict?.value
meta_clone.remove( data_dict?.key )
[ meta_clone, fastqs ]
Expand Down Expand Up @@ -59,7 +59,6 @@ workflow CELLRANGER_MULTI_ALIGN {
ch_gex_frna_probeset = params.gex_frna_probe_set ? file(params.gex_frna_probe_set) : []
ch_gex_target_panel = params.gex_target_panel ? file(params.gex_target_panel) : []
ch_gex_cmo_set = params.gex_cmo_set ? file(params.gex_cmo_set) : []
ch_gex_barcodes = params.gex_barcode_sample_assignment ? file(params.gex_barcode_sample_assignment) : []
Comment thread
nictru marked this conversation as resolved.
ch_fb_reference = params.fb_reference ? file(params.fb_reference) : []
ch_vdj_primer_index = params.vdj_inner_enrichment_primers ? file(params.vdj_inner_enrichment_primers) : []
ch_beam_antigen_panel_csv = [] // currently not implemented
Expand Down Expand Up @@ -90,26 +89,26 @@ workflow CELLRANGER_MULTI_ALIGN {

// CMO
ch_grouped_fastq.gex
.map{ [it[0].id] }
.concat( PARSE_CELLRANGERMULTI_SAMPLESHEET.out.cmo.flatten().map { [ "${it.baseName}" - "_cmo", it ] } )
.map{ pair -> [pair[0].id] }
.concat( PARSE_CELLRANGERMULTI_SAMPLESHEET.out.cmo.flatten().map { csv -> [ "${csv.baseName}" - "_cmo", csv ] } )
.groupTuple()
.map { if ( it.size() == 2 ) { it[1] } else { [] } } // a correct tuple from snippet will have: [ sample, cmo.csv ]
.map { grp -> if ( grp.size() == 2 ) { grp[1] } else { [] } } // a correct tuple from snippet will have: [ sample, cmo.csv ]
.set { ch_cmo_barcode_csv }

// OCM
ch_grouped_fastq.gex
.map{ [it[0].id] }
.concat( PARSE_CELLRANGERMULTI_SAMPLESHEET.out.ocm.flatten().map { [ "${it.baseName}" - "_ocm", it ] } )
.map{ pair -> [pair[0].id] }
.concat( PARSE_CELLRANGERMULTI_SAMPLESHEET.out.ocm.flatten().map { csv -> [ "${csv.baseName}" - "_ocm", csv ] } )
.groupTuple()
.map { if ( it.size() == 2 ) { it[1] } else { [] } } // a correct tuple from snippet will have: [ sample, ocm.csv ]
.map { grp -> if ( grp.size() == 2 ) { grp[1] } else { [] } } // a correct tuple from snippet will have: [ sample, ocm.csv ]
.set { ch_ocm_barcode_csv }

// FRNA
ch_grouped_fastq.gex
.map{ [it[0].id] }
.concat( PARSE_CELLRANGERMULTI_SAMPLESHEET.out.frna.flatten().map { [ "${it.baseName}" - "_frna", it ] } )
.map{ pair -> [pair[0].id] }
.concat( PARSE_CELLRANGERMULTI_SAMPLESHEET.out.frna.flatten().map { csv -> [ "${csv.baseName}" - "_frna", csv ] } )
.groupTuple()
.map { if ( it.size() == 2 ) { it[1] } else { [] } } // a correct tuple from snippet will have: [ sample, frna.csv ]
.map { grp -> if ( grp.size() == 2 ) { grp[1] } else { [] } } // a correct tuple from snippet will have: [ sample, frna.csv ]
.set { ch_frna_sample_csv }

} else {
Expand Down Expand Up @@ -197,7 +196,7 @@ workflow CELLRANGER_MULTI_ALIGN {
// MODULE: cellranger multi
//
CELLRANGER_MULTI(
ch_grouped_fastq.gex.map{ it[0] },
ch_grouped_fastq.gex.map{ pair -> pair[0] },
ch_grouped_fastq.gex,
ch_grouped_fastq.vdj,
ch_grouped_fastq.ab,
Expand Down Expand Up @@ -244,7 +243,7 @@ def parse_demultiplexed_output_channels(in_ch, pattern) {
def out_ch = in_ch
.map { meta, mtx_files ->
def desired_files = []
mtx_files.each{ if ( it.toString().contains("${pattern}") ) { desired_files.add( it ) } }
mtx_files.each{ path -> if ( path.toString().contains("${pattern}") ) { desired_files.add( path ) } }
[ meta, desired_files ]
} // separate only desired files
.transpose() // transpose for handling one meta/file pair at a time
Expand All @@ -260,7 +259,7 @@ def parse_demultiplexed_output_channels(in_ch, pattern) {
}
[ meta_clone, mtx_files ]
} // check if output is from demultiplexed sample, if yes, correct meta.id for proper conversion naming
.filter{ it != null } // remove nulls from previous step
.filter{ item -> item != null } // remove nulls from previous step
.groupTuple( by: 0 ) // group it back as one file collection per sample

return out_ch
Expand Down
2 changes: 1 addition & 1 deletion subworkflows/local/fastqc.nf
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ workflow FASTQC_CHECK {
.map { it -> [ it[1] ] }
.set { fastqc_html_only }

fastqc_multiqc = Channel.empty()
fastqc_multiqc = channel.empty()
fastqc_multiqc = fastqc_multiqc.mix( fastqc_zip_only, fastqc_html_only )

emit:
Expand Down
2 changes: 1 addition & 1 deletion subworkflows/local/kallisto_bustools.nf
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ workflow KALLISTO_BUSTOOLS {
ch_fastq

main:
ch_versions = Channel.empty()
ch_versions = channel.empty()

assert (txp2gene && kallisto_index) || (genome_fasta && gtf):
"Must provide a genome fasta file ('--fasta') and a gtf file ('--gtf') if no index is given!"
Expand Down
12 changes: 6 additions & 6 deletions subworkflows/local/simpleaf.nf
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ workflow SIMPLEAF {
map_dir

main:
ch_versions = Channel.empty()
ch_versions = channel.empty()

/*
* Build simpleaf index if needed
Expand Down Expand Up @@ -60,20 +60,20 @@ workflow SIMPLEAF {
if (!txp2gene) {
txp2gene = SIMPLEAF_INDEX.out.t2g.collect().map { _meta, it -> it }
} else {
txp2gene = Channel.of( txp2gene )
txp2gene = channel.of( txp2gene )
}
} else {
// we have a map dir, so we do not need to build the index
simpleaf_index = Channel.of( [ [:], [] ] )
simpleaf_index = channel.of( [ [:], [] ] )
}
} else {
// we have a simpleaf index, we use it directly
// ensure simpleaf index and txp2gene are Channels
simpleaf_index = Channel.of( [ [ id: simpleaf_index.getName() ], simpleaf_index ] )
simpleaf_index = channel.of( [ [ id: simpleaf_index.getName() ], simpleaf_index ] )

// channel or null
if (txp2gene) {
txp2gene = Channel.of( txp2gene )
txp2gene = channel.of( txp2gene )
}
}

Expand Down Expand Up @@ -119,7 +119,7 @@ workflow SIMPLEAF {
/*
* Run qcatch QC (optional)
*/
ch_qcatch_report = Channel.empty()
ch_qcatch_report = channel.empty()
if ( !skip_qcatch ) {
// Map quant channel to include chemistry for qcatch: tuple(meta, chemistry, quant_dir)
ch_qcatch_input = ch_af_quant.map { meta, quant_dir -> [meta, qcatch_chemistry, quant_dir] }
Expand Down
2 changes: 1 addition & 1 deletion subworkflows/local/starsolo.nf
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,5 @@ workflow STARSOLO {
star_counts = STAR_ALIGN.out.counts
raw_counts = raw_counts
filtered_counts = filtered_counts
for_multiqc = STAR_ALIGN.out.log_final.map{ meta, it -> it }
for_multiqc = STAR_ALIGN.out.log_final.map{ _meta, logFinal -> logFinal }
}
30 changes: 15 additions & 15 deletions subworkflows/local/utils_nfcore_scrnaseq_pipeline/main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ workflow PIPELINE_INITIALISATION {
monochrome_logs // boolean: Do not use coloured log outputs
nextflow_cli_args // array: List of positional nextflow CLI args
outdir // string: The output directory where the results will be saved
input // string: Path to input samplesheet
_input // string: Path to input samplesheet
help // boolean: Display help message and exit
help_full // boolean: Show the full help message
show_hidden // boolean: Show hidden parameters in the help message
Expand Down Expand Up @@ -107,7 +107,7 @@ workflow PIPELINE_INITIALISATION {
// Create channel from input file provided through params.input
//
if (params.aligner == 'cellrangermulti') { // the cellrangermulti sub-workflow logic needs that channels have reads separated by feature_type. Cannot merge all.
Channel
channel
.fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json"))
.map {
meta, fastq_1, fastq_2 ->
Expand All @@ -118,17 +118,17 @@ workflow PIPELINE_INITIALISATION {
}
}
.groupTuple( by: [0,1] )
.map{ id, type, meta, reads -> [ id, meta, reads ] }
.map {
validateInputSamplesheet(it)
.map{ id, _type, meta, reads -> [ id, meta, reads ] }
.map { sheet_row ->
validateInputSamplesheet(sheet_row)
}
.map {
meta, fastqs ->
return [ meta, fastqs.flatten() ]
}
.set { ch_samplesheet }
} else if (params.aligner == 'cellrangerarc') { // the cellrangerarc sub-workflow logic needs that channels have a meta, type, subsample, fastqs structure.
Channel
channel
.fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json"))
.map { meta, fastq_1, fastq_2 ->
if (!fastq_2 || (meta.sample_type == "atac" && !meta.fastq_barcode)) {
Expand All @@ -141,12 +141,12 @@ workflow PIPELINE_INITIALISATION {
}
}
.groupTuple()
.map {
cellrangerarcStructure(it)
.map { structure_input ->
cellrangerarcStructure(structure_input)
}
.set { ch_samplesheet }
} else {
Channel
channel
.fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json"))
.map {
meta, fastq_1, fastq_2 ->
Expand All @@ -157,8 +157,8 @@ workflow PIPELINE_INITIALISATION {
}
}
.groupTuple()
.map {
validateInputSamplesheet(it)
.map { sheet_row ->
validateInputSamplesheet(sheet_row)
}
.map {
meta, fastqs ->
Expand Down Expand Up @@ -241,7 +241,7 @@ def validateCellrangerMultiBarcodes() {
def cellranger_multi_barcodes = file(params.cellranger_multi_barcodes).splitCsv(header: true)

// Get unique samples from input samplesheet for cross-validation
def inputSamples = file(params.input).splitCsv(header: true).collect { it.sample }.toSet()
def inputSamples = file(params.input).splitCsv(header: true).collect { row -> row.sample }.toSet()

// Check that at least one barcode column is provided for each row
// and that each sample uses only one type of barcode
Expand All @@ -268,14 +268,14 @@ def validateCellrangerMultiBarcodes() {

// Validate that at least one barcode identifier is populated in each row
if (rowsWithoutBarcodes) {
def errorDetails = rowsWithoutBarcodes.collect { "row ${it.row} (${it.multiplexed_sample_id})" }.join(', ')
def errorDetails = rowsWithoutBarcodes.collect { missing -> "row ${missing.row} (${missing.multiplexed_sample_id})" }.join(', ')
error("Please check cellranger_multi_barcodes samplesheet -> " +
"The following rows have no barcode identifiers: ${errorDetails}. " +
"Each row must have exactly one of: 'probe_barcode_ids', 'cmo_ids', or 'ocm_ids'.")
}

// Validate that no more than one barcode identifier is populated in each row
def samplesWithMixedBarcodes = sampleBarcodeTypes.findAll { multiplexed_sample_id, info -> info.types.size() > 1 }
def samplesWithMixedBarcodes = sampleBarcodeTypes.findAll { _multiplexed_sample_id, info -> info.types.size() > 1 }
if (samplesWithMixedBarcodes) {
def errorMsg = samplesWithMixedBarcodes.collect { multiplexed_sample_id, info ->
"'${multiplexed_sample_id}' (row ${info.row}) uses multiple barcode types: ${info.types.join(', ')}"
Expand Down Expand Up @@ -321,7 +321,7 @@ def cellrangerarcStructure(input) {

// Validate that the property "sample_type" is present and has valid values
def valid_sample_types = ["gex", "atac"]
def sample_type_ok = metas.collect { meta -> meta.sample_type }.unique().every { it in valid_sample_types }
def sample_type_ok = metas.collect { meta -> meta.sample_type }.unique().every { st -> st in valid_sample_types }
if (!sample_type_ok) {
error("Please check input samplesheet -> The property 'sample_type' is required and can only be 'gex' or 'atac'.")
}
Expand Down
18 changes: 9 additions & 9 deletions workflows/scrnaseq.nf
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ workflow SCRNASEQ {
//
if (params.fasta) {
if (params.fasta.endsWith('.gz')) {
ch_genome_fasta = GUNZIP_FASTA ( [ [:], ch_genome_fasta ] ).gunzip.map { it[1] }
ch_genome_fasta = GUNZIP_FASTA ( [ [:], ch_genome_fasta ] ).gunzip.map { tuple -> tuple[1] }
} else {
ch_genome_fasta = channel.value( ch_genome_fasta )
}
Expand All @@ -111,7 +111,7 @@ workflow SCRNASEQ {
//
if (params.gtf) {
if (params.gtf.endsWith('.gz')) {
ch_gtf = GUNZIP_GTF ( [ [:], ch_gtf ] ).gunzip.map { it[1] }
ch_gtf = GUNZIP_GTF ( [ [:], ch_gtf ] ).gunzip.map { tuple -> tuple[1] }
} else {
ch_gtf = channel.value( ch_gtf )
}
Expand Down Expand Up @@ -196,7 +196,7 @@ workflow SCRNASEQ {
)
ch_mtx_matrices = ch_mtx_matrices.mix( CELLRANGER_ALIGN.out.cellranger_matrices_raw, CELLRANGER_ALIGN.out.cellranger_matrices_filtered )
ch_multiqc_files = ch_multiqc_files.mix(CELLRANGER_ALIGN.out.cellranger_out.map {
meta, outs -> outs.findAll{ it -> it.name == "web_summary.html"}
_meta, outs -> outs.findAll{ summary -> summary.name == "web_summary.html"}
})
}

Expand Down Expand Up @@ -254,12 +254,12 @@ workflow SCRNASEQ {
// needs to have a collected map like that, so every sample from the samplesheet is analysed one at a time,
// allowing to have multiple samples in the sheet, having all the data-type tuples initialized,
// either empty or populated. It will be branched inside the subworkflow.
if (!map_collection_clone.any{ it.feature_type == 'gex' }) { map_collection_clone.add( [id: sample_id, feature_type: 'gex' , gex: empty_file, options:[:] ] ) }
if (!map_collection_clone.any{ it.feature_type == 'vdj' }) { map_collection_clone.add( [id: sample_id, feature_type: 'vdj' , vdj: empty_file, options:[:] ] ) }
if (!map_collection_clone.any{ it.feature_type == 'ab' }) { map_collection_clone.add( [id: sample_id, feature_type: 'ab' , ab: empty_file, options:[:] ] ) }
if (!map_collection_clone.any{ it.feature_type == 'beam' }) { map_collection_clone.add( [id: sample_id, feature_type: 'beam' , beam: empty_file, options:[:] ] ) } // currently not implemented, the input samplesheet checking will not allow it.
if (!map_collection_clone.any{ it.feature_type == 'crispr' }) { map_collection_clone.add( [id: sample_id, feature_type: 'crispr', crispr: empty_file, options:[:] ] ) }
if (!map_collection_clone.any{ it.feature_type == 'cmo' }) { map_collection_clone.add( [id: sample_id, feature_type: 'cmo' , cmo: empty_file, options:[:] ] ) }
if (!map_collection_clone.any{ m -> m.feature_type == 'gex' }) { map_collection_clone.add( [id: sample_id, feature_type: 'gex' , gex: empty_file, options:[:] ] ) }
if (!map_collection_clone.any{ m -> m.feature_type == 'vdj' }) { map_collection_clone.add( [id: sample_id, feature_type: 'vdj' , vdj: empty_file, options:[:] ] ) }
if (!map_collection_clone.any{ m -> m.feature_type == 'ab' }) { map_collection_clone.add( [id: sample_id, feature_type: 'ab' , ab: empty_file, options:[:] ] ) }
if (!map_collection_clone.any{ m -> m.feature_type == 'beam' }) { map_collection_clone.add( [id: sample_id, feature_type: 'beam' , beam: empty_file, options:[:] ] ) } // currently not implemented, the input samplesheet checking will not allow it.
if (!map_collection_clone.any{ m -> m.feature_type == 'crispr' }) { map_collection_clone.add( [id: sample_id, feature_type: 'crispr', crispr: empty_file, options:[:] ] ) }
if (!map_collection_clone.any{ m -> m.feature_type == 'cmo' }) { map_collection_clone.add( [id: sample_id, feature_type: 'cmo' , cmo: empty_file, options:[:] ] ) }

// return final map
map_collection_clone
Expand Down
Loading