snakemake para hacer bioinformática – usando comodines para generalizar sus reglas

Publicado: vie 03 marzo 2023

Por C. Titus Brown

En la ciencia.

Etiquetas: serpientehacer deslizándose

Como mostramos en una publicación de blog anterior, cuando tiene subcadenas repetidas entre la entrada y la salida, puede extraerlas en comodines, pasando de una regla que genera salidas específicas:

rule sketch_genomes_1:
    input:
        "genomes/GCF_000017325.1.fna.gz",
    output:
        "GCF_000017325.1.fna.gz.sig",
    shell: """
        sourmash sketch dna -p k=31  --name-from-first
    """

a una regla que hace cualquier salida que se ajuste a un patrón:

rule sketch_genomes_1:
    input:
        "genomes/.fna.gz",
    output:
        ".fna.gz.sig",
    shell: """
        sourmash sketch dna -p k=31  
            --name-from-first
    """

Aquí, es un comodín que “rellena” según sea necesario para cualquier nombre de archivo que esté bajo el genomes/ directorio y termina con .fna.gz.

Snakemake utiliza simple la coincidencia de patrones para determinar el valor de
– si se le pide un nombre de archivo que termine en .fna.gz.sigsnakemake toma el prefijo y luego busca el archivo de entrada correspondiente
genomes/.fna.gzy completa respectivamente.

¡Esto es increíblemente útil y significa que en muchos casos puede escribir una sola regla que puede generar cientos o miles de archivos!

Sin embargo, hay algunas sutilezas a considerar. En este capítulo, cubriremos las más importantes de esas sutilezas y proporcionaremos enlaces donde puede obtener más información.

Reglas para comodines

Primero, veamos algunas reglas básicas para los comodines.

Los comodines están determinados por la salida deseada

La primera y más importante regla de los comodines es la siguiente: Snakemake completa los valores de los comodines en función del nombre de archivo que se le pide que produzca.

Considere la siguiente regla:

rule a:
    output: ".a.out"
    shell: "touch "

El comodín en el bloque de salida coincidirá cualquier archivo que termina con
.a.out, ¡y el comando de shell asociado lo creará! Esto es poderoso y restrictivo: puede crear cualquier archivo con el sufijo
.a.out – pero también necesitas preguntar para que se cree el archivo.

Esto significa que para hacer uso de esta regla, debe haber otra regla que tenga un archivo que termine en .a.out como entrada requerida. (También puede solicitar explícitamente un archivo de este tipo en la línea de comando). No hay otra forma de que Snakemake adivine el valor del comodín: SnakeMake sigue el dicho de que lo explícito es mejor que lo implícito, y no adivinará en qué archivos quieres creado.

Por ejemplo, la regla anterior podría combinarse con otra regla que solicite uno o más nombres de archivo que terminen en .a.out:

rule make_me_a_file:
    input:
        "result1.a.out",
        "result2.a.out",

Esto también significa que una vez que coloca un comodín en una regla, ya no puede ejecutar esa regla por el nombre de la regla; en su lugar, debe solicitar un nombre de archivo. Si intenta ejecutar una regla que contiene un comodín pero no le dice qué nombre de archivo desea crear, obtendrá:

Target rules may not contain wildcards.

Una forma común de trabajar con reglas comodín es tener otra regla que use expand para construir una lista de archivos deseados; esto a menudo se combina con un glob_wildcards para cargar una lista de comodines. Consulte la receta para cambiar el nombre de los archivos por prefijo, a continuación.

Todos los comodines utilizados en una regla deben coincidir con los comodines de la output: bloquear

snakemake utiliza los comodines en el output: bloque para completar los comodines en otras partes de la regla, por lo que solo puede usar los comodines mencionados en output:.

Entonces, por ejemplo, cada comodín en el input: el bloque necesita ser usado en output:. Considere el siguiente ejemplo, donde el bloque de entrada contiene un comodín analysis que no se utiliza en el bloque de salida:

# this does not work:

rule analyze_sample:
    input: ".x..in"
    output: ".out"

Esto no funciona porque SnakeMake no sabe cómo completar el
analysis comodín en el aporte bloquear.

