объединять с выводами различных правил в Snakemake

#snakemake

#snakemake

Вопрос:

Я хотел бы использовать snakemake для первого объединения некоторых файлов, а затем обработать другие файлы на основе этого слияния. (Менее абстрактно: я хочу объединить управляющие файлы IGG bam из двух разных наборов, а затем использовать их для выполнения пикового вызова для других файлов.

В минимальном примере структура папок будет выглядеть следующим образом.

 ├── data
│   ├── toBeMerged
│   │   ├── singleA
│   │   ├── singleB
│   │   ├── singleC
│   │   └── singleD
│   └── toBeProcessed
│       ├── NotProcess1
│       ├── NotProcess2
│       ├── NotProcess3
│       ├── NotProcess4
│       └── NotProcess5
├── merge.cfg
├── output
│   ├── mergeAB_merge
│   ├── mergeCD_merge
│   ├── NotProcess1_processed
│   ├── NotProcess2_processed
│   ├── NotProcess3_processed
│   ├── NotProcess4_processed
│   └── NotProcess5_processed
├── process.cfg
└── Snakefile
  

Какие файлы объединяются, а какие обрабатываются, определено в двух файлах конфигурации.
merge.cfg

 singlePath  controlName
data/toBeMerged/singleA output/controlAB
data/toBeMerged/singleB output/controlAB
data/toBeMerged/singleC output/controlCD
data/toBeMerged/singleD output/controlCD
  

и обработать.cfg

 controlName inName
output/controlAB    data/toBeProcessed/NotProcess1
output/controlAB    data/toBeProcessed/NotProcess2
output/controlCD    data/toBeProcessed/NotProcess3
output/controlCD    data/toBeProcessed/NotProcess4
output/controlAB    data/toBeProcessed/NotProcess5
  

В настоящее время я застрял с подобным snakefile, который сам по себе не работает и выдает ошибку о том, что оба правила неоднозначны. И даже если бы я заставил это работать, я подозреваю, что это не «правильный» способ, поскольку правило процесса должно иметь {mergeName} в качестве входных данных для построения своей базы данных. Но это не работает, поскольку тогда мне понадобились бы две подстановочные карточки в одном правиле.

 import pandas as pd
cfgMerge = pd.read_table("merge.cfg").set_index("controlName", drop=False)
cfgProc= pd.read_table("process.cfg").set_index("inName", drop=False)


rule all:
    input:
        expand('{mergeName}', mergeName= cfgMerge.controlName),
        expand('{rawName}_processed', rawName= cfgProc.inName)

rule merge:
    input:
        lambda wc: cfgMerge[cfgMerge.controlName == wc.mergeName].singlePath
    output:
        "{mergeName}"
    shell:
        "cat {input} > {output}"

rule process:
    input:
        inMerge=lambda wc: cfgProc[cfgProc.inName == wc.rawName].controlName.iloc[0],
        Name=lambda wc: cfgProc[cfgProc.inName == wc.rawName].inName.iloc[0]
    output:
        '{rawName}_processed'
    shell:
    "cat {input.inMerge} {input.Name} > {output}"
  

Я предполагаю, что ключевая проблема заключается в том, как использовать вывод правила в качестве входных данных для другого, когда оно не зависит от того же подстановочного знака или включает другой другой подстановочный знак.

Комментарии:

1. «как использовать вывод правила в качестве входных данных для другого, когда оно не зависит от того же подстановочного знака» -> Это наводит меня на мысль, что сложная функция ввода могла бы помочь. Под «сложным» я подразумеваю: «С некоторой логикой, реализованной на Python», а также могло бы помочь что-то более читаемое, чем лямбда-функция. «оба правила неоднозначны» -> Такого рода вещи иногда можно разрешить, используя ограничения с подстановочными знаками.

Ответ №1:

Для справки на будущее: проблема, похоже, заключалась не в «использовании вывода правила в качестве входных данных для другого, когда оно не зависит от того же подстановочного знака или включает другой другой подстановочный знак». Кажется, что входные данные для правила all и выходные данные для двух других правил неоднозначны. Простое решение — поместить каждый вывод в другой каталог, и это сработало (см. Ниже).

 import pandas as pd
cfgMerge = pd.read_table("merge.cfg").set_index("controlName", drop=False)
cfgProc= pd.read_table("process.cfg").set_index("inName", drop=False)

#ruleorder: merge > process

rule all:
    input:
        expand('output/bam/{rawName}_processed', rawName= cfgProc.inName),
        expand('output/control/{controlNameSnake}', controlNameSnake= cfgMerge.controlName.unique())

rule merge:
    input:
        lambda wc: cfgMerge[cfgMerge.controlName == wc.controlNameSnake].singlePath.unique()
    output:
        'output/control/{controlNameSnake}'
    shell:
        'echo {input} > {output}'


rule process:
    input:
        in1="data/toBeProcessed/{rawName}",
        in2=lambda wc: "output/control/" "".join(cfgProc[cfgProc.inName == wc.rawName].controlName.unique())
    output:
        'output/bam/{rawName}_processed'
    shell:
        'echo {input} > {output}'