Использование нескольких имен файлов в качестве подстановочных знаков в Snakemake

Я пытаюсь создать правило для реализации bedtools в snakemake, которое будет closest файлом с кучей файлов в другом каталоге.

У меня есть в каталоге /home/bedfiles 20 файлов кровати:

1A.bed , 2B_83.bed , 3f_33.bed ...

Я хочу, чтобы в каталоге /home/bedfiles было 20 измененных файлов кроватей:

1A_modified,  2B_83_modified , 3f_33_modified ...

Итак, команда bash будет такой:

filelist='/home/bedfiles/*.bed'
for mfile in $filelist;
do
bedtools closest -a /home/other/merged.txt -b ${mfile} > ${mfile}_modified

Таким образом, эта команда создаст файлы с расширением _modified в каталоге /home/bedfiles.

Я хочу реализовать это с помощью Snakemake, однако у меня все еще возникает синтаксическая ошибка, которую я не знаю, как исправить. Мое испытание:

Шаг 1. Получение первой части постельных файлов в каталоге

FIRSTPART = [f.split(".")[0] for f in os.listdir("/home/bedfiles") if f.endswith('.bed')]

Шаг 2. Определение имени и папки вывода

MODIFIED = expand("/home/bedfiles/{first}_modified", first=FIRSTPART)

Шаг 3. Написание этого на rule all:

rule all:
   input: MODIFIED

Шаг 4. Создание специального правила для реализации «ближайших к спальням инструментов»

rule closest:

    input:
        input1 = "/home/other/merged.txt" , \
        input2 = expand("/home/bedfiles/{first}.bed", first=FIRSTPART) 

    output:
        expand("/home/bedfiles/{first}_modified", first=FIRSTPART)  

    shell:
        """ bedtools closest -a {input.input1} -b {input.input2} > {output} """

И это выдает мне ошибку в строке для правила all, input:

invalid syntax

Вы знаете, как обойти эту ошибку или каким-либо другим способом ее реализовать?

PS: Записать имена файлов по очереди невозможно.


person bapors    schedule 25.01.2018    source источник


Ответы (2)


Удалите вызов expand в вашем определении input и output в closest. В настоящее время вы передаете вектор из 20 имен файлов как input.input2 и вектор из 20 имен файлов как output.

То есть ваше правило closest в настоящее время пытается выполнить один раз и создать 20 файлов; тогда как он должен запускаться 20 раз и каждый раз создавать один файл.

В closest вы хотите, чтобы input.input2 был одним файлом, а output - одним файлом при каждом запуске этого правила:

FIRSTPART = [f.split(".")[0] for f in os.listdir("/home/bedfiles") if f.endswith('.bed')]

print("These are the input files:")
print([f + ".bed" for f in FIRSTPART])

MODIFIED = expand("/home/bedfiles/{first}_modified", first=FIRSTPART)
print("These will be created")
print(MODIFIED)

rule all:
   input: MODIFIED

rule closest:
    message: """
        Converts /home/other/merged.txt and /some/dir/xyz.bed
        into /some/dir/xyz_modified
        """

    input:
        input1 = "/home/other/merged.txt",
        input2 = "{prefix}.bed" 

    output:    "{prefix}_modified"  

    shell:
        """ 
        bedtools closest -a {input.input1} -b {input.input2} > {output}
        """

Вот эксперимент:

Переместитесь во временный каталог и в этом каталоге выполните следующие действия:

mkdir bedfiles                                                                  
touch bedfiles/{a,b,c,d}.bed

Затем добавьте в текущий каталог файл с именем Snakefile, содержащий следующий код

import os                                                                         
import os.path
import re

input_dir = "bedfiles"
input_files = [os.path.join(input_dir, f) for f in os.listdir(input_dir)]

print(input_files)                                                                

output_files = [re.sub(".bed$", "_modified", f) for f in input_files]             

print(output_files)                                                               

rule all:                                                                         
    input: output_files                                                           

rule mover:                                                                       
    input: "{prefix}.bed"                                                         
    output: "{prefix}_modified"                                                   
    shell:                                                                        
       """ cp {input} {output} """

Затем запустите его, используя snakemake в командной строке. Snakemake целеустремлен; он работает над тем, как сделать желаемый результат на основе существующих файлов.

person Russ Hyde    schedule 25.01.2018
comment
Но тогда, если я не буду расширяться, как я могу указать имя вывода в rule all? - person bapors; 25.01.2018
comment
Кроме того, когда я говорю /path/to/bedfiles/{prefix}.bed, где мне указать этот префикс? Говорится ли * .bed как в bash? - person bapors; 25.01.2018
comment
Я не сказал модифицировать rule all, оставьте расширение там. prefix определяется автоматически, потому что входной .bed и выходной _modified файл находятся в одном каталоге. Snakemake просмотрит имена файлов в all::input и для каждого из них определит, как это сделать, учитывая существующие файлы и определенные правила. Например, будет решено, что / home / bedfiles / 1A_modified можно создать из /home/bedfiles/1A.bed с помощью правила closest, автоматически установив prefix на / home / bedfiles / 1A. - person Russ Hyde; 25.01.2018
comment
Так следует ли мне также удалить переменную FIRSTPART? - person bapors; 25.01.2018
comment
можно ли отредактировать свой ответ, чтобы показать детали? Потому что, если я удалю FIRSTPART, который сохраняет имена файлов, как я могу расширить? Кроме того, если я скажу только {prefix}, не сказав больше ничего, как я могу узнать, что он не нашел другой файл кровати в другом каталоге? - person bapors; 25.01.2018
comment
Не удаляйте FIRSTPART, он определяет входные файлы, и из него вы создаете цели своего рабочего процесса. - person Russ Hyde; 25.01.2018
comment
но опять же, как я могу узнать, что {префикс} - это / home / bedfiles, а не / home / other / other / otherfiles, если у них есть оба файла .bed внутри? - person bapors; 25.01.2018
comment
Рабочий процесс будет генерировать только те файлы, которые указаны в качестве входных данных для первого правила в вашем Snakefile, поэтому он будет генерировать только эти файлы в вашем all::input, и все они имеют форму /home/bedfiles/<some_sample>_modified по построению - person Russ Hyde; 25.01.2018
comment
Спасибо, что расширили свой ответ. Мне не хватало объявления для input_files, поэтому я не мог найти нужные файлы кровати. Отличный ответ! Еще раз большое спасибо! - person bapors; 26.01.2018
comment
Здесь, если бы я не создавал файлы _modified, чтобы он не брал их из правила всего, как бы мне указать входной файл? будет ли это правилом что-то: input: input_files или input: для f в input_files? - person bapors; 26.01.2018

Простой: неверный синтаксис относится к отсутствующему , после input1 = "/home/other/merged.txt". Надеюсь, это поможет Марку.

person Marc G.    schedule 25.01.2018
comment
@bapors Я думаю, что snakemake иногда выдает ошибки, сообщая о строке, где начинается правило. Но, может быть, не из-за синтаксических ошибок ... - person bli; 26.01.2018
comment
Я не думаю, что это заслуживает отрицательного голосования, в исходной публикации была настоящая синтаксическая ошибка. - person Russ Hyde; 26.01.2018