Piénselo de esta manera: si esto funcionara, habría múltiples archivos de entrada diferentes para la misma salida, y Snakemake no tendría forma de elegir qué archivo de entrada usar.

Hay situaciones en las que los comodines en el output: bloquear hacer no
necesita estar en el input: sin embargo, consulte “Uso de comodines para determinar parámetros para usar en el bloque de shell”, a continuación, sobre el uso de comodines para determinar parámetros para el bloque de shell.

Los comodines son locales para cada regla

Los nombres comodín solo deben coincidir dentro un bloque de reglas. Puede usar los mismos nombres de comodines en varias reglas para mantener la coherencia y la legibilidad, pero Snakemake los tratará como comodines independientes y los valores de los comodines no se compartirán.

Entonces, por ejemplo, estas dos reglas usan el mismo comodín a en ambas reglas –

rule analyze_this:
    input: ".first.txt"
    output: ".second.txt"

rule analyze_that:
    input: ".second.txt"
    output: ".third.txt"

pero esto es equivalente a estas dos reglas siguientes, que usan diferente
comodines a y b en las reglas separadas:

rule analyze_this:
    input: ".first.txt"
    output: ".second.txt"

rule analyze_that:
    input: ".second.txt"
    output: ".third.txt"

Hay una excepción a la regla de que los comodines son independientes: cuando utiliza restricciones de comodines globales para restringir la coincidencia de comodines por nombre de comodín, las restricciones se aplican a todos los usos de ese nombre de comodín en el Snakefile. sin embargo, el valores de los comodines siguen siendo independientes: solo se comparte la restricción.

Si bien los comodines tienen valores independientes, es una buena convención elegir comodines para que tengan el mismo significado semántico en todo el Snakefile; por ejemplo, siempre use sample consistentemente para referirse a una muestra. ¡Esto facilita la lectura del Snakefile!

Un apéndice interesante: debido a que los comodines son locales para cada regla, ¡usted es libre de hacer coincidir diferentes partes de patrones en reglas diferentes! Consulte “Combinar y combinar comodines”, a continuación.

El espacio de nombres comodín está implícitamente disponible en input: y output: bloques, pero no en otros bloques.

Dentro de input: y output: bloques en una regla, puede hacer referencia a los comodines directamente por su nombre. Si desea utilizar comodines en otras partes de una regla, debe utilizar el wildcards. prefijo. Aquí,
wildcards es un espacio de nombres, de la que hablaremos más adelante. (CTB)

Considere este Snakefile:

# this does not work:

rule analyze_this:
    input: ".first.txt"
    output: ".second.txt"
    shell: "analyze  -o  --title "

Aquí obtendrá un error,

NameError: The name 'a' is unknown in this context. Did you mean 'wildcards.a'?

Como sugiere el error, debe usar wildcards.a en el bloque de shell en su lugar:

rule analyze_this:
    input: ".first.txt"
    output: ".second.txt"
    shell: "analyze  -o  --title "

Los comodines coinciden con avidez, a menos que estén restringidos

La coincidencia de patrón comodín elige el más largo posible coincidir con
cualquier caracteres, lo que puede resultar en un comportamiento ligeramente confuso. Considerar:

rule all:
    input:
        "x.y.z.gz"

rule something:
    input: "..txt"
    output: "..gz"
    shell: "gzip -c  > "

En el something regla, para el archivo de salida deseado x.y.z.gz,
será actualmente x.y y será z. Pero sería igualmente válido para ser x y sufijo para ser y.z.

Un ejemplo más extremo muestra la coincidencia codiciosa aún más claramente:

rule all:
    input:
        "longer_filename.gz"

rule something:
    input: ".txt"
    output: ".gz"
    shell: "gzip -c  > "

dónde se reduce a un solo carácter, ey
es longer_filenam!

Dos reglas simples para la coincidencia de comodines son: * todos los comodines deben coincidir con al menos un carácter. * después de eso, los comodines coincidirán con avidez: cada comodín coincidirá con todo lo que pueda antes de que se considere el siguiente comodín.

Por lo tanto, es una buena práctica usar restricciones de comodines para limitar la coincidencia de comodines. Consulte “Restricción de comodines para evitar subdirectorios y/o puntos”, a continuación, para ver algunos ejemplos.

