Snakemake 公式 | Snakemake GitHub
Snakemake は、GNU Make のようなタスクランナーの一つです。ファイルの依存関係をシンプルに書きつつ、Python で好きな処理がかけるのが魅力です。
ルールの書き方
rule all:
input: "output-A.txt"
rule hoge:
input: "input-{sample}.txt"
output: "output-{sample}.txt"
shell: "myscript.sh {input} > {output}"
| パラメータ | 説明 |
|---|---|
| input: | 入力ファイルの指定。{sample} 等でワイルドカードを指定できる。 |
| output: | 出力ファイルの指定。input: の指定したワイルドカードを使うことができる。 |
| shell: | 実行するコマンド。{input}, {output} などを利用可。 |
| run: | 実行するPythonコード。shell: と run: は同時に指定できない。 |
その他のパラメータ: params:, log:, benchmark:, message:, threads:, resources:, version:,
リファレンス
定義済み変数
input: 以外のパラメータでは {input}, {output} などとして定義済み変数にアクセスできる。トップレベルのコード部や run: パラメータでは、通常の変数としてアクセス可。
| 変数 | 説明 |
|---|---|
| {input} |
input:に対応するファイル、またはファイル群(スペース区切り) |
| {output} |
output:に対応するファイル、またはファイル群(スペース区切り) |
| {wildcards.*} |
input:, output: で指定したワイルドカードの集まり。 |
| {params.*} |
params: で設定した文字列の集まり。 |
| {rules.*} | 定義された rule: の集まり。 |
| {checkpoints.*} | 定義された checkpoint: の集まり。 |
| {config} |
configfile: で読み込んだファイルの設定。 |
| {rule} | ( shell:, run: のみアクセス可。)現在のルール名(str) |
{.*} となっている箇所は、{wildcards.sample}等、属性に個々のアイテム名を指定する。
input: では {hoge} とした部分はすべてワイルドカード定義として扱われる。
定義済みトップレベル要素
rule: 以外にも、下記の要素を定義することができます。その他、通常の Python コードを記述することが可能です。
| 要素 | 説明 |
|---|---|
| rule: | ルール指定(前述) |
| checkpoint: | 特殊なルール指定(使い方は後述) |
| configfile: | YAML 形式の外部変数定義を読み込む。 |
| include: | 他の Snakefile を取り込む |
| workdir: | カレントディレクトリを指定 |
| subworkflow: | (未調査) |
定義済み関数(抜粋)
| 関数 | 説明 |
|---|---|
| expand | wildcard を展開した結果の str のリストを返す。最終成果物のリストの生成などで頻繁に使うことになる(はず)。 |
| glob_wildcards | ファイル名探索をする glob のワイルドカード版。得られるのが、ファイル名ではなく、ワイルドカードであることに注意。(普通にファイル名の一覧が必要であれば標準ライブラリ(`glob.glob`等)を普通に使える) |
| touch | output: セクションで使用。処理完了後に touch で指定されたファイルの更新時刻を更新する。 |
| directory | output: セクションで使用。出力先としてディレクトリを指定するときに使用。参考 |
| temp | output: セクションで使用。引数で指定されたファイルは、ジョブ成功時でも削除される。 |
| protected | output: セクションで使用。引数で指定されたファイルは、ジョブ失敗時にも削除されない。 |
| remote | input:, output: セクションで使用。詳細は別ページで説明予定 |
ワイルドカードの書式
| 書式 | 説明 |
|---|---|
| {sample} | デフォルト。正規表現としては .+ が指定されたのと同じ |
| {sample,[A-Z]+} |
,の後ろにワイルドカードがマッチする正規表現を指定可能 |
| {sample:02d} | Python標準のフォーマット指定も利用可 |
| {sample:q} | 文字列をクォートする |
コマンドラインオプション
| オプション | 説明 |
|---|---|
| -n, --dryrun | dryrun |
| -p, --printshellcmds | 実行したコマンドを標準出力に出す(デフォルトでは出ない) |
| -f, --force | 依存関係を無視して強制実行する |
| -R [TARGET, TARGET, ...], --forcerun [TARGET, TARGET, ...] |
TARGET 以降のルール(TARGET と、TARGET に依存しているルール)を再実行する |
| -U TARGET[, TARGET, ...], --until TARGET[, TARGET, ...] |
TARGET 以前のルール (TARGET が依存しているルール) を再実行する |
| -s filename, --snakefile filename | Snakefile を指定 |
| -d, --directory | ワーキングディレクトリを指定 |
| -l, --list | Snakefile の rule 一覧を出力する |
| --lt, --list-target-files | rule のうち、snakemake RULE として指定可能なルール (=ルールにwildcardを含まないもの) を出力する。なお、-lt とすると、-l, -t(--touch) と解釈され、--lt とはならないので注意。 |
| -t, --touch |
outputのファイルの更新時間だけを更新し、コマンドを実行しない。output のファイルがない場合には何も起こらないことに注意(空ファイルが作成されたりはしない) |
| -k, --keep-going | 途中でエラーが発生しても、実行可能なジョブは実行する(デフォルトはエラー発生次第、即座に止まる) |
定番の書き方
default ターゲット
ターゲット指定が省略された場合、Make と同じく一番上の rule がターゲットとして指定された扱いになる。
input: に、最終的に生成されるファイルを指定することで、必要な依存関係をたどって生成に必要な rule: 群が実行される。
rule all:
input: "final-result.txt"
分析の途中から再実行
ワイルドカード付きのルールを再実行したい場合、-R (--forcerun) オプションを使います。
% snakemake -R step2 all
最終的にワイルドカードを展開しているルールを指定しつつ、 -R オプションで再実行するターゲットを指定します。
単に -f オプションで指定すると、ワイルドカードの展開ができずエラーになります。
% snakemake -f step2
Building DAG of jobs...
WorkflowError:
Target rules may not contain wildcards. Please specify concrete files or a rule without wildcards.
参考 Can SnakeMake be forced to rerun rules when files are missing - Stack Overflow
分析の特定ステップだけを再実行
先程の例は step2 以降を再実行でしたが、step2 だけを再実行したい場合はどうでしょうか。その場合は -U オプションを利用します。
% snakemake -R step2 -U step2 all
ちょうど -R で指定したターゲットから、-Uで指定したターゲットまでが実行されます。両方に同じターゲットを指定すると、そのターゲットだけが実行されるようになります。
.env の読み込み
Snakefile には通常の Python スクリプトを書けますので1、たとえば pip install python-dotenv を実行しておいて、Snakefile に
from dotenv import load_dotenv
load_dotenv()
# 以後、通常のルール記述
rule all:
input: ...
などと書けばOKです。
(逆にいえば、snakemake 標準では .env の読み込み機能は提供されていない模様。)
input: パラメータに変数の値を指定する
var_a = 'some_text'
rule hoge:
input: "{var_a}"
などと書いても、{var_a} というワイルドカードを定義したことになり、変数の値は入りません。変数の値をいれるためには、例えば下記の方法があります。
-
input: f'{var_a}'とする。(ワイルドカードを使う場合はf'{var_a}-{{wc_a}}'とワイルドカード側を{{}}とする。) -
input: expand('{var_a}', var_a=var_a)として、ワイルドカード展開を利用する
-
正確には「ルール記述が通常の Python 関数に置き換えられて、Python スクリプトとして実行される」 ↩