在 Snakemake 中丢弃部分文件名:"Wildcards in input files cannot be determined from output files"

Discard part of filename in Snakemake: "Wildcards in input files cannot be determined from output files"

我 运行 遇到了 Snakemake 的 WildcardError: Wildcards in input files cannot be determined from output files 问题。问题是我不想保留输入文件名的可变部分。例如,假设我有这些文件。

$ mkdir input
$ touch input/a-foo.txt
$ touch input/b-wsdfg.txt
$ touch input/c-3523.txt

我有一个像这样的 Snakemake 文件:

subjects = ['a', 'b', 'c']

result_pattern = "output/{kind}.txt"

rule all:
    input:
        expand(result_pattern, kind=subjects)

rule step1:
    input:
        "input/{kind}-{fluff}.txt"
    output:
        "output/{kind}.txt"
    shell:
        """
        cp {input} {output}
        """

我希望输出的文件名只包含我感兴趣的部分。我明白输入中的每个通配符都需要在输出中对应一个通配符的原理。那么我想要做的是一种反模式吗?例如,我假设可能有两个文件 input/a-foo.txtinput/a-bar.txt,它们会互相覆盖。我应该在输入 snakemake 之前重命名我的输入文件吗?

I want the output file names to just have the part I'm interested in [...]. I suppose there could be two files input/a-foo.txt and input/a-bar.txt, and they would overwrite each other.

在我看来,您需要决定如何解决此类冲突。如果输入文件是:

input/a-bar.txt
input/a-foo.txt    <- Note duplicate {a}
input/b-wsdfg.txt
input/c-3523.txt

您希望如何命名输出文件并根据什么标准命名?答案与 snakemake 无关,但根据您的情况,您可以在 Snakefile 中包含 python 代码来自动处理此类冲突。

基本上,一旦做出此类决定,您就可以着手解决问题。


But suppose there are no file name conflicts, it seems like the wildcard system doesn't handle cases where you want to remove some variable fluff from a filename

可以使用 python 的 glob 模式处理可变部分:

import glob
...
rule step1:
    input:
        glob.glob("input/{kind}-*.txt")
    output:
        "output/{kind}.txt"
    shell:
        """
        cp {input} {output}
        """

您甚至可以更详细地使用专用函数来匹配给定 {kind} 通配符的文件:

def get_kind_files(wc):
    ff = glob.glob("input/%s-*.txt" % wc.kind)
    if len(ff) != 1:
        raise Exception('Exepected exactly 1 file for kind "%s"' % wc.kind)
    # Possibly more checks tha you got the right file
    return ff

rule step1:
    input:
        get_kind_files,
    output:
        "output/{kind}.txt"
    shell:
        """
        cp {input} {output}
        """