Nextflow输入如何在元组中声明元组

3

我正在使用Nextflow工作流程,在某个阶段使用groupTuple()方法根据样本ID对一系列文件进行分组,最终生成如下通道:

[sample_id, [file_A, file_B, ... , file_N]]
[sample_id, [file_A, file_B, ... , file_N]]
...
[sample_id, [file_A, file_B, ... , file_N]]

请注意,这是与 .fromFilePairs() 相同的通道结构。
我想以这种方式在进程中使用这些通道项,即对于每个条目,该进程从第一个字段中读取 sample_id,并一次性从内部元组读取所有文件
Nextflow 文档对此有点晦涩难懂,很难找到如何在通道中声明此类型的输入,因此我想在 Stack Overflow 上创建一个问题,然后为任何寻找答案的人自己回答。
如何在 nextflow 进程的 input 部分中声明内部元组?
3个回答

2

path 限定符(以前是 file 限定符)可用于将单个(文件)值 多个(文件)值的集合暂存到进程执行目录中。文档中多个输入文件一节底部的注释还提到:

文件输入 一节介绍的常规文件输入结构也同样适用于多个文件的集合。


这意味着,您可以使用一个脚本变量,例如:
input:
tuple val(sample_id), path(my_files)

在这种情况下,变量将保存文件列表(保留原始文件名)。您可以直接使用它来引用列表中的所有文件,或者使用方括号(切片)表示法访问特定(文件)元素(如果需要)。
这是您大多数时候想要的语法。但是,如果您需要可预测的文件名或者需要处理具有相同文件名的文件,则可能需要不同的方法:

或者,您可以指定一个目标文件名,例如:

input:
tuple val(sample_id), path('my_file')

如果进程接收到单个文件,则该文件将使用目标文件名进行分段。但是,当进程接收到一组文件时,文件名将附加一个表示其在列表中序数位置的数字后缀。例如:

process test {

    tag { sample_id }

    debug true
    stageInMode 'rellink'

    input:
    tuple val(sample_id), path('fastq')

    """
    echo "${sample_id}:"
    ls -g --time-style=+"" fastq*
    """
}

workflow {

    readgroups = Channel.fromFilePairs( '*_{1,2}.fastq' )
    
    test( readgroups )
}

结果:

$ touch {foo,bar,baz}_{1,2}.fastq
$ nextflow run . 
N E X T F L O W  ~  version 22.04.4
Launching `./main.nf` [scruffy_caravaggio] DSL2 - revision: 87a80d6d50
executor >  local (3)
[65/66f860] process > test (bar) [100%] 3 of 3 ✔
baz:
lrwxrwxrwx 1 users 20  fastq1 -> ../../../baz_1.fastq
lrwxrwxrwx 1 users 20  fastq2 -> ../../../baz_2.fastq

foo:
lrwxrwxrwx 1 users 20  fastq1 -> ../../../foo_1.fastq
lrwxrwxrwx 1 users 20  fastq2 -> ../../../foo_2.fastq

bar:
lrwxrwxrwx 1 users 20  fastq1 -> ../../../bar_1.fastq
lrwxrwxrwx 1 users 20  fastq2 -> ../../../bar_2.fastq


请注意,可以使用通配符*?来控制分阶段文件的名称。请参见上面的链接,了解表格显示如何根据输入集合的基数替换通配符的详细信息。

在将这些文件捕获到变量path(my_files)之后,如何对它们进行迭代?在这种情况下:[file_A, file_B, ... , file_N]按照相同的顺序进行迭代。 - Death Metal
1
@DeathMetal 这取决于您对集合的具体操作。但是,如果您想要在某些转换(使用闭包指定)后获取集合,可以使用 collect - Steve

1
在上面的示例中,我的内部元组仅包含一种类型(文件)。因此,我可以将整个元组的第二项(即内部元组)作为单个输入项传递到file()限定符下。就像这样:
input:
tuple \
val(sample_id), \
file(inner_tuple) \
from Input_channel

这将确保元组内容逐个读取为文件,就像在通道上执行.collect()一样,以便所有文件都将在下一个流程的临时目录中可用。


1
仅使用脚本变量只能解决问题的一半。如果需要,您还可以使用目标文件名和 *? 通配符来重写输入文件名。常规文件输入结构对于文件集合也是有效的。 - Steve

1
问题是如何确定sample_id,但如果它们只是不同的文件扩展名,您可以尝试使用以下代码:
all_files = Channel.fromPath("/path/to/your/files/*")
all_files.map { it -> [it.simpleName, it] }
         .groupTuple()
         .set { grouped_files }


it -> [it.simpleName, it] 这段代码是什么意思? - Death Metal
嗨。显然我误解了OP的意思。我以为他想知道如何创建这个结构,而实际上他想知道如何处理它。无论如何:该行代码通过将“simpleName”添加到索引0,并在索引1中包含文件对象,从通道的每个文件元素创建一个元组。 - Patrick H.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接