当两个不同的规则路径可以生成给定的输出时,snakemake可以避免歧义吗?

时间:2016-11-09 15:19:12

标签: python bioinformatics snakemake

初始工作流程

我有一个可以从配对端数据生成一些输出的snakefile。

在这个snakefile中,我有一条规则“安装”给定存储在配置文件(get_raw_data)中的信息的数据。

然后我有一条规则使用该数据生成工作流的其余部分所依赖的中间文件(run_tophat)。

以下是这些规则的输入和输出(OPJ代表os.path.join):

rule get_raw_data:
    output:
        OPJ(raw_data_dir, "{lib}_1.fastq.gz"),
        OPJ(raw_data_dir, "{lib}_2.fastq.gz"),

(稍后有关此规则的实施的详细信息)

rule run_tophat:
    input:
        transcriptome = OPJ(annot_dir, "dmel-all-r5.9.gff"),
        fq1 = OPJ(raw_data_dir, "{lib}_1.fastq.gz"),
        fq2 = OPJ(raw_data_dir, "{lib}_2.fastq.gz"),
    output:
        junctions = OPJ(output_dir, "{lib}", "junctions.bed"),
        bam = OPJ(output_dir, "{lib}", "accepted_hits.bam"),

并且(简化)我的主要规则是这样的:

rule all:
    input:
        expand(OPJ(output_dir, "{lib}", "junctions.bed"), lib=LIBS),

将工作流程扩展到单端数据

我现在必须在单端数据上运行我的工作流程。

我想避免最终输出具有不同的名称模式,具体取决于数据是单端还是配对端。

我可以轻松地制作上述两条规则的变体,这两条规则应该适用于单端数据(get_raw_data_single_endrun_tophat_single_end),其输入和输出如下:

rule get_raw_data_single_end:
    output:
        OPJ(raw_data_dir, "{lib}.fastq.gz")

rule run_tophat_single_end:
    input:
        transcriptome = OPJ(annot_dir, "dmel-all-r5.9.gff"),
        fq = OPJ(raw_data_dir, "{lib}.fastq.gz"),
    output:
        junctions = OPJ(output_dir, "{lib}", "junctions.bed"),
        bam = OPJ(output_dir, "{lib}", "accepted_hits.bam"),

如何为snakemake提供足够的信息来选择正确的规则路径?

配置文件包含有关lib通配符是否与以下方式与单端或配对端数据相关联的信息:库名称是lib2raw或{中的键{1}}字典(从配置文件中读取两个字典)。

我不希望相同的库名称成为两个词典中的键。因此,从某种意义上说,我是否希望执行工作流的单端或双端分支并不含糊。

lib2raw_single_endlib2data使用函数get_raw_data(使用这些词典)来确定要运行以“安装”数据的shell命令。

这是此函数的简化版本(实际的函数包含一个额外的分支,用于从SRR标识符生成数据命令):

get_raw_data_single_end

除了输出之外,两个def lib2data(wildcards): lib = wildcards.lib if lib in lib2raw: raw = lib2raw[lib] link_1 = "ln -s %s %s_1.fastq.gz" % (raw.format(mate="1"), lib) link_2 = "ln -s %s %s_2.fastq.gz" % (raw.format(mate="2"), lib) return "%s\n%s\n" % (link_1, link_2) elif lib in lib2raw_single_end: raw = lib2raw_single_end[lib] return "ln -s %s %s.fastq.gz\n" % (raw, lib) else: raise ValueError("Procedure to get raw data for %s unknown." % lib) 规则是相同的,并按以下方式工作:

get_raw_data*

给定的信息在规则输入和输出中没有编码,但只有在配置文件和函数中才能确定正确的规则路径吗?

似乎情况并非如此。实际上,我正在尝试测试我的新snakefile(添加了params: shell_command = lib2data, shell: """ ( cd {raw_data_dir} {params.shell_command} ) """ 规则),但是在执行*_single_end规则期间发生KeyError,而库是正在执行的规则与单端数据相关联。

如何实现所需的行为(能够使用配置中的信息选择正确分支的双分支工作流程)?

修改:get_raw_data是由KeyError

中的错误引起的

使用正确的字典获取与库名相关的数据后,我最终得到以下错误:

lib2data

编辑2:向AmbiguousRuleException: Rules run_tophat and run_tophat_single_end are ambiguous for the file tophat_junction_discovery_revision_supplement/HWT3/junctions.bed. Expected input files: run_tophat: ./HWT3_1.fastq.gz ./HWT3_2.fastq.gz Annotations/dmel-all-r5.9.gff run_tophat_single_end: ./HWT3.fastq.gz Annotations/dmel-all-r5.9.gff 规则

添加输入

在阅读this post on the snakemake mailing list后,我尝试在规则中添加一些输入以避免含糊不清。

get_raw_data*

这会产生 def lib2data_input(wildcards): lib = wildcards.lib if lib in lib2raw: raw = lib2raw[lib] return [raw.format(mate="1"), raw.format(mate="2")] elif lib in lib2raw_single_end: raw = lib2raw_single_end[lib] return [raw] else: raise ValueError("Procedure to get raw data for %s unknown." % lib) rule get_raw_data: input: lib2data_input # [same output, params and shell as before] # [same modification for the single-end case] 。奇怪的是,据报道丢失的文件确实存在。该诀窍应该有效吗?(无法重现这一点,现在这导致:)

MissingInputException

我指定“数据安装”规则输入的方式显然不足以引导snakemake遵循正确的规则。

2 个答案:

答案 0 :(得分:1)

我不知道它是否有帮助,但您可以使用函数来定义规则的输入。这样,您可以使用相同的规则来处理单端或双端数据,因为规则的输出是相同的......

def my_inputs(wildcards):
    data_type = config["data_type"]
    if (data_type == "pe"):
        input = ...
    elif (data_type == "se"):
        input = ...
    return input

rule my_rule:
    input: my_inputs
    ...

答案 1 :(得分:0)

由user1829905作为suggested,我曾尝试将get_raw_data*规则设为一,但由于此规则的输出变量而失败。

但是,我可以将run_tophat*规则合并为一个:它们具有相同的输出。

rule run_tophat:
    input:
        transcriptome = OPJ(annot_dir, "dmel-all-r5.9.gff"),
        fq = lib2fq,
    output:
        junctions = OPJ(output_dir, "{lib}", "junctions.bed"),
        bam = OPJ(output_dir, "{lib}", "accepted_hits.bam"),

我尝试了以下函数来生成此融合规则的输入:

def lib2fq(wildcards):
    lib = wildcards.lib
    if lib in lib2sr:
        return [OPJ(raw_data_dir, "{lib}_1.fastq.gz"), OPJ(raw_data_dir, "{lib}_2.fastq.gz")]
    elif lib in lib2raw:
        return [OPJ(raw_data_dir, "{lib}_1.fastq.gz"), OPJ(raw_data_dir, "{lib}_2.fastq.gz")]
    elif lib in lib2raw_single_end:
        return [OPJ(raw_data_dir, "{lib}.fastq.gz")]
    else:
        raise ValueError("Procedure to get raw data for %s unknown." % lib)

但是这次尝试失败了InputFunctionException

ValueError: Procedure to get raw data for {lib} unknown.

但是,根据第一个规则的输出明确定义第二个规则的输入可以解决问题。

def lib2fq(wildcards):
    lib = wildcards.lib
    if lib in lib2raw_single_end:
        return rules.get_raw_data_single_end.output
    else:
        return rules.get_raw_data.output

我不完全理解为什么会出现这种差异。