繁体   English   中英

snakemake - 如何根据先前生成可变数量文件的规则制作输入文件列表

[英]snakemake - how to make a list of input files based on a previous rule that produces variable number of files

比如说,我从一堆这样的文件开始:

group_1_in.txt, group_2_in.txt, group_3_in.txt

我使用生成如下所示目录结构的规则处理它们。

rule process_group_files:
    input: 'group_{num}_in.txt'
    output: directory('group_{num}')
    shell: "some_command {input} {output}'

## directory structure produced: 
group_1
    sample1_content.txt
    sample2_content.txt
    sample3_content.txt
group_2
    sample2_content.txt
    sample3_content.txt
    sample4_content.txt
group_3
    sample1_content.txt
    sample2_content.txt
    sample5_content.txt 

然后,我有规则处理它们以按样本聚合文件:

rule aggregate_by_sample:
    input: expand('{group}/{sample}_content.txt')
    output: '{sample}_allcontent.txt'
    shell: "cat {input} | some_command > {output}"

我希望这条规则的输入是:

group_1/sample1_content.txt, group_3/sample1_content.txt
group_1/sample2_content.txt, group_2/sample2_content.txt, group_3/sample2_content.txt
group_1/sample3_content.txt, group_2/sample3_content.txt
group_2/sample4_content.txt 
group_3/sample5_content.txt

并生成以下 output 文件:

sample1_allcontent.txt
sample2_allcontent.txt
sample3_allcontent.txt
sample4_allcontent.txt
sample5_allcontent.txt

此时,我想使用这些 output 文件。 所以,这个规则可以是这样的:

rule process_by_sample:
    input: <list of all sample_allcontent files>
    output: final_output.txt 
    shell: "cat {input} | some_other_command > {output}"

我的问题是:我如何告诉 snakemake 等到它处理完aggregate_by_sample规则中的所有文件,然后将那组 output 文件用于规则process_by_sample 我通过将aggregate_by_sample设置为检查点来探索检查点的想法,但我应该使用“目录”作为 output,因为我不知道将生成多少个output文件。 但我不能那样做,因为我的 output 文件名使用通配符,而 snakemake 抱怨Wildcards in input files cannot be determined from output files

编辑——在看到@troy-comi 的回答后,我意识到我把问题简单化了。 我更新了我的问题以包含第一条规则process_group_files 在管道开始时,我只知道我有多少个组以及“数字”通配符列表是什么。

由于文件已经存在,您可以使用 glob_wildcards 获取文件系统上组/样本的列表。 使用它,您可以通过更多处理来构建您的输入文件。

这是我的(未经测试的)想法:

wc =  glob_wildcards('{group}/{sample}_content.txt')
samples_to_group = {}
for samp, group in zip(wc.group, wc.sample):
    if samp not in samples_to_group:
        samples_to_group[samp] = []
    samples_to_group.append(group)

# now samples_to_group is a map of which groups are present for each sample

rule all:
    input: "final_output.txt"

rule aggregate_by_sample:
    input: expand('{group}/{sample}_content.txt', 
                  group=samples_to_group[wildcards.sample],
                  allow_missing=True)
    output: '{sample}_allcontent.txt'
    shell: "cat {input} | some_command > {output}"

rule process_by_sample:
    input: expand('{sample}_allcontent.txt', sample=samples_to_group.keys())
    output: final_output.txt 
    shell: "cat {input} | some_other_command > {output}"

如果另一个规则正在生成您必须使用检查点的文件。

-- 编辑以回答精致的问题 --

如果你事先知道样本,我只能让它工作,不需要组样本映射,只是你总共有 5 个样本......

使用以下文件设置目录:

$ tail data/group_*.txt
==> data/group_1.txt <==
1
2
3

==> data/group_2.txt <==
2
3
4

==> data/group_3.txt <==
1
2
5

然后是一个 Snakefile

wildcard_constraints:
    num="\d+"

groups = glob_wildcards('data/group_{num}.txt').num
samples = range(1, 6)

rule all:
    input: "final_output.txt"

checkpoint process_group_files:
    input: 'data/group_{num}.txt'
    output: directory('data/group_{num}')
    shell:
        'mkdir {output} \n'
        'for line in $(cat {input}) ; do echo "$line {input}" '
            '> {output}/${{line}}_content.txt ; '
        'done \n'
        'sleep 1'

def aggregate_input(wildcards):
    for num in groups:
        checkpoints.process_group_files.get(num=num).output

    grps = glob_wildcards(f'data/group_{{group}}/{wildcards.sample}_content.txt').group
    return expand('data/group_{group}/{sample}_content.txt',
            group=grps,
            sample=wildcards.sample)


rule aggregate_by_sample:
    input: aggregate_input
    output: 'data/agg/{sample}_allcontent.txt'
    shell: 'cat {input} > {output}'

rule process_by_sample:
    input: expand('data/agg/{sample}_allcontent.txt', sample=samples)
    output: 'final_output.txt'
    shell: 'cat {input} > {output}'

将给出最终的 output:

$ cat final_output.txt
1 data/group_1.txt
1 data/group_3.txt
2 data/group_1.txt
2 data/group_2.txt
2 data/group_3.txt
3 data/group_1.txt
3 data/group_2.txt
4 data/group_2.txt
5 data/group_3.txt

“魔术”是使用 for 循环调用检查点,这是您需要的锁定。 同样,它需要事先了解样本。 您可以尝试第二层检查点,但这通常会失败。 我还记得其他人在 for 循环中遇到检查点问题,因此它可能会在非玩具示例中中断。 顺便说一句,这是 snakemake 5.10

老实说,它最终可能更容易分成两个工作流程( snakemake -s Snakefile1 && snakemake -s Snakefile2 )!

祝你好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM