Snakefile和通配符/正则表达式用于输出文件命名

时间:2018-11-19 17:14:14

标签: snakemake

在旨在映射长读段的snakemake生物信息学工作流程中,输入的fastq数据可能具有一系列可能的文件扩展名,具体取决于用户偏好和文件压缩格式(例如,我希望观察到sequence.fastq或{{1} }。通配符可用于选择输入文件-我在输出文件命名方面遇到了挑战。我期望在一个工作流程中,我们可以看到未压缩,gzip压缩和bzip2压缩的样本。

是否存在剥离文件扩展名的推荐方法,以使映射的输出可以为sequence.fq.gz而不是过多的sequence.bam

非常感谢您收到任何提示-谢谢S

1 个答案:

答案 0 :(得分:0)

有几种方法可以做到这一点。不需要正则表达式但在命名标准下序列ID和扩展名由单个点分隔的一种方法是仅在首次出现时才使用split。例如,如果您使用的文件名中有两个或多个标识符,且两个标识符之间用.(例如{sequence_id1}.{sequence_id2}.{extension})隔开,则必须使用regex,但逻辑与下面类似。

您可以通过使用以下文件创建输入目录来测试此示例:

$ mkdir input
$ for i in 1 2 3;do touch input/sequence"$i";done
$ for i in 4 5 6;do touch input/sequence"$i".gz;done
$ for i in 7 8 9;do touch input/sequence"$i".fq.gz;done
$ for i in 10 11 12;do touch input/sequence"$i".bzip;done

以下Snakefile实现将满足您的要求,并允许根据是否有扩展名和扩展名类型执行不同的操作:

###Snakefile
# Get all filenames in a specific input directory
wildcards = glob_wildcards('input/{fq_files}')
# Split the filenames into basename and extension
files = [filename.split('.', 1) for filename in wildcards.fq_files]
# Create a dictionary of mapping basename:extension
file_dict = {filename[0]: filename[1] if len(
    filename) == 2 else '' for filename in files}

rule all:
    input:
        expand('output/{seqid}.bam', seqid=file_dict.keys()),

rule generate_bams:
    input:
        lambda wc: f'input/{{seqid}}.{file_dict[wc.seqid]}' if file_dict[wc.seqid] != '' else 'input/{seqid}',
    output: 'output/{seqid}.bam',
    run:
        if (file_dict[wildcards.seqid] == 'gz'):
            shell(
                'echo "FILENAME = {input}\nFile has gz in filename" > {output}')
        elif (file_dict[wildcards.seqid] == 'fq.gz'):
            shell(
                'echo "FILENAME = {input}\nFile has fq.gz in filename" > {output}')
        elif (file_dict[wildcards.seqid] == 'bzip'):
            shell(
                'echo "FILENAME = {input}\nFile has bzip in filename" > {output}')
        else:
            shell(
                'echo "FILENAME = {input}\nFile has no extension in filename" > {output}')

由于glob_wildcards不会保留扩展名到基本名的映射关系,因此您可以拆分文件名并创建一个基本名:扩展名映射。创建此字典后,您始终可以在输入和参数指定或运行/ shell指令期间对其进行访问。您可以通过将拆分部分更改为正则表达式并获取匹配的组来对正则表达式进行类似操作。

我正在使用Python 3.6,如果您的Python低于3.6,则可以更改字符串文字部分:

lambda wc: f'input/{{seqid}}.{file_dict[wc.seqid]}' if file_dict[wc.seqid] != '' else 'input/{seqid}',

收件人:

lambda wc: 'input/{{seqid}}.{0}'.format(file_dict[wc.seqid]) if file_dict[wc.seqid] != '' else 'input/{seqid}',

因此,如果文件名没有扩展名或带有各种扩展名,则可以使用glob_wilcardssplit和用于存储basename:extension映射的字典来说明它们。

将来,您应该尝试提供示例输入,输出,如果不是可行示例,则至少提供您尝试过的示例。


编辑

我假设您没有具有不同扩展名的相同序列名称。如果确实要考虑到这一点,则可以将序列名称映射到多个扩展名。您可以通过以下方式进行更改:

### Create a dictionary of mapping basename:extension
# file_dict = {filename[0]: filename[1] if len(
#     filename) == 2 else '' for filename in files}
### Creata dictionary of mapping basename: [extensions]
file_dict = {}
for filename in files:
    if len(filename) == 2:
        file_dict.setdefault(filename[0],[]).append(filename[1])
    else:
        file_dict.setdefault(filename[0],[]).append('')
print(file_dict)

这样做,您还需要在input指令中将lambda函数更改为for循环或列表理解,并在if/elif(condition)中更改条件。