【问题标题】:Multiple inputs and outputs in a single rule Snakemake file单个规则 Snakemake 文件中的多个输入和输出
【发布时间】:2017-06-15 07:23:58
【问题描述】:

我正在开始使用 Snakemake,我有一个非常基本的问题,我在 snakemake 教程中找不到答案。

我想创建一个单一的规则蛇文件来一个一个地下载linux中的多个文件。 输出中不能使用expand,因为文件需要一个一个下载,不能使用通配符,因为它是目标规则。

我想到的唯一方法是这样的东西不能正常工作。我不知道如何使用 {output} 将下载的项目发送到具有特定名称的特定目录,例如“downloaded_files.dwn”,以便在以后的步骤中使用:

links=[link1,link2,link3,....]
rule download:    
output: 
    "outdir/{downloaded_file}.dwn"
params: 
    shellCallFile='callscript',
run: 
    callString=''
    for item in links:
        callString+='wget str(item) -O '+{output}+'\n'
    call('echo "' + callString + '\n" >> ' + params.shellCallFile, shell=True)
    call(callString, shell=True)

我很感激任何关于如何解决这个问题的提示,以及我不太了解蛇的哪一部分。

【问题讨论】:

  • 如果您不使用-j 选项运行snakemake,则在给定时间只会运行一个规则实例。是否需要按精确的顺序下载文件?
  • 另外,通常使用第一个只有输入的all 规则,您可以使用扩展。这将推动工作流程的其余部分。
  • 链接名称中是否存在可用于决定下载文件名称的模式?请记住,Snakemake 旨在使用文件名的规律性。
  • 您显示的规则有一个问题,即output 对应于单个文件名,但您的callString 将包含对wget 的多次调用,并且始终使用相同的-O 参数。此外,{downloaded_file} 部分将使 Snakemake 有一个名为“downloaded_file”的通配符,如果没有进一步的信息,将无法确定其值。您可能应该首先尝试简化您的规则。如果你只有一个链接,你会怎么做?
  • 还有一个观察结果:您的params.shellCallFile 可能应该是log 而不是params。参见例如stackoverflow.com/a/42839257/1878788

标签: python-3.x snakemake


【解决方案1】:

这是一个可以帮助您解决问题的注释示例:

# Create some way of associating output files with links
# The output file names will be built from the keys: "chain_{key}.gz"
# One could probably directly use output file names as keys 
links = {
    "1" : "http://hgdownload.cse.ucsc.edu/goldenPath/hg38/liftOver/hg38ToAptMan1.over.chain.gz",
    "2" : "http://hgdownload.cse.ucsc.edu/goldenPath/hg38/liftOver/hg38ToAquChr2.over.chain.gz",
    "3" : "http://hgdownload.cse.ucsc.edu/goldenPath/hg38/liftOver/hg38ToBisBis1.over.chain.gz"}


rule download:
    output:
        # We inform snakemake that this rule will generate
        # the following list of files:
        # ["outdir/chain_1.gz", "outdir/chain_2.gz", "outdir/chain_3.gz"]
        # Note that we don't need to use {output} in the "run" or "shell" part.
        # This list will be used if we later add rules
        # that use the files generated by the present rule.
        expand("outdir/chain_{n}.gz", n=links.keys())
    run:
        # The sort is there to ensure the files are in the 1, 2, 3 order.
        # We could use an OrderedDict if we wanted an arbitrary order.
        for link_num in sorted(links.keys()):
            shell("wget {link} -O outdir/chain_{n}.gz".format(link=links[link_num], n=link_num))

这是另一种做法,对下载的文件使用任意名称并使用output(虽然有点人为):

links = [
    ("foo_chain.gz", "http://hgdownload.cse.ucsc.edu/goldenPath/hg38/liftOver/hg38ToAptMan1.over.chain.gz"),
    ("bar_chain.gz", "http://hgdownload.cse.ucsc.edu/goldenPath/hg38/liftOver/hg38ToAquChr2.over.chain.gz"),
    ("baz_chain.gz", "http://hgdownload.cse.ucsc.edu/goldenPath/hg38/liftOver/hg38ToBisBis1.over.chain.gz")]


rule download:
    output:
        # We inform snakemake that this rule will generate
        # the following list of files:
        # ["outdir/foo_chain.gz", "outdir/bar_chain.gz", "outdir/baz_chain.gz"]
        ["outdir/{f}".format(f=filename) for (filename, _) in links]
    run:
        for i in range(len(links)):
            # output is a list, so we can access its items by index
            shell("wget {link} -O {chain_file}".format(
                link=links[i][1], chain_file=output[i]))
        # using a direct loop over the pairs (filename, link)
        # could be considered "cleaner"
        # for (filename, link) in links:
        #     shell("wget {link} -0 outdir/{filename}".format(
        #         link=link, filename=filename))

使用snakemake -j 3可以并行完成三个下载的示例:

# To use os.path.join,
# which is more robust than manually writing the separator.
import os

# Association between output files and source links
links = {
    "foo_chain.gz" : "http://hgdownload.cse.ucsc.edu/goldenPath/hg38/liftOver/hg38ToAptMan1.over.chain.gz",
    "bar_chain.gz" : "http://hgdownload.cse.ucsc.edu/goldenPath/hg38/liftOver/hg38ToAquChr2.over.chain.gz",
    "baz_chain.gz" : "http://hgdownload.cse.ucsc.edu/goldenPath/hg38/liftOver/hg38ToBisBis1.over.chain.gz"}


# Make this association accessible via a function of wildcards
def chainfile2link(wildcards):
    return links[wildcards.chainfile]


# First rule will drive the rest of the workflow
rule all:
    input:
        # expand generates the list of the final files we want
        expand(os.path.join("outdir", "{chainfile}"), chainfile=links.keys())


rule download:
    output:
        # We inform snakemake what this rule will generate
        os.path.join("outdir", "{chainfile}")
    params:
        # using a function of wildcards in params
        link = chainfile2link,
    shell:
        """
        wget {params.link} -O {output}
        """

【讨论】:

  • 感谢 bli 的出色解决方案。再问一个问题。是否也可以修改此规则以并行下载链接?
  • 要并行运行,您可能可以在all 规则的input 中移动expand,从run 部分中删除for 循环,然后使用@987654331 @。 all 规则将导致 download 规则为每个想要的文件运行一次。改天我会添加一个示例,但您可以同时尝试。
  • @user3015703 我为并行下载添加了一个示例。
猜你喜欢
  • 1970-01-01
  • 2018-08-07
  • 1970-01-01
  • 2021-12-29
  • 2021-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
相关资源
最近更新 更多