我目前有在配置文件中的字典帮助下基于模式匹配使用 snakemake 重命名某些文件的问题。
input
通配符之后不再与 output
通配符匹配。数据遵循以下结构:
.
├── pool1
│ ├── name_A.txt
│ ├── name_B.txt
│ ├── name_C.txt
│ └── name_D.txt
└── pool2
├── name_E.txt
├── name_F.txt
├── name_G.txt
└── name_H.txt
我想将它们重命名为基于文件名的子模式。在这种情况下,大写字母应替换为数字,而不同的池可以“编码”相同的数字。
.
├── pool1
│ ├── name_1.txt
│ ├── name_2.txt
│ ├── name_3.txt
│ └── name_4.txt
└── pool2
├── name_2.txt
├── name_3.txt
├── name_5.txt
└── name_6.txt
每个池的替换存储在配置文件中,如下所示:
pools=['pool1','pool2']
c2n : [{'A':'1',
'B':'2',
'C':'3',
'D':'4'},
{'E':'2',
'F':'3',
'G':'5',
'H':'6'}]
不幸的是 rule all from snakemake 没有找到重命名的输出文件。这些列表是在
rule all
之前根据配置文件使用嵌套 for 循环创建的。
rename_in=['pool1/name_A','pool1/name_B','pool1/name_C','pool1/name_D','pool2/name_E','pool2/name_F','pool2/name_G','pool2/name_H']
rename_out=['pool1/name_1','pool1/name_2','pool1/name_3','pool1/name_4','pool2/name_2','pool2/name_3','pool2/name_5','pool2/name_6']
rule all:
input:
# rename.smk
expand("{pattern}.txt", pattern=rename_out)
for l, n in zip(rename_in, rename_out):
rule:
input:
f"{l}.txt"
output:
f"{n}.txt"
shell:
"mv {input} {output}"
rule rename:
input:
"pool1/name_{l}.txt"
output:
"pool1/name_{config[c2n][l]}.txt"
shell:
"mv {input} {output}"
mv
命令的子进程,但是 rule all
仍然无法正确识别输出。Snakemake 有没有聪明又简单的重命名文件的方法?在最佳世界中,这将基于池动态发生,但在这一点上我很好地让它以某种方式工作。 到目前为止,我一直在尝试绕过检查点,因为一开始这对我来说似乎是一个简单的问题。 我发现了一些与我类似的问题,但都没有更改输入和输出中的通配符。 提前致谢 (:
rule all
您说,“这些列表是在根据配置文件全部规则之前使用嵌套 for 循环创建的。”使用下面的示例代码,您只需将
input
更改为 rule all
即可成为列表 rename_out
.
rule all:
input:
rename_out
我认为你的 zip 想法是正确的。我将它嵌入到规则中。
这是一个在您提供的情况下有效的示例,将它们放在一起:
from shutil import move
import os
import glob
rename_in=['pool1/name_A','pool1/name_B','pool1/name_C','pool1/name_D','pool2/name_E','pool2/name_F','pool2/name_G','pool2/name_H']
rename_out=['pool1/name_1','pool1/name_2','pool1/name_3','pool1/name_4','pool2/name_2','pool2/name_3','pool2/name_5','pool2/name_6']
rule all:
input:
rename_out
rule rename_files:
input:
[path for path in rename_in if os.path.exists(path)]
output:
[rename_out[indx] for indx,path in enumerate(rename_in) if os.path.exists(path)]
run:
for f_in,f_out in zip(rename_in, rename_out):
if f_in in glob.glob(f"{f_in.split('/')[0]}/*"):
move(f_in, f_out)
注意,为了让 snakemake 稍后处理文件状态的微小变化,整个列表不会用作执行繁重工作的规则的输入和输出。当使用整个列表作为主要规则的输入和输出时,在从第一个方块开始时有效。如果在那种情况下你将一个文件恢复为原始名称,它会破坏工作流程,因为 snakemake 评估事情并说整个输出列表已过时并擦除所有涉及的文件以准备重新制作它们。 (事实上 ,如果该目录完全变空,它甚至会清除这些文件所在的目录。)。
Bu加上只涉及尚未重命名为
input
的文件和output
中的rename_files
规则中的相应文件,你会看到你可以将原始名称恢复为一个或几个并重新- 运行工作流程,snakemake 将只处理重命名这些文件,而保留在第一轮中重命名的其他文件不变。 snakemake 的一大优势在于它可以跟踪工作流程中必须完成的所有工作,因此您不想失去这种能力。因为否则你可以直接使用 Python。
这充分利用了 Snakemake 作为 Python 超集的优势。将
rename_files
中使用的一些代码放在上下文中以获得更多解释:
rename_files
规则的列表推导式建立在此代码使文件的子集列表存在于可能更大的文件列表中.split()
从名称中获取池特定目录来处理字符串。这就是 f_in.split('/')[0]
部分正在做的事情。)