【问题标题】:Is the use of * allowed in Snakemake?Snakemake 中是否允许使用 *?
【发布时间】:2022-01-19 10:15:04
【问题描述】:

我需要连接在Snakefile 中使用通配符创建的某些目录中的某些文件。我尝试创建以下规则来连接这些目录中的所有文件:

# concatenate output per hmm
rule concatenate:
    input:
        output_{hmm}/* ,
    output: 
        output_{hmm}/cat_{hmm}.txt,
    params:
        cmd='cat'
    shell: 
        '{params.cmd} {input} > {output} '

它不起作用并产生以下错误:

"SyntaxError in line 62 of /scratch/data1/agalvez/domains/Snakefile_ecdf:
invalid syntax (Snakefile_ecdf, line 62)"

我不知道该规则有什么问题,我想* 的使用可能不够,但我想不出另一种方法来做我打算做的事情。

编辑: 这个问题可能缺少一些信息,所以我也会附上完整的 Snakefile:

ARCHIVE_FILE = 'output.tar.gz'

# a single output file
OUTPUT_FILE = 'output_{hmm}/{species}_{hmm}.out'

# a single input file
INPUT_FILE = 'proteins/{species}.fasta'

# a single hmm file
HMM_FILE = 'hmm/{hmm}.hmm'

# a single cat file
CAT_FILE = 'cat/cat_{hmm}.txt'

# Build the list of input files.
INP = glob_wildcards(INPUT_FILE).species

# Build the list of hmm files.
HMM = glob_wildcards(HMM_FILE).hmm

# The list of all output files
OUT = expand(OUTPUT_FILE, species=INP, hmm=HMM)

# The list of all CAT files
CAT = expand(CAT_FILE, hmm=HMM)

# pseudo-rule that tries to build everything.
# Just add all the final outputs that you want built.
rule all:
    input: ARCHIVE_FILE

# hmmsearch
rule hmm:
    input:
        species=INPUT_FILE ,
        hmm=HMM_FILE
    output: 
        OUTPUT_FILE,
    params:
        cmd='hmmsearch --noali -E 99 --tblout'
    shell: 
        '{params.cmd} {output} {input.hmm} {input.species} '

# concatenate output per hmm
from glob import glob

rule concatenate:
    input:
        files = glob("output_{hmm}/*") ,
    output: 
        CAT_FILE,
    params:
        cmd='cat'
    shell: 
        '{params.cmd} {input.files} {output} '

# create an archive with all results
rule create_archive:
    input: OUT, CAT,
    output: ARCHIVE_FILE
    shell: 'tar -czvf {output} {input}'

【问题讨论】:

    标签: python shell glob snakemake


    【解决方案1】:

    出于测试目的,让我们创建一个示例文件集(使用虚拟文件进行操作以确保工作流正常工作)。在终端,我跑了:

    mkdir proteins && touch proteins/1.fasta proteins/2.fasta
    mkdir hmm && touch hmm/A.hmm hmm/B.hmm
    

    现在,您的工作流程基本正确,除了规则 concatenate。此规则的输入由规则hmm 创建,此规则的输出特定于hmm 的通配符值。因此,您对给定hmm 的所有species 值感兴趣。获得它的方法是使用expand,但将hmm保持为通配符格式,使用expand(OUTPUT_FILE, species=INP, hmm="{hmm}")

    rule concatenate:
        input:
            expand(OUTPUT_FILE, species=INP, hmm="{hmm}"),
        output:
            CAT_FILE,
        params:
            cmd="cat",
        shell:
            "{params.cmd} {input} > {output} "
    

    在下面的工作流程中,我修改了规则hmm 以进行快速测试运行,因此完整的工作流程将如下所示:

    ARCHIVE_FILE = "output.tar.gz"
    
    # a single output file
    OUTPUT_FILE = "output_{hmm}/{species}_{hmm}.out"
    
    # a single input file
    INPUT_FILE = "proteins/{species}.fasta"
    
    # a single hmm file
    HMM_FILE = "hmm/{hmm}.hmm"
    
    # a single cat file
    CAT_FILE = "cat/cat_{hmm}.txt"
    
    # Build the list of input files.
    INP = glob_wildcards(INPUT_FILE).species
    
    # Build the list of hmm files.
    HMM = glob_wildcards(HMM_FILE).hmm
    
    # The list of all output files
    OUT = expand(OUTPUT_FILE, species=INP, hmm=HMM)
    
    # The list of all CAT files
    CAT = expand(CAT_FILE, hmm=HMM)
    
    
    # pseudo-rule that tries to build everything.
    # Just add all the final outputs that you want built.
    rule all:
        input:
            ARCHIVE_FILE,
    
    
    # hmmsearch
    rule hmm:
        input:
            species=INPUT_FILE,
            hmm=HMM_FILE,
        output:
            touch(OUTPUT_FILE),
        params:
            #        cmd='hmmsearch --noali -E 99 --tblout'
            cmd="echo",
        shell:
            "{params.cmd} {output} {input.hmm} {input.species} "
    
    
    rule concatenate:
        input:
            expand(OUTPUT_FILE, species=INP, hmm="{hmm}"),
        output:
            CAT_FILE,
        params:
            cmd="cat",
        shell:
            "{params.cmd} {input} > {output} "
    
    
    # create an archive with all results
    rule create_archive:
        input:
            CAT,
        output:
            ARCHIVE_FILE,
        shell:
            "tar -czvf {output} {input}"
    

    【讨论】:

    • 感谢您的回复。我尝试复制您的“规则连接”,但它仍然给我错误消息“无事可做(所有请求的文件都存在且是最新的)。”我通过“触摸” hmm 输入文件来解决它,但我仍然不明白为什么当它们不存在时它没有生成 cat 文件。感谢您的帮助。
    • 我认为你最初的 cat 命令没有包含 ">" 符号,这是保存输出文件所必需的。
    【解决方案2】:

    Snakefile 是 Python 代码,因此所有文件引用都应该是字符串/类似路径的对象(或返回此类对象的变量/函数)。但是,一般输入文件应该是特定文件,而不是目录。

    有几种方法可以解决这个问题,其中之一是在 python 中调用 glob 文件并显式传递它们:

    from glob import glob
    
    rule concatenate:
        input:
            files = glob("output_{hmm}/*") ,
        output: 
            combined = "output_{hmm}/cat_{hmm}.txt",
        params:
            cmd='cat'
        shell: 
            '{params.cmd} {input.files} {output.combined} '
    

    请注意,就目前而言,此规则会在重复运行时导致问题,因为连接文件 ("output_{hmm}/cat_{hmm}.txt") 将在重复运行时被覆盖。

    【讨论】:

    • 首先感谢您的快速响应和帮助。如果我创建一个新目录来存储连接的文件,它会解决问题吗?因此,我可以使用“concatenated_files/cat_{hmm}.txt”,而不是使用“output_{hmm]/cat_{hmm}.txt”作为我的输出选项。这行得通吗?
    • 不客气,是的,这样行。
    • 抱歉打扰了,再次感谢。我尝试了您的建议,但 Snakemake 告诉我没有什么可做的,好像文件已经存在(但它们不存在)。 “无事可做(所有请求的文件都存在并且是最新的)。”。
    • 有趣的是,“output_{hmm}/*”中的文件是由另一个规则生成的吗?如果是这样,则需要采用不同的方法。
    • 是的,他们是!很抱歉之前没有澄清这一点。我将编辑原始问题以显示 Snakefile 的完整内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 2012-01-24
    • 2012-08-04
    • 2010-09-21
    • 1970-01-01
    相关资源
    最近更新 更多