Algunos ejemplos de comodines

Ejecutar una regla en muchos archivos

Los comodines se pueden usar para ejecutar la misma regla simple en muchos archivos: ¡este es uno de los usos más simples y poderosos para la creación de serpientes!

Considere este Snakefile para comprimir muchos archivos:

rule all:
    input:
        "compressed/F3D141_S207_L001_R1_001.fastq.gz",
        "compressed/F3D141_S207_L001_R2_001.fastq.gz",
        "compressed/F3D142_S208_L001_R1_001.fastq.gz",
        "compressed/F3D142_S208_L001_R2_001.fastq.gz"

rule gzip_file:
    input:
        "original/"
    output:
        "compressed/.gz"
    shell:
        "gzip -c  > "

Este Snakefile especifica una lista de archivos comprimidos que quiere producir y se basa en comodines para hacer la coincidencia de patrones requerida para encontrar los archivos de entrada y completar el bloque de shell.

Habiendo dicho eso, este Snakefile es inconveniente de escribir y es algo propenso a errores:

  • escribir los archivos individualmente es molesto si tiene muchos de ellos.
  • para generar la lista de archivos, debe cambiarles el nombre a mano, ¡lo cual es propenso a errores!

Snakemake proporciona varias funciones que pueden ayudar con estos problemas. Puede cargar la lista de archivos desde un archivo de texto o una hoja de cálculo, u obtener la lista directamente desde el directorio usando glob_wildcards; y puedes usar expand para cambiarles el nombre de forma masiva. ¡Sigue leyendo para ver algunos ejemplos!

¿Por qué usar snakemake aquí?

