Snakemake如何根据wildcard值选择执行对应规则?
解决Snakemake中物种分支执行及公共预处理重复问题
针对你遇到的问题,核心是要让公共预处理规则prepare_data仅在处理mouse或human时触发一次,同时避免其他物种的规则无意义地调用它。以下是几种可行的实现方案:
方案1:分组通配符+条件依赖(推荐)
通过明确拆分目标集,让mouse/human的处理规则依赖prepare_data,其他物种的规则直接独立执行。
步骤1:定义规则与依赖
# 限制species通配符的合法取值 wildcard_constraints: species=r"mouse|human|(?!mouse|human)\w+" # 公共预处理规则:无通配符,确保仅执行一次 rule prepare_data: output: "data/processed/ready_flag.txt" shell: """ # 这里编写公共预处理逻辑,如下载公共参考、初始化配置等 echo "Preprocessing done" > {output} """ # mouse/human专属处理规则:依赖prepare_data rule process_mouse_human: input: prep="data/processed/ready_flag.txt", raw_data="data/raw/{species}.fastq" output: "data/processed/{species}.bam" shell: """ # 编写mouse/human特有的处理流程,比如比对到特定参考基因组 samtools view -Sb {input.raw_data} > {output} """ # 其他物种处理规则:不依赖prepare_data rule process_other_animals: input: raw_data="data/raw/{species}.fastq" output: "data/processed/{species}.bam" shell: """ # 编写其他物种的专属处理逻辑 custom_animal_pipeline {input.raw_data} -o {output} """
步骤2:拆分目标集合
# 定义所有需要处理的物种列表 all_species = ["mouse", "human", "rat", "dog", "cat"] # 拆分mouse/human和其他物种的目标文件 mh_targets = expand("data/processed/{species}.bam", species=["mouse", "human"]) animal_targets = expand("data/processed/{species}.bam", species=[s for s in all_species if s not in ["mouse", "human"]]) # 总目标规则 rule all: input: mh_targets, animal_targets
运行时,Snakemake会自动识别:mouse/human的目标需要先执行prepare_data,再执行process_mouse_human;其他物种直接执行process_other_animals,不会触发prepare_data。
方案2:动态生成规则
如果需要为每个物种生成独立规则,可通过Python循环动态创建,精准控制依赖关系:
all_species = ["mouse", "human", "rat", "dog"] rule prepare_data: output: "data/processed/ready_flag.txt" shell: "echo 'Preprocessing done' > {output}" # 为mouse/human生成带prepare_data依赖的规则 for sp in ["mouse", "human"]: rule: name = f"process_{sp}" input: prep="data/processed/ready_flag.txt", raw=f"data/raw/{sp}.fastq" output: f"data/processed/{sp}.bam" shell: f"samtools view -Sb {input.raw} > {output}" # 为其他物种生成无依赖的规则 for sp in [s for s in all_species if s not in ["mouse", "human"]]: rule: name = f"process_{sp}" input: raw=f"data/raw/{sp}.fastq" output: f"data/processed/{sp}.bam" shell: f"custom_animal_pipeline {input.raw} -o {output}" rule all: input: expand("data/processed/{species}.bam", species=all_species)
这种方式适合每个物种的处理逻辑差异较大的场景,同时保证prepare_data仅被mouse/human的规则调用一次。
方案3:Checkpoint(适用于动态预处理输出)
如果prepare_data的输出是动态生成的(比如根据后续需求生成不同文件),可以用Checkpoint确保它仅执行一次:
checkpoint prepare_data: output: directory("data/processed/prep_output") shell: """ mkdir -p {output} echo 'Preprocessing done' > {output}/ready.txt # 其他动态预处理步骤 """ # 定义函数获取预处理输出,确保Checkpoint完成后才继续 def get_prep_input(wildcards): prep_dir = checkpoints.prepare_data.get_output()[0] return f"{prep_dir}/ready.txt" rule process_mouse_human: input: prep=get_prep_input, raw_data="data/raw/{species}.fastq" output: "data/processed/{species}.bam" shell: "samtools view -Sb {input.raw_data} > {output}" rule process_other_animals: input: raw_data="data/raw/{species}.fastq" output: "data/processed/{species}.bam" shell: "custom_animal_pipeline {input.raw_data} -o {output}" rule all: input: expand("data/processed/{species}.bam", species=["mouse", "human", "rat", "dog"])
Checkpoint会在所有依赖它的规则执行前完成,且仅执行一次,适合复杂的动态预处理场景。
内容的提问来源于stack exchange,提问作者dariober
相关产品推荐
相关产品推荐

