在snakemake运行期间动态减少输入文件集

时间:2017-03-17 07:55:52

标签: snakemake

这更像是关于snakemake功能的技术问题。我想知道是否可以在snakemake运行期间动态改变输入样本集。

我想这样做的原因如下:让我们假设一组样本关联的bam文件。第一个规则确定每个样本的质量(基于bam文件),即所有输入文件。 但是,根据指定的标准,只有一部分样本被认为是有效的,应该进一步处理。因此,只应对已批准的bam文件执行下一步(例如基因计数或其他内容),如下面的最小示例所示:

configfile: "config.yaml"

rule all:
   input: "results/gene_count.tsv"

rule a:
   input: expand( "data/{sample}.bam", sample=config['samples'])
   output: "results/list_of_qual_approved_samples.out"
   shell: '''command'''

rule b:
   input: expand( "data/{sample}.bam", sample=config['valid_samples'])
   output: "results/gene_count.tsv"
   shell: '''command'''

在此示例中,规则a将使用有效样本名称列表扩展配置文件,即使我相信知道这是不可能的。

当然,直接的解决方案是拥有两个不同的输入:1。)所有bam文件和2.)列出所有有效文件的文件。这将归结为在规则代码中进行样本选择。

rule alternative_b:
   input: 
      expand( "data/{sample}.bam", sample=config['samples']),
      "results/list_of_qual_approved_samples.out"
   output: "results/gene_count.tsv"
   shell: '''command'''

但是,您是否看到了设置规则的方法,以便可以实现第一个示例的行为?

非常感谢, 拉尔夫

3 个答案:

答案 0 :(得分:1)

我想我的回答可能很有趣。

起初我以为不可能这样做。因为Snakemake needs the final files在最后。因此,您不能在不知道开头的分离的情况下分离一组文件。

但后来我尝试使用动态功能。使用动态功能,您无需知道规则将创建的文件数量。

所以我编码了这个:

rule all:
   input: "results/gene_count.tsv"

rule a:
   input: expand( "data/{sample}.bam", sample=config['samples'])
   output: dynamic("data2/{foo}.bam")
   shell: 
     './bloup.sh "{input}"'

rule b:
   input: dynamic("data2/{foo}.bam")
   output: touch("results/gene_count.tsv")
   shell: '''command'''

与第一个示例一样,snakefile希望生成一个名为results/gene_count.ts的文件。

rule a从配置文件中获取所有样本。此规则执行选择要创建的文件的脚本。我有4 initial个文件(geneA,geneB,geneC,geneD)和only touches two作为第二个库中的输出(geneA和geneD文件)。 动态功能没有问题。

rule b获取rule a创建的所有动态文件。所以你只需要产生 results / gene_count.tsv 。我只是在示例中触及它。

以下是log of Snakemake以获取更多信息:

Provided cores: 1
Rules claiming more threads will be scaled down.
Job counts:
        count   jobs
        1       a
        1       all
        1       b
        3

rule a:
    input: data/geneA.bam, data/geneB.bam, data/geneC.bam, data/geneD.bam
    output: data2/{*}.bam (dynamic)

Subsequent jobs will be added dynamically depending on the output of this rule
./bloup.sh "data/geneA.bam data/geneB.bam data/geneC.bam data/geneD.bam"

Dynamically updating jobs
Updating job b.
1 of 3 steps (33%) done
rule b:
    input: data2/geneD.bam, data2/geneA.bam
    output: results/gene_count.tsv

command
Touching output file results/gene_count.tsv.

2 of 3 steps (67%) done

localrule all:
    input: results/gene_count.tsv

3 of 3 steps (100%) done

答案 1 :(得分:1)

另一种不使用“动态”的方法。

并不是您不知道要使用多少文件,而是仅使用您将要开始使用的文件的子集。由于您可以生成所有潜在文件的“samples.txt”列表,因此我假设您有一个坚定的起点。

我做了类似的事情,我有初始文件,我想处理有效性,(在我的情况下,我正在提高质量〜排序,索引等)。然后我想忽略除了生成的文件之外的所有内容。

