有没有办法在 .yaml 文件中定义一个 snakemake 配置字符串,以便它可以包含 {通配符} 和 {param} 值,当该字符串在 shell 命令中使用时,{
例如,假设您希望配置字符串定义要作为参数传递给程序的字符串的格式:
RG: "ID:{ID} REP:{REP}">
其中上述内容在 .yaml 文件中,ID 和 REP 是通配符,shell 命令会将扩展的字符串作为参数传递给程序。
让我试着对这个问题提供一个简短的答案:
在 Snakemake 中,您可以为参数提供函数,这些参数将通配符作为参数。在这些函数中,您可以执行任何 python 代码,包括格式化配置值的格式语句,例如
configfile: "config.yaml"
rule:
output:
"plots/myplot.{mywildcard}.pdf"
params:
myparam=lambda wildcards: config["mykey"].format(**wildcards)
shell:
...
如您所见,您可以使用 python 解包运算符和str.format
方法来替换配置文件中的值。这假设config["mykey"]
生成一个包含与上述相同通配符的字符串,例如"foo{mywildcard}bar"
.
是的,使用 params lambda 函数:
MACBOOK> cat paramsArgs.yaml
A: "Hello world"
B: "Message: {config[A]} ID: {wildcards.ID} REP: {wildcards.REP}"
MACBOOK> cat paramsArgs
configfile: "paramsArgs.yaml"
rule all:
input: "ID2307_REP12.txt"
def paramFunc(key, wildcards, config):
return config[key].format(wildcards=wildcards, config=config)
rule:
output: "ID{ID}_REP{REP}.txt"
params: A=config["A"], B=lambda wildcards: paramFunc("B", wildcards, config)
shell:
"""
echo 'A is {params.A}' > {output}
echo 'B is {params.B}' >> {output}
"""
MACBOOK> snakemake -s paramsArgs
Provided cores: 1
Rules claiming more threads will be scaled down.
Job counts:
count jobs
1 2
1 all
2
rule 2:
output: ID2307_REP12.txt
jobid: 1
wildcards: REP=12, ID=2307
Finished job 1.
1 of 2 steps (50%) done
localrule all:
input: ID2307_REP12.txt
jobid: 0
Finished job 0.
2 of 2 steps (100%) done
MACBOOK> cat ID2307_REP12.txt
A is Hello world
B is Message: Hello world ID: 2307 REP: 12
这是一个参数函数,可让您在配置字符串中扩展来自几个不同 snakemake 源的值:
def paramFunc(wildcards, input, output, threads, resources, config,
global_cfg, this_cfg, S):
return S.format(wildcards=wildcards, input=input, output=output,
threads=threads, resources=resources, config=config,
global_cfg=global_cfg, this_cfg=this_cfg)
下面是一个如何从 Snakemake params: 部分中调用 paramFunc(( 的示例,以扩展配置参数 config["XYZ"] 的值并将其分配给名为 "text" 的参数,然后在 shell 命令中展开该 "text" 参数:
params:
text=lambda wildcards, input, output, threads, resources:
paramFunc(wildcards, input, output, threads, resources, config,
global_cfg, my_local_cfg, config["XYZ"])
shell: "echo 'text is {params.text}'"
请注意,paramFunc(( 的最后一个参数是您想要的参数值 要扩展,在这种情况下,配置 ["XYZ"]。 其他参数都是包含该参数值可能引用的值的字典。
您可能已经定义了这样的 config["XYZ"],例如,在 .yaml 文件中:
ABC: "Hello world"
XYZ: "ABC is {config[ABC]}"
但是,字符串 XYZ 不限于扩展同一文件中定义的值(此处扩展了 ABC(,但您可以使用其他"{}"构造来访问在其他位置定义的其他值:
Defined in Use this construct in param
---------- ---------------------------
"config" dictionary "{config[<name>]}"
wildcards used in the output filename "{wildcards[<name>]}"
input filename(s) "{input}" or "{input[NAME]}" or "{input[#]}"
output filename(s) "{output}" or "{output[NAME]}" or "{output[#]}"
threads "{threads}"
resources "{resources[<name>]}"
"global_cfg" global config dictionary "{global_cfg[<name>]}"
"my_local_cfg" module config dictionary "{this_cfg[<name>]}"
值"global_cfg"和"my_local_cfg"是两个特殊的字典,可以添加它们来帮助模块化蛇文件。
对于"global_cfg",这个想法是你可能想要一个 snakefile-global 定义的字典。 在您的主蛇文件中,执行以下操作:
include: "global_cfg.py"
在文件global_cfg.py中,放置全局定义:
global_cfg = {
"DATA_DIR" : "ProjData",
"PROJ_DESC" : "Mint Sequencing"
}
然后,您可以在参数字符串中引用这些值,例如:
"{global_cfg[DATADIR]}"
(字符串必须通过调用 paramFunc((在 params: 部分中扩展(
对于"my_local_cfg",这个想法是您可能希望将每个 snakefile 规则放在一个单独的文件中,并将该规则的参数也定义在一个单独的文件中,因此每个规则都有一个规则文件和一个参数文件。 在主蛇文件中:
(include paramFunc() definition above)
include: "myrule.snake"
rule all:
input: "myrule.txt"
在myrule.snake中:
include: "myrule.py"
myrule.py 放置 myrule 模块的配置设置:
myrule_cfg = {
"SPD" : 125,
"DIST" : 98,
"MSG" : "Param settings: Speed={this_cfg[SPD]} Dist={this_cfg[DIST]}"
}
回到myrule.snake:
include: "myrule.py"
rule myrule:
params:
SPD=myrule_cfg["SPD"],
DIST=myrule_cfg["DIST"],
# For MSG call paramFunc() to expand {name} constructs.
MSG=lambda wildcards, input, output, threads, resources:
paramFunc(wildcards, input, output, threads, resources, config,
global_cfg, myrule_cfg, myrule_cfg["MSG"])
message: "{params.MSG}"
output: "myrule.txt"
shell: "echo '-speed {params.SPD} -dist {params.DIST}' >{output}"
请注意,paramFunc(( 函数将名称 "myrule_cfg"(因规则而异(映射到固定名称 "this_cfg"(无论规则如何都相同(。
请注意,我包含.py定义global_cfg和this_cfg字典的文件。 这些可以在 .yaml 文件中定义,但问题是它们最终都在一个字典"config"中结束。 如果配置文件命令允许指定字典,那就太好了,例如:
configfile: global_cfg="global_cfg.yaml"
也许有一天,该功能会被添加到snakemake中。
我意识到 Johannes Köster 的答案中 **config 和 **globals(( 到 format(( 的附加参数可用于允许扩展在 snakefile 的 python 代码中定义的变量,例如以下示例中的变量"ABC",并允许扩展配置参数而不在扩展中使用"config"。 假设 config.yaml 包含:
X: "Hello"
MSG: "config X: {X} variable ABC: {ABC} wildcard WW: {WW}"
你有这个蛇锉:
configfile: "config.yaml"
rule all:
input: "test.Goodbye.txt"
rule A:
output: "test.{WW}.txt"
params: MSG=lambda wildcards: config["MSG"].format(wildcards=wildcards, **config, **globals())
message: "{params.MSG}"
shell: "echo '{params.MSG}' >{output}"
ABC = "This is the ABC variable"
消息和文件输出将是以下行:
config X: Hello variable ABC: This is the ABC variable wildcard WW: Goodbye