You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Snakemake RNA-seq管道按样本类型自动切换子流程

Handling Mixed Single-End and Paired-End RNA-seq Samples in a Single Snakemake Pipeline

Got it, let's break down how to solve this cleanly—no need to duplicate rules or run separate pipelines. The key is to leverage Snakemake's dynamic input/output functions and conditional logic to adapt to each sample's type, either via a config file or automatic file detection.

Option 1: Explicit Sample Type in Config File

This is straightforward if you know your sample types upfront. Start by defining sample types in your config.yaml:

samples:
  sample_A: SE
  sample_B: PE
  sample_C: SE

Step 1: Write Helper Functions for Input/Output

Create reusable functions to fetch the correct files for SE/PE samples. Add these to your Snakefile:

def get_raw_input(wildcards):
    sample_type = config["samples"][wildcards.sample]
    if sample_type == "SE":
        return f"data/raw/{wildcards.sample}.fastq.gz"
    else:
        return [
            f"data/raw/{wildcards.sample}_R1.fastq.gz",
            f"data/raw/{wildcards.sample}_R2.fastq.gz"
        ]

def get_qc_output(wildcards):
    sample_type = config["samples"][wildcards.sample]
    if sample_type == "SE":
        return f"data/qc/{wildcards.sample}_qc.fastq.gz"
    else:
        return [
            f"data/qc/{wildcards.sample}_R1_qc.fastq.gz",
            f"data/qc/{wildcards.sample}_R2_qc.fastq.gz"
        ]

Step 2: Build Universal Rules (No Duplication!)

Instead of writing separate rules for SE/PE, use a single rule that adapts its command based on input count. For example, a quality control rule:

rule quality_control:
    input:
        get_raw_input
    output:
        get_qc_output
    params:
        cmd_flags = lambda wildcards, input, output: (
            f"-i {input} -o {output}" if len(input) == 1
            else f"-i1 {input[0]} -i2 {input[1]} -o1 {output[0]} -o2 {output[1]}"
        )
    shell:
        """
        somecommand {params.cmd_flags}
        """

Step 3: Merge to Single Output

For the merging step, write another helper function to fetch QC outputs, then build a rule that handles both cases:

def get_merge_input(wildcards):
    sample_type = config["samples"][wildcards.sample]
    if sample_type == "SE":
        return f"data/qc/{wildcards.sample}_qc.fastq.gz"
    else:
        return [
            f"data/qc/{wildcards.sample}_R1_qc.fastq.gz",
            f"data/qc/{wildcards.sample}_R2_qc.fastq.gz"
        ]
rule merge_to_single_output:
    input:
        get_merge_input
    output:
        f"data/merged/{wildcards.sample}_final.bam"
    shell:
        """
        if [ {len(input)} -eq 1 ]; then
            # SE case: process single file to merged output
            star --readFilesIn {input} --outFileNamePrefix data/merged/{wildcards.sample}_
        else
            # PE case: process paired files to single merged BAM
            star --readFilesIn {input[0]} {input[1]} --outFileNamePrefix data/merged/{wildcards.sample}_
        fi
        mv data/merged/{wildcards.sample}_Aligned.sortedByCoord.out.bam {output}
        """

Step 4: Define Final Targets

Use expand to generate targets for all samples:

rule all:
    input:
        expand("data/merged/{sample}_final.bam", sample=config["samples"].keys())

Option 2: Automatic Detection of Sample Type (No Config Needed)

If you don't know sample types upfront, use a checkpoint to run the download first, then auto-detect file counts to determine SE/PE.

Step 1: Checkpoint for Data Download

First, define a checkpoint to handle downloading (Snakemake will run this before resolving downstream rules):

checkpoint download_raw_data:
    output:
        directory("data/raw")
    shell:
        """
        # Your download command here (e.g., wget, sra-toolkit)
        # Ensure PE files follow a consistent naming pattern like {sample}_R1.fastq.gz
        """

Step 2: Auto-Detect Samples and Types

Add functions to parse downloaded files and determine sample types:

import glob
import os

def get_all_samples():
    # Fetch output from the download checkpoint
    checkpoint_dir = checkpoints.download_raw_data.get_output()[0]
    # Extract unique sample names from file names
    samples = set()
    for file in glob.glob(os.path.join(checkpoint_dir, "*.fastq.gz")):
        # Adjust split logic to match your file naming convention
        sample_name = os.path.basename(file).split("_")[0]
        samples.add(sample_name)
    return sorted(samples)

def get_sample_files(wildcards):
    checkpoint_dir = checkpoints.download_raw_data.get_output()[0]
    return glob.glob(os.path.join(checkpoint_dir, f"{wildcards.sample}*.fastq.gz"))

def is_pe_sample(wildcards):
    return len(get_sample_files(wildcards)) == 2

Step 3: Adapt Rules to Auto-Detected Types

Rewrite your rules to use these auto-detection functions. For example:

rule quality_control:
    input:
        get_sample_files
    output:
        lambda wildcards: (
            f"data/qc/{wildcards.sample}_qc.fastq.gz" if not is_pe_sample(wildcards)
            else [
                f"data/qc/{wildcards.sample}_R1_qc.fastq.gz",
                f"data/qc/{wildcards.sample}_R2_qc.fastq.gz"
            ]
        )
    params:
        cmd_flags = lambda wildcards, input, output: (
            f"-i {input} -o {output}" if len(input) == 1
            else f"-i1 {input[0]} -i2 {input[1]} -o1 {output[0]} -o2 {output[1]}"
        )
    shell:
        """
        somecommand {params.cmd_flags}
        """

Step 4: Final Targets

Use the auto-detected sample list for your final rule:

rule all:
    input:
        expand("data/merged/{sample}_final.bam", sample=get_all_samples())

Key Tips to Avoid Headaches

  • Consistent Naming: Ensure PE files follow a predictable pattern (e.g., sample_R1.fastq.gz, sample_R2.fastq.gz) so detection functions work reliably.
  • Reuse Logic: Keep conditional logic in helper functions/params instead of shell scripts where possible—this makes the pipeline easier to maintain.
  • Test Incrementally: Test with one SE and one PE sample first to verify the logic works before scaling to full datasets.

内容的提问来源于stack exchange,提问作者athiebaut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 19:23:16