Могут ли значения параметров конфигурации 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
Другие вопросы по тегам