【发布时间】:2018-08-25 21:43:54
【问题描述】:
我不知道如何用 Snakemake 做到这一点。
首先,说我的“全部”规则是:
rule all:
input: "SA.txt", "SA_T1.txt", "SA_T2.txt",
"SB.txt", "SB_T1.txt", "SB_T2.txt", "SB_T3.txt"
注意SA 有两个_T# 文件,而SB 有三个这样的文件,这是其中的关键元素。
现在我想写一个这样的规则来生成这些文件:
rule X:
output: N="S{X}.txt", T="S{X}_T{Y}.txt"
(etc.)
但 SnakeMake 要求两个输出模板具有相同的通配符,而这些模板没有。此外,即使 SnakeMake 可以处理多个通配符,它也可能希望找到与 S{X}_T{Y}.txt 模板匹配的单个文件名,但我希望它匹配 {X} 与第一个模板的 {X} 匹配的所有文件,即我希望output.T 是一个列表,而不是单个文件。所以看起来这样做的方法是:
def myExpand(T, wildcards):
T = T.replace("{X}", wildcards.X)
T = [T.replace("{Y}", S) for S in theXYs[wildcards.X]]
return T
rule X:
output: N="S{X}.txt", T=lambda wildcards: myExpand("S{X}_T{Y}.txt", wildcards)
(etc.)
但我不能这样做,因为 lambda 函数不能用于输出部分。
我该怎么做?
在我看来,这支持在输出语句上支持 lambda 函数,提供一个通配符字典,其中填充来自输出语句的已解析部分的值。
响应 cmets 的添加:
需要通配符 Y 的值,因为其他规则对具有通配符 Y 的文件有输入。
我的规则知道 Y(和 X)的不同值,它需要处理从数据库读取到 Python 字典的数据。
X 有很多值,每个 X 值有 2 到 6 个 Y 值。我认为对 X 的每个值使用单独的规则是没有意义的。但是,我可能错了,因为我最近了解到可以将规则放入循环中,并创建多个规则。
有关工作流程的更多信息:我正在将来自一个人的多个肿瘤样本的体细胞变异 VCF 文件合并到一个 VCF 文件中,并这样做使得对于任何一个肿瘤中的每个被调用的变异,所有肿瘤都不会调用该变异分析以确定变体的读取深度,该变量包含在合并的 VCF 文件中。
整个过程涉及大约 14 个步骤,可能多达 14 条规则。我其实并不想使用 14 条规则,但更愿意在一条规则中完成所有操作。
但是,我现在认为解决方案确实是使用许多单独的规则。我之所以避免这样做,部分原因是因为有大量不必要的中间文件,但实际上,这些临时文件无论如何都存在,在单个大规则内。使用多个规则,我可以将它们标记为 temp(),这样 Snakemake 将在最后删除它们。
为了充实这个我认为是合法的讨论,让我们假设一个可能出现的简单情况。假设对于许多人中的每一个人,您有 N (>=2) 个肿瘤 VCF 文件,就像我一样,并且您想编写一个规则来生成 N+1 个输出文件,每个肿瘤一个输出文件加一个与此人关联的更多文件。使用通配符 X 表示人员 ID,使用通配符 Y 表示人员 X 中的肿瘤 ID。假设操作是将所有肿瘤 VCF 文件中存在的所有变体放入人员输出 VCF 文件中,并将所有其他变体放入相应的肿瘤输出文件中它们出现的肿瘤。 假设一个程序从 N 个输入文件生成所有 N+1 个文件。你是怎么写规则的?
你想要这个:
rule:
output: COMMON="{X}.common.vcf", INDIV="{X}.{Y}.indiv.vcf"
input: "{X}.{Y}.vcf"
shell: """
getCommonAndIndividualVariants --inputs {input} \
--common {output.COMMON} --indiv {output.INDIV}
"""
但这违反了输出通配符的规则。
我这样做的方式是使用两个规则,虽然不太令人满意,但很有效,第一个规则的输出模板具有更多通配符,第二个模板具有更少的通配符通配符,并让第二条规则创建临时输出文件,这些文件由第一条规则重命名为最终名称:
rule A:
output: "{X}.{Y}.indiv.vcf"
input: "{X}.common.vcf"
run: "for infile in {input}: os.system('mv '+infile+'.tmp'+' '+infile)"
rule B:
output: "{X}.common.vcf"
input: lambda wildcards: \
expand("{X}.{Y}.vcf", **wildcards, Y=getYfromDB(wildcards["X"]))
params: OUT=lambda wildcards: \
expand("{X}.{Y}.indiv.vcf.tmp", Y=getYfromDB(wildcards["X"]))
shell: """
getCommonAndIndividualVariants --inputs {input} \
--common {output} --indiv {params.OUT}
"""
【问题讨论】: