此问题来自我之前询问过的question,并且它考虑了如何使用Snakemake正确访问配置文件。我有一个特定的问题需要解决,我首先要问的是一个普遍的问题,理解索引是如何工作的,我会问第二个问题。
我使用snakemake运行和从Alignment / QC到主题分析的ATAC-seq管道。
答:具体问题
我试图在对齐之前添加一个名为trim_galore_pe
的规则来修剪我的fastq文件中的适配器,并从snakemake中抛出一个错误语句作为trim galore
生成的输出文件的名称与snakemake的预期不符。这是因为我无法弄清楚如何在我的snakemake文件中正确编写输出文件语句以使名称匹配。
TRIM GALORE
生成的名称示例包含SRA编号,例如:
trimmed_fastq_files/SRR2920475_1_val_1.fq.gz
而snakemake所期望的文件包含示例引用,应该是:
trimmed_fastq_files/Corces2016_4983.7B_Mono_1_val_1.fq.gz
这也会影响trim_galore_pe
规则之后的后续规则。我需要找到一种方法来使用配置文件中的信息来生成所需的输出文件。
对于Snakefile中显示的所有规则后,我需要通过样本名称命名文件,即Corces2016_4983.7A_Mono
。对于下面Snakefile中显示的所有FAST_QC
和MULTIQC
规则,在输出文件名结构中包含样本名称也是有用的,他们都已在当前的Snakefile。
但是,Bowtie2的输入,FASTQC规则以及trim_galore_pe
规则的输入和输出需要包含SRA编号。问题从trim_galore
的输出开始,影响所有下游规则。
虽然我之前的规则中已经提取了SRA编号,但我不确定在不使用配置文件中明确说明的fastq_files
文件夹时如何执行此操作。通过引入trim_galore_pe
规则,我有效地将一组新的SRA文件移动到新的trimmed_fastq_files
文件夹中。如何从包含旧文件夹名称的SRA文件配置文件列表中提取仅 SRA编号,同时引用Snakefile中的新trimmed_fastq_files
文件夹是我的问题的关键。
我希望这很清楚。
这是我的配置文件:
samples:
Corces2016_4983.7A_Mono: fastq_files/SRR2920475
Corces2016_4983.7B_Mono: fastq_files/SRR2920476
cell_types:
Mono:
- Corces2016_4983.7A
index: /home/genomes_and_index_files/hg19
这是我的Snakefile:
# read config info into this namespace
configfile: "config.yaml"
print (config['samples'])
rule all:
input:
expand("FastQC/PRETRIM/{sample}_{num}_fastqc.zip", sample=config["samples"], num=['1', '2']),
expand("bam_files/{sample}.bam", sample=config["samples"]),
"FastQC/PRETRIM/fastq_multiqc.html",
"FastQC/POSTTRIM/fastq_multiqc.html"
rule fastqc_pretrim:
input:
sample=lambda wildcards: f"{config['samples'][wildcards.sample]}_{wildcards.num}.fastq.gz"
output:
# Output needs to end in '_fastqc.html' for multiqc to work
html="FastQC/PRETRIM/{sample}_{num}_fastqc.html",
zip="FastQC/PRETRIM/{sample}_{num}_fastqc.zip"
wrapper:
"0.23.1/bio/fastqc"
rule multiqc_fastq_pretrim:
input:
expand("FastQC/PRETRIM/{sample}_{num}_fastqc.html", sample=config["samples"], num=['1', '2'])
output:
"FastQC/PRETRIM/fastq_multiqc.html"
wrapper:
"0.23.1/bio/multiqc"
rule trim_galore_pe:
input:
sample=lambda wildcards: expand(f"{config['samples'][wildcards.sample]}_{{num}}.fastq.gz", num=[1,2])
output:
"trimmed_fastq_files/{sample}_1_val_1.fq.gz",
"trimmed_fastq_files/{sample}_1.fastq.gz_trimming_report.txt",
"trimmed_fastq_files/{sample}_2_val_2.fq.gz",
"trimmed_fastq_files/{sample}_2.fastq.gz_trimming_report.txt"
params:
extra="--illumina -q 20"
log:
"logs/trim_galore/{sample}.log"
wrapper:
"0.23.1/bio/trim_galore/pe"
rule fastqc_posttrim:
input:
"trimmed_fastq_files/{sample}_1_val_1.fq.gz", "trimmed_fastq_files/{sample}_2_val_2.fq.gz"
output:
# Output needs to end in '_fastqc.html' for multiqc to work
html="FastQC/POSTTRIM/{sample}_{num}_fastqc.html",
zip="FastQC/POSTTRIM/{sample}_{num}_fastqc.zip"
wrapper:
"0.23.1/bio/fastqc"
rule multiqc_fastq_posttrim:
input:
expand("FastQC/POSTTRIM/{sample}_{num}.trim_fastqc.html", sample=config["samples"], num=['1', '2'])
output:
"FastQC/POSTTRIM/fastq_multiqc.html"
wrapper:
"0.23.1/bio/multiqc"
rule bowtie2:
input:
"trimmed_fastq_files/{sample}_1_val_1.fq.gz", "trimmed_fastq_files/{sample}_2_val_2.fq.gz"
output:
"bam_files/{sample}.bam"
log:
"logs/bowtie2/{sample}.txt"
params:
index=config["index"], # prefix of reference genome index (built with bowtie2-build),
extra=""
threads: 8
wrapper:
"0.23.1/bio/bowtie2/align"
目前正在运行,并使用snakemake -np
提供完整的工作清单,但会引发上述错误。
B:一般性问题
是否有在线资源简明扼要地解释如何使用python引用配置文件,特别是参考snakemake?在线文档是相当不充分的,并假设python的先验知识。
我的编程经验主要是在bash和R中,但我喜欢Snakemake,并且通常了解字典和列表在python中的工作方式以及如何引用存储在其中的项目。但是我发现在上面的一些Snakemake规则中复杂地使用包围,通配符和引号可能会让人感到困惑,因此在尝试引用配置文件中的文件名的不同部分时往往会很困难。我想完全理解如何利用这些元素。
例如,在上面发布的Snakefile中的这样的规则中:
sample=lambda wildcards: expand(f"{config['samples'][wildcards.sample]}_{{num}}.fastq.gz", num=[1,2])
此命令实际发生了什么?我的理解是我们使用config['samples']
访问配置文件,我们使用[wildcards.sample]
部分显式访问配置文件的fastq_files/SRR2920475
部分。扩展允许我们遍历配置文件中适合命令中的参数的每个项目,即所有SRA文件,以及在命令中使用wildcards
调用所需的lambda通配符。我不确定的是:
f
在展开之后做了什么,为什么需要?config['samples']
在方括号内包含引号,但[wildcards.sample]
周围不需要引号?num
的部分,但这些数字有时会用引号括起来,有时候不是......为什么?任何建议,提示,指示都将不胜感激。
C:对@bli
下面提出的建议进行澄清我已根据您在评论中的建议编辑了我的配置文件,并省略了只留下SRA编号的文件夹名称。这对我来说很有意义,但是我还有其他几个问题阻止我运行这个Snakefile。
新配置文件:
samples:
Corces2016_4983.7A_Mono: SRR2920475
Corces2016_4983.7B_Mono: SRR2920476
cell_types:
Mono:
- Corces2016_4983.7A
index: /home/c1477909/genomes_and_index_files/hg19
新Snakefile:
# read config info into this namespace
configfile: "config.yaml"
print (config['samples'])
rule all:
input:
expand("FastQC/PRETRIM/{sample}_{num}_fastqc.zip", sample=config["samples"], num=['1', '2']),
expand("bam_files/{sample}.bam", sample=config["samples"]),
"FastQC/PRETRIM/fastq_multiqc.html",
"FastQC/POSTTRIM/fastq_multiqc.html",
rule fastqc_pretrim:
input:
lambda wildcards: f"fastq_files/{config['samples'][wildcards.sample]}_{wildcards.num}.fastq.gz"
output:
# Output needs to end in '_fastqc.html' for multiqc to work
html="FastQC/PRETRIM/{sample}_{num}_fastqc.html",
zip="FastQC/PRETRIM/{sample}_{num}_fastqc.zip"
wrapper:
"0.23.1/bio/fastqc"
rule multiqc_fastq_pretrim:
input:
expand("FastQC/PRETRIM/{sample}_{num}_fastqc.html", sample=config["samples"], num=['1', '2'])
output:
"FastQC/PRETRIM/fastq_multiqc.html"
wrapper:
"0.23.1/bio/multiqc"
rule trim_galore_pe:
input:
lambda wildcards: expand(f"fastq_files/{config['samples'][wildcards.sample]}_{{num}}.fastq.gz", num=[1,2])
output:
"trimmed_fastq_files/{wildcards.sample}_1_val_1.fq.gz",
"trimmed_fastq_files/{wildcards.sample}_1.fastq.gz_trimming_report.txt",
"trimmed_fastq_files/{wildcards.sample}_2_val_2.fq.gz",
"trimmed_fastq_files/{wildcards.sample}_2.fastq.gz_trimming_report.txt"
params:
extra="--illumina -q 20"
log:
"logs/trim_galore/{sample}.log"
wrapper:
"0.23.1/bio/trim_galore/pe"
rule fastqc_posttrim:
input:
lambda wildcards: expand(f"trimmed_fastq_files/{config['samples'][wildcards.sample]}_{{num}}_val_{{num}}.fq.gz", num=[1,2])
output:
# Output needs to end in '_fastqc.html' for multiqc to work
html="FastQC/POSTTRIM/{sample}_{num}_fastqc.html",
zip="FastQC/POSTTRIM/{sample}_{num}_fastqc.zip"
wrapper:
"0.23.1/bio/fastqc"
rule multiqc_fastq_posttrim:
input:
expand("FastQC/POSTTRIM/{sample}_{num}.trim_fastqc.html", sample=config["samples"], num=['1', '2'])
output:
"FastQC/POSTTRIM/fastq_multiqc.html"
wrapper:
"0.23.1/bio/multiqc"
rule bowtie2:
input:
lambda wildcards: expand(f"trimmed_fastq_files/{config['samples'][wildcards.sample]}_{{num}}_val_{{num}}.fq.gz", num=[1,2])
output:
"bam_files/{sample}.bam"
log:
"logs/bowtie2/{sample}.txt"
params:
index=config["index"], # prefix of reference genome index (built with bowtie2-build),
extra=""
threads: 8
wrapper:
"0.23.1/bio/bowtie2/align"
使用这些新文件最初一切正常,snakemake -np
创建了部分作业列表。但是,这是因为已经完成了一半的完整工作清单;这就是生成trimmed_fastq_files
文件夹,并且正确命名的修剪的fastq文件就位于其中。当我删除所有以前创建的文件以查看整个新版本的Snakefile是否能正常工作时,snakemake -np
失败,说明trim_galore_pe
规则下游规则缺少输入文件。
正如您所看到的,我尝试在输出部分中调用{wildcard.sample}
规则的输入部分中设置的trim_galore_pe
变量,但是snakemake并不喜欢这样。有可能这样做吗?
我也尝试使用以下答案中的提示,但这也没有效果:
rule trim_galore_pe:
input:
sample=lambda wildcards: expand(f"fastq_files/{config['samples'][wildcards.sample]}_{{num}}.fastq.gz", num=[1,2])
output:
expand(f"trimmed_fastq_files/{config['samples'][wildcards.sample]}_{{num}}_val_{{num}}.fq.gz", num=[1,2]),
expand(f"trimmed_fastq_files/{config['samples'][wildcards.sample]}_{{num}}.fastq.gz_trimming_report.txt", num=[1,2])
params:
extra="--illumina -q 20"
log:
"logs/trim_galore/{sample}.log"
wrapper:
"0.23.1/bio/trim_galore/pe"
然后错误说明wildcards not defined
。因此,从逻辑上讲,我尝试将lambda wildcards:
放在输出部分的两个expand语句之前,以尝试定义通配符,但这会引发语法错误Only input files can be specified as functions
。我也尝试过使用下面的一些索引建议,但无法获得正确的组合。
这可能是由于我对Snakefiles不确定的另一件事造成的,这就是确定范围的方法。
rule all
中定义变量,是否所有其他规则都可以访问它? {wildcard.sample}
变量?那是因为该变量被封闭在一个封闭的'范围lambda函数?非常感谢任何(进一步)建议。
答案 0 :(得分:3)
我会尝试回答你的问题B,并提供我希望对你和其他人有用的额外细节。
编辑:我在最后回答了问题C时添加了一些尝试。
首先,关于你所说的"倒置"逗号,它们通常被称为"单引号",它们在python中用于构建字符串。双引号也可用于相同目的。主要区别在于您尝试创建包含引号的字符串。使用双引号可以创建包含单引号的字符串,反之亦然。否则,你需要逃避"使用反斜杠的引用(" \"):
s1 = 'Contains "double quotes"'
s1_bis = "Contains \"double quotes\""
s2 = "Contains 'single quotes'"
s2_bis = 'Contains \'single quotes\''
(我倾向于选择双引号,这只是个人品味。)
rule trim_galore_pe:
input:
sample=lambda wildcards: expand(f"{config['samples'][wildcards.sample]}_{{num}}.fastq.gz", num=[1,2])
您正在为函数(lambda wildcards: ...
)分配一个函数(sample
),该变量恰好属于规则的输入部分。
这将导致snakemake在根据通配符的当前值(根据它想要生成的输出的当前值推断)确定特定规则实例的输入时使用此函数。
为清楚起见,人们很可能通过将函数定义与规则声明分离而不使用lambda
构造来重写它,并且它将以相同的方式工作:
def determine_sample(wildcards):
return expand(
f"{config['samples'][wildcards.sample]}_{{num}}.fastq.gz",
num=[1,2])
rule trim_galore_pe:
input:
sample = determine_sample
expand
是一个特定于snakemake的函数(但你可以在任何python程序或带from snakemake.io import expand
的交互式解释器中导入它),这样可以更容易地生成字符串列表。在下面的交互式python3.6会话中,我们将尝试使用不同的本机python构造重现使用它时发生的情况。
# We'll try to see how `expand` works, we can import it from snakemake
from snakemake.io import expand
# We want to see how it works using the following example
# expand(f"{config['samples'][wildcards.sample]}_{{num}}.fastq.gz", num=[1,2])
# To make the example work, we will first simulate the reading
# of a configuration file
import yaml
config_text = """
samples:
Corces2016_4983.7A_Mono: fastq_files/SRR2920475
Corces2016_4983.7B_Mono: fastq_files/SRR2920476
cell_types:
Mono:
- Corces2016_4983.7A
index: /home/genomes_and_index_files/hg19
"""
# Here we used triple quotes, to have a readable multi-line string.
# The following is equivalent to what snakemake does with the configuration file:
config = yaml.load(config_text)
config
输出:
{'cell_types': {'Mono': ['Corces2016_4983.7A']},
'index': '/home/genomes_and_index_files/hg19',
'samples': {'Corces2016_4983.7A_Mono': 'fastq_files/SRR2920475',
'Corces2016_4983.7B_Mono': 'fastq_files/SRR2920476'}}
我们获得了一个字典,其中的密钥"样本"与嵌套字典相关联。
# We can access the nested dictionary as follows
config["samples"]
# Note that single quotes could be used instead of double quotes
# Python interactive interpreter uses single quotes when it displays strings
输出:
{'Corces2016_4983.7A_Mono': 'fastq_files/SRR2920475',
'Corces2016_4983.7B_Mono': 'fastq_files/SRR2920476'}
# We can access the value corresponding to one of the keys
# again using square brackets
config["samples"]["Corces2016_4983.7A_Mono"]
输出:
'fastq_files/SRR2920475'
# Now, we will simulate a `wildcards` object that has a `sample` attribute
# We'll use a namedtuple for that
# https://docs.python.org/3/library/collections.html#collections.namedtuple
from collections import namedtuple
Wildcards = namedtuple("Wildcards", ["sample"])
wildcards = Wildcards(sample="Corces2016_4983.7A_Mono")
wildcards.sample
输出:
'Corces2016_4983.7A_Mono'
编辑(15/11/2018):我发现了一种更好的创建通配符的方法:
from snakemake.io import Wildcards
wildcards = Wildcards(fromdict={"sample": "Corces2016_4983.7A_Mono"})
# We can use this attribute as a key in the nested dictionary
# instead of using directly the string
config["samples"][wildcards.sample]
# No quotes here: `wildcards.sample` is a string variable
输出:
'fastq_files/SRR2920475'
expand
# Now, the expand of the example works, and it results in a list with two strings
expand(f"{config['samples'][wildcards.sample]}_{{num}}.fastq.gz", num=[1,2])
# Note: here, single quotes are used for the string "sample",
# in order not to close the opening double quote of the whole string
输出:
['fastq_files/SRR2920475_1.fastq.gz', 'fastq_files/SRR2920475_2.fastq.gz']
# Internally, I think what happens is something similar to the following:
filename_template = f"{config['samples'][wildcards.sample]}_{{num}}.fastq.gz"
# This template is then used for each element of this "list comprehension"
[filename_template.format(num=num) for num in [1, 2]]
输出:
['fastq_files/SRR2920475_1.fastq.gz', 'fastq_files/SRR2920475_2.fastq.gz']
# This is equivalent to building the list using a for loop:
filenames = []
for num in [1, 2]:
filename = filename_template.format(num=num)
filenames.append(filename)
filenames
输出:
['fastq_files/SRR2920475_1.fastq.gz', 'fastq_files/SRR2920475_2.fastq.gz']
# It is interesting to have a look at `filename_template`
filename_template
输出:
'fastq_files/SRR2920475_{num}.fastq.gz'
# The part between curly braces can be substituted
# during a string formatting operation:
"fastq_files/SRR2920475_{num}.fastq.gz".format(num=1)
输出:
'fastq_files/SRR2920475_1.fastq.gz'
现在让我们进一步展示如何使用字符串格式。
# In python 3.6 and above, one can create formatted strings
# in which the values of variables are interpreted inside the string
# if the string is prefixed with `f`.
# That's what happens when we create `filename_template`:
filename_template = f"{config['samples'][wildcards.sample]}_{{num}}.fastq.gz"
filename_template
输出:
'fastq_files/SRR2920475_{num}.fastq.gz'
在格式化字符串期间发生了两次替换:
config['samples'][wildcards.sample]
的值用于制作字符串的第一部分。 (sample
周围使用了单引号,因为这个python表达式位于用双引号构建的字符串中。)
作为格式化操作的一部分,num
周围的双括号缩小为单个括号。这就是为什么我们可以在涉及num
的进一步格式化操作中再次使用它。
# Equivalently, without using 3.6 syntax:
filename_template = "{filename_prefix}_{{num}}.fastq.gz".format(
filename_prefix = config["samples"][wildcards.sample])
filename_template
输出:
'fastq_files/SRR2920475_{num}.fastq.gz'
# We could achieve the same by first extracting the value
# from the `config` dictionary
filename_prefix = config["samples"][wildcards.sample]
filename_template = f"{filename_prefix}_{{num}}.fastq.gz"
filename_template
输出:
'fastq_files/SRR2920475_{num}.fastq.gz'
# Or, equivalently:
filename_prefix = config["samples"][wildcards.sample]
filename_template = "{filename_prefix}_{{num}}.fastq.gz".format(
filename_prefix=filename_prefix)
filename_template
输出:
'fastq_files/SRR2920475_{num}.fastq.gz'
# We can actually perform string formatting on several variables
# at the same time:
filename_prefix = config["samples"][wildcards.sample]
num = 1
"{filename_prefix}_{num}.fastq.gz".format(
filename_prefix=filename_prefix, num=num)
输出:
'fastq_files/SRR2920475_1.fastq.gz'
# Or, using 3.6 formatted strings
filename_prefix = config["samples"][wildcards.sample]
num = 1
f"{filename_prefix}_{num}.fastq.gz"
输出:
'fastq_files/SRR2920475_1.fastq.gz'
# We could therefore build the result of the expand in a single step:
[f"{config['samples'][wildcards.sample]}_{num}.fastq.gz" for num in [1, 2]]
输出:
['fastq_files/SRR2920475_1.fastq.gz', 'fastq_files/SRR2920475_2.fastq.gz']
就Python如何构建字符串而言,以下内容有点复杂:
input:
lambda wildcards: expand(f"fastq_files/{config['samples'][wildcards.sample]}_{{num}}.fastq.gz", num=[1,2])
但它应该可行,正如我们在以下模拟中所看到的那样:
from collections import namedtuple
from snakemake.io import expand
Wildcards = namedtuple("Wildcards", ["sample"])
wildcards = Wildcards(sample="Corces2016_4983.7A_Mono")
config = {"samples": {
"Corces2016_4983.7A_Mono": "SRR2920475",
"Corces2016_4983.7B_Mono": "SRR2920476"}}
expand(
f"fastq_files/{config['samples'][wildcards.sample]}_{{num}}.fastq.gz",
num=[1,2])
输出:
['fastq_files/SRR2920475_1.fastq.gz', 'fastq_files/SRR2920475_2.fastq.gz']
trim_galore_pe
规则中的问题实际上在output
部分:您不应该在{wildcards.sample}
使用{sample}
,而只是output
。
规则的"trimmed_fastq_files/Corces2016_4983.7A_Mono_1_val_1.fq.gz"
部分通过匹配要获取的文件与给定的模式匹配,告知snakemake通配符属性对于给定规则实例的含义。与花括号匹配的部分将用于设置相应属性名称的值。
例如,如果snakemake想要一个名为"trimmed_fastq_files/{sample}_1_val_1.fq.gz"
的文件,它会尝试将其与所有规则的输出部分中出现的所有模式相匹配,并最终找到这个:Corces2016_4983.7A_Mono
幸运的是,通过建立{sample}
和sample
部分之间的对应关系,它可以将文件名与模式匹配。然后它会在本地通配符实例中放置一个Wildcards = namedtuple("Wildcards", ["sample"])
wildcards = Wildcards(sample="Corces2016_4983.7A_Mono")
属性,就像我手动执行以下操作一样:
{wildcards.sample}
如果您使用{wildcards}
代替Wildcards = namedtuple("Wildcards", ["sample"])
wildcards = Wildcards(wildcards.sample="Corces2016_4983.7A_Mono")
File "<ipython-input-12-c02ce12bff85>", line 1
wildcards = Wildcards(wildcards.sample="Corces2016_4983.7A_Mono")
^
SyntaxError: keyword can't be an expression
,我不知道在snakemake中会发生什么,但让我们尝试使用我的模拟框架:
output:
expand(f"trimmed_fastq_files/{config['samples'][wildcards.sample]}_{{num}}_val_{{num}}.fq.gz", num=[1,2]),
您的以下尝试怎么样?
f
在此,我的理解是Python首先尝试在f"trimmed_fastq_files/{config['samples'][wildcards.sample]}_{{num}}_val_{{num}}.fq.gz"
上应用config['samples'][wildcards.sample]
字符串格式。
为此,它需要能够评估wildcards
,但wildcards not defined
对象尚不存在。因此wildcards
。
只有在匹配&#34;下游&#34;所需文件的名称后才会生成{attribute_name}
。包含wildcards
个模式的字符串的规则。但这是snakemake目前正在努力建立的字符串。
以下是要记住的一些要点:
wildcards
实际上只在本地,在规则的实例中,在将其输出与另一个&#34;下游&#34;规则实例。{attribute_name}
对象。默认情况下,wildcards
占位符将替换为本地"{sample}"
对象的属性("Corces2016_4983.7A_Mono"
变为wildcards
),但如果您想要构建更复杂的内容文件名,您需要通过一个必须显式处理此lambda wildcards: f"{wildcards.sample}"
对象的函数来执行此操作("Corces2016_4983.7A_Mono"
变为{{1}})。答案 1 :(得分:2)
对于问题的A部分,我建议使用制表符分隔的文件来存储样本信息,ID等,无论您拥有多少样本。然后,您可以在配置文件中存储此文件的路径,并使用带有pandas库的列标识符来访问它。有关详细信息,请参阅this thread。
至于B部分:
看起来它是一种在python中格式化字符串的新方法,请参阅this link for ex。
config['samples']
旨在访问配置文件的密钥&#34; samples&#34;,而[wildcards.sample]
旨在访问通配符{sample}
as在您的工作流程中定义(rule all
)。
双括号通常用于转义简单括号。在这里,它避免了扩展{{num}}
(不能将自己的手放在snakemake&the文档的示例中)。
num=['1', '2']
正在为通配符{num}
分配值列表,以便稍后可以使用{wildcards.num}
进行访问。如果所有规则都是&#39;输入和输出是链接的,您不应该多次定义这些值。
希望这能澄清你的一些担忧,祝你好运!