#python #bioinformatics #jobs #job-scheduling #snakemake
Вопрос:
Я пишу конвейер в Snakemake для людей, которые не обладают большими знаниями в области программирования, поэтому я хочу, чтобы они могли запускать весь конвейер, запрашивая только snakemake all -c
в командной строке.
У меня есть 2 файла конфигурации в моем файле Snakefile:
configfile: "config.yaml"
configfile: "config_samples.yaml"
Эти файлы конфигурации будут объединены вместе с помощью Snakemake.
config.yaml
это стандартный конфигурационный файл. config_samples.yaml
представляет собой конфигурационный файл, содержимое которого изменяется в зависимости от ввода конвейера. Это выглядит следующим образом:
samples:
CYP20130000B:
R1: CYP20130000B_R1.fastq
R2: CYP20130000B_R2.fastq
SAT20020000A:
R1: SAT20020000A_R1.fastq
R2: SAT20020000A_R2.fastq
...
Я использую скрипт Python в правиле Snakemake для создания содержимого config_samples.yaml
(используя директиву snakemake script). Это прекрасно работает.
Однако, когда я перечисляю все свои желаемые результаты в all
правиле, например, так:
"config_samples.done", # flag file for rule that generates config_samples.yaml
expand(QC_raw_reads/{sample}_{direction}_fastqc.html", sample=config["samples"], direction=["R1", "R2"])
Тогда это не сработает, потому expand()
что будет расширяться только до образцов, которые находятся в текущем config_samples.yaml
состоянии, поэтому до того, как скрипт Python фактически создаст новый config_samples.yaml
с новыми образцами.
Этого можно легко избежать, запустив правило, которое генерируется config_samples.yaml
отдельно перед запуском конвейера enterire, но, возвращаясь к началу, я хочу, чтобы оно оставалось максимально простым для непрограммистов.
Итак, мне было интересно, есть ли способ позволить Snakemake перестроить/перенести задания, чтобы их можно было обновить для новых образцов.
Комментарии:
1. Вы кладете карту перед лошадью. Зачем вам нужен этот файл yaml? Вы создаете эту конфигурацию, а затем планируете прочитать ее для следующего запуска… Почему бы не работать с содержимым этой конфигурации даже без создания файла yaml?
2. Нет, я хочу сгенерировать конфигурацию для того же запуска. Например, если я выполню первый запуск с 3 образцами, то yaml будет сгенерирован с 3 образцами, и он будет работать нормально. Однако, если я затем хочу запустить снова, но с новыми образцами, допустим 5, то это не будет работать, потому что тогда, когда я прошу
all
правление в командной строке, выход файлы помещаются в предыдущие 3 образцов, потому что те будут по-прежнему находиться в YAML, а не в 5 новых, потому что эти не были сформированы, по правилу, что делает.3. Так зачем вам вообще нужен yaml? Конфигурация должна быть источником информации, но в вашем случае источником является что-то другое.
4. Потому что в конфигурации у меня есть информация обо всех инструментах, а что нет, и в этом другом yaml я хочу перечислить образцы, потому что это может привести к очень длинному списку, и я хочу сохранить это отдельно от файла конфигурации (и, кроме того, записывать образцы в yaml проще, потому что я могу просто полностью перезаписать его и не беспокоиться об удалении чего-либо из конфигурации).
5. Вам вообще не нужно хранить список образцов в файле конфигурации.
Ответ №1:
Вся ваша проблема, похоже, возникла из-за этого предложения:
Я использую скрипт Python в правиле Snakemake для создания содержимого примеров конфигурации.yaml (с использованием директивы скрипта snakemake). Это прекрасно работает.
Решение может быть таким же простым, как осознание того, что скрипт Python может выполняться вне правила Snakemake только в начале вашего змеиного файла. Змеиный файл-это в основном скрипт на Python. Таким образом, вы можете просто импортировать свой скрипт в этот змеиный файл и выполнить его там.
Таким образом, ваш змеиный файл может выглядеть следующим образом:
import config_generator
config = config_generator.add_samples(config)
rule all:
input: expand(QC_raw_reads/{sample}_{direction}_fastqc.html", sample=config["samples"], direction=["R1", "R2"])
rule A:
...
config_generator.py
выглядело бы так:
def add_samples(config):
# here you can calculate whatever you calculate to get config_samples
# e.g. config["samples"] = ...
return config
Комментарии:
1.Спасибо, это отлично работает! Сначала я не был уверен, что это сработает , потому что я использую
config.yaml
для извлечения полного пути к образцам, но пока вы вводите «config = config_generator.add_samples(config)
послеconfigfile: config.yaml
snakefile
«, это работает.2. Обновление: похоже, это работает не слишком хорошо, если вы используете
run
директиву для правила. Это правило затем имеет доступ ко всему, что определено в файле Snakefile, также за пределами правила , и кажется, что оно постоянно повторяетсяconfig_generator.add_samples(config)
, но я не уверен на 100% (ошибки, которые я получаю, очень противоречивы и, вероятно, специфичны для моего случая)
Ответ №2:
Я не полностью переварил вопросы и комментарии ниже, но я чувствую, что согласен с @DmitryKuzminov в том, что текущая настройка немного изменена.
В любом случае, я думаю, что вы можете заставить snakemake регенерироваться config_samples.yaml
, добавив в начало файла Snakefile, перед первым правилом, что-то вроде:
if os.path.exists('config_samples.yaml'):
os.remove('config_samples.yaml')
вы даже можете сделать этот шаг управляемым в командной строке с помощью:
if config['remake_config'] == 'yes':
if os.path.exists('config_samples.yaml'):
os.remove('config_samples.yaml')
а затем выполните с:
snakemake -C remake_config='yes' ...
Комментарии:
1. Это хорошее предложение, но не совсем то, что я ищу. К тому времени, когда я запрошу желаемый вывод в командной строке, конфигурационный файл уже был прочитан Snakemake, но затем
config_samples.yaml
все еще содержит старые образцы вместо новых, которые будут сгенерированы во время выполнения. Я искал способ позволить Snakemake обновлять свою конфигурацию с помощью недавно сгенерированных образцов во время выполнения, чтобы можно было генерировать соответствующие выходные данные для каждого нового образца. Однако сейчас я чувствую, что это просто невозможно, поэтому я просто позволю пользователю выполнить две команды, чтобы исправить это