为避免创建示例文件的辅助列表,我建议创建第二个数据目录(reBamDIR),data2(BamDIR)。在data2中,您对所有有效的文件进行符号链接。这样,Snake就可以在data2目录中处理所有内容。使管道更容易向下移动,管道可以停止依赖样本列表,它可以使用通配符处理所有内容(更容易编码)。这是可能的,因为我符号链接然后标准化名称。我列出了输出规则中的符号链接文件,因此Snakemake了解它们,然后它可以创建DAG。

`-- output
    |-- bam
    |   |-- Pfeiffer2.bam ->     /home/tboyarski/share/projects/tboyarski/gitRepo-LCR-BCCRC/Snakemake/buildArea/output/reBam/Pfeiffer2_realigned_sorted.bam
    |   `-- Pfeiffer2.bam.bai ->     /home/tboyarski/share/projects/tboyarski/gitRepo-LCR-    BCCRC/Snakemake/buildArea/output/reBam/Pfeiffer2_realigned_sorted.bam.bai
    |-- fastq
    |-- mPile
    |-- reBam
    |   |-- Pfeiffer2_realigned_sorted.bam
    |   `-- Pfeiffer2_realigned_sorted.bam.bai

在这种情况下,您需要的只是“验证器”中的返回值,以及响应它的条件运算符。

我认为你已经有了这个,因为你必须在验证步骤中使用条件。不要使用它将文件名写入txt文件,只需将文件符号链接到最终位置并继续。

我的原始数据在reBamDIR中。 我存储在BamDIR中的最终数据。 我只将管道中此阶段的文件符号链接到bamDIR。 reBamDIR中有其他文件,但我不希望我的其他管道看到它们,所以,我将它们过滤掉。

我不确定如何实施“验证器”和你的条件,因为我不知道你的情况,我还在学习。只是尝试提供替代观点//方法。

from time import gmtime, strftime

rule indexBAM:
    input:
        expand("{outputDIR}/{reBamDIR}/{{samples}}{fileTAG}.bam", outputDIR=config["outputDIR"], reBamDIR=config["reBamDIR"], fileTAG=config["fileTAG"])
    output:
        expand("{outputDIR}/{reBamDIR}/{{samples}}{fileTAG}.bam.bai", outputDIR=config["outputDIR"], reBamDIR=config["reBamDIR"], fileTAG=config["fileTAG"]),
        expand("{outputDIR}/{bamDIR}/{{samples}}.bam.bai", outputDIR=config["outputDIR"], bamDIR=config["bamDIR"]),
        expand("{outputDIR}/{bamDIR}/{{samples}}.bam", outputDIR=config["outputDIR"], bamDIR=config["bamDIR"])
    params:
        bamDIR=config["bamDIR"],
        outputDIR=config["outputDIR"],
        logNAME="indexBAM." + strftime("%Y-%m-%d.%H-%M-%S", gmtime())
    log:
        "log/" + config["reBamDIR"]
    shell:
        "samtools index {input} {output[0]} " \
        " 2> {log}/{params.logNAME}.stderr " \
        "&& ln -fs $(pwd)/{output[0]} $(pwd)/{params.outputDIR}/{params.bamDIR}/{wildcards.samples}.bam.bai " \
        "&& ln -fs $(pwd)/{input} $(pwd)/{params.outputDIR}/{params.bamDIR}/{wildcards.samples}.bam"

答案 2 :(得分:0)

**这不是你问题的答案,而是一个达到目标的建议。 **

我认为在管道运行期间修改yaml文件是不可能的 - 或者至少不是微不足道的。

就个人而言,当我运行snakemake工作流程时,我使用外部文件,我称之为#34;元数据"。它们包括一个配置文件,但也包含一个包含样本列表的标签文件(以及可能包含所述样本的其他信息)。配置文件包含一个参数,该参数是此文件的路径。

在这样的设置中,我建议您使用"规则a"输出包含所选样本的另一个选项卡文件,该文件的路径可以包含在配置文件中(即使它在启动工作流程时不存在)。规则b将该文件作为输入。

在你的情况下你可以:

config:
 samples: "/path/to/samples.tab"
 valid_samples: "/path/to/valid_samples.tab"

我不知道它是否有意义,因为它基于我自己的组织。我认为它很有用,因为它允许存储的信息不仅仅是样本名称,如果你有100个样本,它就更容易管理!