有没有办法在 .yaml 文件中定义一个蛇形配置字符串,以便它可以包含 {wildcard} 和 {param} 值,并且当在 shell 命令中使用该字符串时,{<name>} 值被替换为“<name>”的实际值?
例如,假设您想要一个配置字符串来定义要作为参数传递给程序的字符串的格式:
RG:“ID:{ID} 代表:{REP}”
上面的内容在 .yaml 文件中,ID 和 REP 是通配符,shell 命令会将展开的字符串作为参数传递给程序。
有没有办法在 .yaml 文件中定义一个蛇形配置字符串,以便它可以包含 {wildcard} 和 {param} 值,并且当在 shell 命令中使用该字符串时,{<name>} 值被替换为“<name>”的实际值?
例如,假设您想要一个配置字符串来定义要作为参数传递给程序的字符串的格式:
RG:“ID:{ID} 代表:{REP}”
上面的内容在 .yaml 文件中,ID 和 REP 是通配符,shell 命令会将展开的字符串作为参数传递给程序。
让我尝试为这个问题提供一个简短的答案:
在 Snakemake 中,您可以为 params 提供函数,这些函数以通配符作为参数。在这些函数中,您可以执行任何 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
我意识到 Johannes Köster 的答案中的 **config 和 **globals() 到 format() 的附加参数可用于允许扩展蛇文件的 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
这是一个参数函数,可让您在配置字符串中扩展来自多个不同的 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 参数中调用 paramFunc() 的示例:部分,以扩展配置参数 config["XYZ"] 的值并将其分配给名为“text”的参数,然后扩展该“text”参数在 shell 命令中:
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() 的最后一个参数是您要扩展的参数值,在本例中为 config["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”,想法是您可能想要一个蛇文件全局定义的字典。在您的主蛇文件中,执行以下操作:
include: "global_cfg.py"
在文件 global_cfg.py 中,放置全局定义:
global_cfg = {
"DATA_DIR" : "ProjData",
"PROJ_DESC" : "Mint Sequencing"
}
然后您可以在参数字符串中引用这些值,例如:
"{global_cfg[DATADIR]}"
(字符串必须在 params: 部分通过调用 paramFunc() 进行扩展)
对于“my_local_cfg”,想法是您可能希望将每个蛇文件规则放在一个单独的文件中,并将该规则的参数也定义在一个单独的文件中,因此每个规则都有一个规则文件和一个参数文件。在主蛇文件中:
(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”(无论规则如何,都相同)。
请注意,我包含了定义 global_cfg 和 this_cfg 字典的 .py 文件。这些可以改为在 .yaml 文件中定义,但问题是它们最终都在一个字典“config”中。如果 configfile 命令允许指定字典就好了,例如:
configfile: global_cfg="global_cfg.yaml"
也许有一天该功能会添加到snakemake中。