Могут ли значения параметров конфигурации snakemake быть строками со значениями {<name>} для интерполяции / расширения?
Есть ли способ определить строку конфигурации snakemake в файле.yaml, чтобы она могла содержать значения {wildcard} и {param}, а когда эта строка используется в команде оболочки, значения {
Например, предположим, что вы хотите, чтобы строка конфигурации определяла формат строки, передаваемой в качестве аргумента программе:
RG: "ID: {ID} REP: {REP}"
где приведенное выше находится в файле.yaml, а ID и REP являются подстановочными знаками, а команда оболочки передает расширенную строку в качестве аргумента программе.
4 ответа
Позвольте мне дать краткий ответ на вопрос:
В 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:
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
Вот функция param, которая позволяет вам расширять значения из нескольких различных источников 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)
Вот пример того, как вызывать paramFunc() из раздела params: Snakemake, чтобы расширить значение параметра конфигурации config["XYZ"] и назначить его параметру с именем "text", а затем развернуть этот параметр "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() - это значение параметра, которое вы хотите раскрыть, в данном случае 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" идея состоит в том, что вы можете захотеть иметь словарь глобальных определений snakefile. В вашем основном файле змеи сделайте это:
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.nake:
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 позволила указать словарь, например:
configfile: global_cfg="global_cfg.yaml"
Возможно, эта функция когда-нибудь будет добавлена в змеиное дело.
Я понял, что дополнительные аргументы **config и **globals() для format() в ответе Йоханнеса Кестера могут быть использованы для разрешения раскрытия переменных, определенных в коде python файла snakefile, таких как переменная "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