Snakemake es un sistema de gestión de flujos de trabajo (workflow management) que te permite crear pipelines reproducibles y escalables. Utiliza una sintaxis basada en Python y trabaja con reglas que definen cómo transformar archivos de entrada en archivos de salida.
Ventajas principales:
# Con conda (recomendado)
conda install -c bioconda snakemake
# Con pip
pip install snakemake
# Verificar instalación
snakemake --version
Crea un archivo Snakefile
:
rule saludo:
output:
"saludo.txt"
shell:
"echo 'Hola desde Snakemake!' > {output}"
Ejecutar:
snakemake -c1
Conceptos clave:
rule
: define una tareaoutput
: archivo(s) que se generanshell
: comando a ejecutar{output}
: wildcard que se reemplaza por el nombre del
archivorule copiar_archivo:
input:
"datos_originales.txt"
output:
"datos_copia.txt"
shell:
"cp {input} {output}"
Primero crea el archivo de entrada:
echo "Datos de prueba" > datos_originales.txt
snakemake -c1
rule crear_datos:
output:
"datos.txt"
shell:
"echo 'linea1\nlinea2\nlinea3' > {output}"
rule contar_lineas:
input:
"datos.txt"
output:
"conteo.txt"
shell:
"wc -l {input} > {output}"
rule all:
input:
"conteo.txt"
La regla all
: Define el objetivo final.
Snakemake trabaja hacia atrás para determinar qué ejecutar.
Procesa múltiples archivos con una sola regla:
MUESTRAS = ["muestra1", "muestra2", "muestra3"]
rule all:
input:
expand("resultados/{muestra}_procesado.txt", muestra=MUESTRAS)
rule procesar:
input:
"datos/{muestra}.txt"
output:
"resultados/{muestra}_procesado.txt"
shell:
"cat {input} | tr '[:lower:]' '[:upper:]' > {output}"
Crea los archivos de entrada:
mkdir -p datos
echo "texto minúscula" > datos/muestra1.txt
echo "otro texto" > datos/muestra2.txt
echo "más datos" > datos/muestra3.txt
Conceptos: - {muestra}
: wildcard que
toma diferentes valores - expand()
: genera listas de
archivos
rule analizar_datos:
input:
"datos/{muestra}.txt"
output:
"analisis/{muestra}_stats.txt"
params:
min_length=5
run:
with open(input[0]) as f_in, open(output[0], 'w') as f_out:
lines = f_in.readlines()
f_out.write(f"Total líneas: {len(lines)}\n")
f_out.write(f"Parámetro min_length: {params.min_length}\n")
Bloques run:
permiten código Python
directamente en la regla.
Snakefile:
rule procesar_con_script:
input:
"datos/{muestra}.csv"
output:
"resultados/{muestra}_limpio.csv"
script:
"scripts/limpiar_datos.py"
scripts/limpiar_datos.py:
import pandas as pd
# Snakemake proporciona objetos 'snakemake'
df = pd.read_csv(snakemake.input[0])
df_limpio = df.dropna()
df_limpio.to_csv(snakemake.output[0], index=False)
config.yaml:
muestras:
- muestra1
- muestra2
- muestra3
parametros:
umbral: 0.05
iteraciones: 1000
Snakefile:
configfile: "config.yaml"
rule all:
input:
expand("resultados/{muestra}.txt", muestra=config["muestras"])
rule analizar:
input:
"datos/{muestra}.txt"
output:
"resultados/{muestra}.txt"
params:
umbral=config["parametros"]["umbral"]
shell:
"echo 'Umbral: {params.umbral}' > {output}"
Cuando el input depende de wildcards de forma compleja:
def obtener_archivos_input(wildcards):
if wildcards.tipo == "completo":
return ["datos/parte1.txt", "datos/parte2.txt"]
else:
return ["datos/parte1.txt"]
rule procesar_dinamico:
input:
obtener_archivos_input
output:
"resultados/{tipo}_resultado.txt"
shell:
"cat {input} > {output}"
Para cuando no sabes los outputs hasta ejecutar un paso:
checkpoint dividir_datos:
input:
"datos_grandes.txt"
output:
directory("chunks/")
shell:
"""
mkdir -p chunks
split -l 100 {input} chunks/chunk_
"""
def agregar_chunks(wildcards):
checkpoint_output = checkpoints.dividir_datos.get(**wildcards).output[0]
chunks = glob.glob(f"{checkpoint_output}/chunk_*")
return expand("procesados/{chunk}_proc.txt",
chunk=[os.path.basename(c) for c in chunks])
rule procesar_chunk:
input:
"chunks/{chunk}"
output:
"procesados/{chunk}_proc.txt"
shell:
"wc -l {input} > {output}"
rule all:
input:
agregar_chunks
rule tarea_pesada:
input:
"input.txt"
output:
"output.txt"
threads: 4
resources:
mem_mb=4000,
runtime=120 # minutos
priority: 50
shell:
"mi_programa --threads {threads} {input} {output}"
Ejecutar con límites:
snakemake --cores 8 --resources mem_mb=16000
rule analisis_r:
input:
"datos.csv"
output:
"grafico.pdf"
conda:
"envs/r_ambiente.yaml"
shell:
"Rscript scripts/graficar.R {input} {output}"
envs/r_ambiente.yaml:
channels:
- conda-forge
- r
dependencies:
- r-base=4.2
- r-ggplot2
- r-dplyr
Ejecutar:
snakemake --use-conda --cores 4
Organiza workflows grandes en módulos:
Snakefile:
module analisis:
snakefile: "modules/analisis.smk"
config: config
use rule * from analisis as analisis_*
rule all:
input:
rules.analisis_reporte_final.output
rule paso_intermedio:
input:
"input.txt"
output:
temp("temporal.txt") # Se borrará automáticamente
shell:
"procesar {input} > {output}"
rule resultado_final:
input:
"temporal.txt"
output:
protected("resultado_final.txt") # No se puede sobrescribir
shell:
"finalizar {input} > {output}"
proyecto/
├── Snakefile
├── config.yaml
├── envs/
│ ├── python_env.yaml
│ └── r_env.yaml
├── scripts/
│ ├── preprocesar.py
│ └── analizar.R
├── rules/
│ ├── control_calidad.smk
│ └── analisis.smk
├── datos/
│ └── muestras/
└── resultados/
├── qc/
└── figuras/
rule con_logs:
input:
"input.txt"
output:
"output.txt"
log:
"logs/{rule}.log"
benchmark:
"benchmarks/{rule}.txt"
shell:
"(mi_comando {input} > {output}) 2> {log}"
from snakemake.utils import validate
configfile: "config.yaml"
validate(config, schema="schemas/config.schema.yaml")
# schemas/config.schema.yaml (formato JSON Schema)
# Ver qué se ejecutará sin ejecutar
snakemake -n
# Ver el grafo de dependencias
snakemake --dag | dot -Tpdf > dag.pdf
# Reporte HTML interactivo
snakemake --report report.html
Crea un workflow que:
Construye un pipeline que:
Desarrolla un workflow que:
# Ejecución básica
snakemake --cores 4
# Dry-run (ver qué se ejecutará)
snakemake -n
# Forzar re-ejecución de una regla
snakemake -R nombre_regla
# Limpiar outputs
snakemake --delete-all-output
# Desbloquear directorio (si hubo error)
snakemake --unlock
# Ejecutar regla específica
snakemake nombre_archivo_output
# Modo detallado
snakemake -p --verbose
# Con perfilado
snakemake --profile mi_perfil/
¡Buena suerte con tu aprendizaje de Snakemake!