Es posible realizar la misma tarea utilizando gzip -k original/*aunque también tendría que mover los archivos a su ubicación final.

como se usa gzip -k original/* diferente de usar snakemake? ¿Y es mejor?

Primero, si bien los resultados no son diferentes, ambos enfoques comprimirán el conjunto de archivos de entrada, ¡que es lo que desea! – el gzip
-k
el comando se ejecuta en de serie y no entrará paralelo – es decir, gzip por defecto comprimirá un archivo a la vez. El Snakefile ejecutará la regla gzip_file en paraleloutilizando tantos procesadores como especifique con -j. Eso significa que si tuviera muchos, muchos archivos de este tipo, ¡un problema común en bioinformática! – la serpiente La versión podría ejecutarse muchas veces más rápido.

En segundo lugar, especificar muchos archivos en la línea de comandos con gzip -k
original/*
funciona con gzip pero no con cada comando de shell. Algunos comandos solo se ejecutan en un archivo a la vez; gzip simplemente funciona si le das uno o varios archivos. Muchos otros programas no funcionan en múltiples archivos de entrada; por ejemplo, el fastp El programa para preprocesar archivos FASTQ se ejecuta en un conjunto de datos a la vez. (También vale la pena mencionar que snakemake le brinda una manera flexible de escribir líneas de comando personalizadas; más sobre eso más adelante).

En tercer lugar, en Snakefile estamos siendo explícitos sobre qué archivos esperamos que existan después de que se ejecuten las reglas, mientras que si solo ejecutáramos gzip -k
original/*
le estamos pidiendo al shell que comprima cada archivo en
original/. Si borramos accidentalmente un archivo en el original
subdirectorio, entonces gzip no lo sabría y no se quejaría, pero snakemake sí. Este es un tema que aparecerá repetidamente: a menudo es más seguro ser realmente explícito sobre qué archivos espera, para que pueda recibir alertas sobre posibles errores.

Y, en cuarto lugar, el enfoque de Snakefile le permitirá cambiar el nombre de los archivos de salida de formas interesantes, con gzip -k original/*, estás atascado con los nombres de archivo originales. ¡Esta es una característica que exploraremos en la siguiente subsección!

Renombrar archivos por prefijo usando glob_wildcards

Considere un conjunto de archivos llamados así:

F3D141_S207_L001_R1_001.fastq
F3D141_S207_L001_R2_001.fastq

dentro de original/ subdirectorio.

Ahora suponga que desea cambiarles el nombre a todos para deshacerse del _001 sufijo antes .fastq. ¡Esto es muy fácil con comodines!

Los siguientes usos de Snakefile glob_wildcards para cargar una lista de archivos de un directorio y luego hacer una copia de ellos con el nuevo nombre debajo del
renamed/ subdirectorio. Aquí, glob_wildcards extrae el
patrón de el conjunto de archivos disponibles en el directorio:

# first, find matches to filenames of this form:
files = glob_wildcards("original/_001.fastq")

# next, specify the form of the name you want:
rule all:
    input:
        expand("renamed/.fastq", sample=files.sample)

# finally, give snakemake a recipe for going from inputs to outputs.
rule rename:
    input:
        "original/_001.fastq",
    output:
        "renamed/.fastq"
    shell:
        "cp  "

Este Snakefile también hace uso de expand para reescribir la lista cargada en el conjunto deseado de nombres de archivo. Esto significa que ya no tenemos que escribir la lista de archivos nosotros mismos; podemos dejar que Snakemake lo haga con expand!

Tenga en cuenta que aquí podría hacer un mv en lugar de un cp y luego
glob_wildcards ya no recogería los archivos modificados después de ejecutarse.

Este Snakefile carga la lista de archivos desde el propio directorio, lo que significa que si un archivo de entrada se elimina accidentalmente, SnakeMake no se quejará. Al cambiar el nombre de los archivos, es poco probable que esto cause problemas; sin embargo, al ejecutar flujos de trabajo, recomendamos cargar la lista de muestras desde un archivo de texto o una hoja de cálculo para evitar problemas.

También tenga en cuenta que este Snakefile encontrará y cambiará el nombre de todos los archivos en
original/ ¡así como cualquier subdirectorio! Esto es porque
glob_wildcards por defecto incluye todos los subdirectorios. Consulte la siguiente sección a continuación para ver cómo usar restricciones de comodín para evitar la carga desde subdirectorios.

Restricción de comodines para evitar subdirectorios y/o puntos

Los comodines coinciden con cualquier cadena, incluido ‘/’, etc. glob_wildcards
buscará automáticamente los archivos en los subdirectorios y también los “estirará” para que coincidan con los delimitadores comunes en los nombres de archivo, como ‘.’ y ‘-‘. Esto se conoce comúnmente como “coincidencia codiciosa” y significa que a veces sus comodines coincidirán con mucho más nombre de archivo de lo que desea. Puede limitar las coincidencias de comodines mediante restricciones de comodines.

A continuación se muestran dos restricciones comodín comunes, por separado y en combinación. La primera restricción evita archivos en subdirectorios y la segunda restricción evita puntos.

# match all .txt files - no constraints
all_files = glob_wildcards(".txt").filename

# match all .txt files in this directory only - avoid /
this_dir_files = glob_wildcards(".txt").filename

# match all files with only a single period in their name - avoid .
prefix_only = glob_wildcards(".txt").filename

# match all files in this directory with only a single period in their name
# avoid / and .
prefix_and_dir_only = glob_wildcards(".txt").filename

Consulte las restricciones de comodines para obtener más información y detalles.

Ejemplos de comodines avanzados

Renombrar archivos usando múltiples comodines

El primer ejemplo de cambio de nombre anterior funciona muy bien cuando desea cambiar solo el sufijo de un archivo y puede usar un solo comodín, pero si desea hacer un cambio de nombre más complicado, es posible que deba usar varios comodines.

Considere la situación en la que desea cambiar el nombre de los archivos de la forma de
F3D141_S207_L001_R1_001.fastq a F3D141_S207_R1.fastq. Desafortunadamente, no puede hacer eso con un solo comodín, pero puede usar dos, así:

# first, find matches to filenames of this form:
files = glob_wildcards("original/_L001__001.fastq")

# next, specify the form of the name you want:
rule all:
    input:
        expand("renamed/_.fastq", zip,
               sample=files.sample, r=files.r)

# finally, give snakemake a recipe for going from inputs to outputs.
rule rename:
    input:
        "original/_L001__001.fastq",
    output:
        "renamed/_.fastq"
    shell:
        "cp  "

Estamos haciendo uso de tres características nuevas en este código:

Primero, glob_wildcards coincide con varios comodines y coloca los valores resultantes en una única variable de resultado (aquí, files).

En segundo lugar, los valores coincidentes se colocan en dos listas ordenadas,
files.sample y files.rde modo que los valores extraídos de los nombres de archivo coincidan en pares.

En tercer lugar, cuando usamos expandle pedimos que “comprima” las dos listas de comodines juntas, en lugar del valor predeterminado, que es hacer todas las combinaciones posibles con product.

Además, al igual que con el ejemplo anterior, este Snakefile encontrará y cambiará el nombre de todos los archivos en original/ ¡así como cualquier subdirectorio!

Enlaces:

Mezclar y combinar cuerdas

Una consecuencia un tanto no intuitiva (pero también muy útil) de que los comodines sean locales para las reglas es que puede hacer coincidencias de cadenas inteligentes para mezclar y combinar reglas genéricas con reglas más específicas.

Considere este Snakefile, en el que estamos mapeando lecturas de múltiples muestras a múltiples referencias (regla map_reads_to_reference), así como convertir archivos SAM a BAM:

rule all:
    input:
        "sample1.x.ecoli.bam",
        "sample2.x.shewanella.bam",
        "sample1.x.shewanella.bam"

rule map_reads_to_reference:
    input:
        reads=".fq",
        reference=".fa",
    output:
        ".x..sam"
    shell: "minimap2 -ax sr   > "

rule convert_sam_to_bam:
    input:
        ".sam"
    output:
        ".bam"
    shell: "samtools view -b  -o 

¡Aquí, Snakemake está felizmente usando diferentes comodines en cada regla y combinándolos con diferentes partes del patrón! Entonces,

  • Regla convert_sam_to_bam convertirá genéricamente cualquier archivo SAM en un archivo BAM basado únicamente en el .bam y .sam sufijos

  • Sin embargo, map_reads_to_references solo producirá archivos de mapeo que coincidan con el patrón de .x.que a su vez dependen de la existencia de .fa y .fastq.

Esto funciona porque, en última instancia, Snakemake solo está emparejando cadenas y no “sabe” nada sobre la estructura de las cadenas que está emparejando. Y tampoco recuerda los comodines en las reglas. Por lo tanto, ¡Snakemake coincidirá felizmente con un conjunto de comodines en una regla y con un conjunto diferente de comodines en otra regla!

Uso de comodines para determinar los parámetros que se utilizarán en el bloque de shell.

También puede usar comodines para crear reglas que produzcan archivos de salida donde los parámetros utilizados para generar los contenidos se basan en el nombre del archivo; por ejemplo, considere este ejemplo de generación de subconjuntos de archivos FASTQ:

rule all:
    input:
        "big.subset100.fastq"

rule subset:
    input:
        "big.fastq"
    output:
        "big.subset.fastq"
    shell: """
        head -  > 
    """

Aquí, el comodín es solo en el nombre del archivo de salida, no en el nombre del archivo de entrada. Snakemake utiliza el valor comodín para determinar cómo completar el número de líneas para head para seleccionar del archivo!

Esto puede ser realmente útil para generar archivos con muchos parámetros diferentes para un comando de shell en particular: “barridos de parámetros”. Más sobre esto más adelante.

Cómo pensar en los comodines

Comodines (junto con expand y glob_wildcards) son quizás la característica más poderosa de snakemake: permiten la aplicación genérica de reglas a un número arbitrario de archivos, basándose completamente en patrones simples.

Sin embargo, ¡con ese poder viene un poco de complejidad!

En última instancia, los comodines tienen que ver con instrumentos de cuerda y patrones. Snakemake utiliza la coincidencia de patrones para extraer patrones de los archivos de salida deseados y luego completa esas coincidencias en otras partes de la regla. La mayor parte de la complejidad resultante proviene de evitar la ambigüedad en la combinación y el relleno de patrones, junto con el desafío combinado de construir todos los nombres de los archivos que realmente desea crear.

Referencias adicionales

Ver también: el
documentos de snakemake en comodines.

Fuente del artículo

Deja un comentario