用 Ipython 可以把所有的步驟全部包成一份
Ipython
No more shell scripts
因為在生物資訊中,一個 pipeline 就會用到很多工具,所以當然除了跑工具的一堆 shell scripts 以外,還有處理資料的 python code,可是這樣子就會很亂。
但不並否認 command line 有時還蠻方便ㄉ,Ipython 提供了 Magic ,也就是在 code 裡面 每行的最前面都補上一個 !
就能執行 shell 。所以改寫 .sh 到 ipython 是非常容易的
原 download.sh
echo "Download yeast Reference fasta file"
mkdir -p Download
wget ftp://ftp.ensembl.org/pub/release-90/fasta/saccharomyces_cerevisiae/dna/Saccharomyces_cerevisiae.R64-1-1.dna.toplevel.fa.gz -O Download/yeast.fa.gz
變成 download.ipy
print("Download yeast Reference fasta file")
!mkdir -p Download
!wget ftp://ftp.ensembl.org/pub/release-90/fasta/saccharomyces_cerevisiae/dna/Saccharomyces_cerevisiae.R64-1-1.dna.toplevel.fa.gz -O Download/yeast.fa.gz
執行 ipython download.ipy
就能動了
當然用 popen
執行也可以,不過我覺得用 ipython 的 !
比較可讀,接下來你會看很多好處。
for loop 迴圈
當然,要多用一點 Python 很方便的功能,比如說 for if,相較於 bash 非常舒服。再加上 python 的 字串處理,awk cut grep sed 通通可以被取代
Python 還可以把資料都放在 Dictionary ,然後用 for 去 iterate 他,所以整份 code 看起來就很乾淨。
從下面的 code ,你可以發現更重要的事,變數被統一了。通通都是用 python f-string 的方式去呼叫,使用方式是 {VAR_NAME}
也是很簡潔。
Comment 註解
當然,每個步驟都應該放上註解,說明
- 做什麼
- Input Output 甚麼
- 那些參數 與其意義
剛好可以用 doc-string 來寫。剛剛的例子,可以改寫成這樣
MultiThreading
如果軟體開 Multithreading 那就直接下參數開,如果不能,那就我們自己 Multithreading,比如說每個檔每個檔下載很慢,我們可以同時一次全開(假設沒超過你本機的網路極限)
這是用 python 的好處之一,簡單的幾行就搞定ㄌ
除了用在 download,有些一個個跑的 sample 其實都可以改寫成同時跑,當然,條件是那個軟體沒有用到所有的 thread,不然沒有加速的效果
Logger 輸出目前資訊
使用 python logging 這個 default package 除了可以 output 在 console 外,你也可以設定 output 在檔案,使用方式如下
有興趣的話可以加 time tqdm 之類的 讓使用者更方便(當然包括自己)
pandas
pandas 是 python 一個處理 csv tsv 這種 DataFrame 一個很有用的套件,最簡單的使用方式,就可以解決 cut xx | sort
這種除了方便但閱讀性不高的寫法。
以下為常用讀取的方式(其實生物資訊的資料就常常是這些格式而已)
import pandas as pd
pd.read_csv(file_name) # read csv
pd.read_csv(file_name, sep='\t') # read tsv
pd.read_csv(file_name, header=None) # read csv without header
pd.read_csv(file_name, header=None, names=["column_name1", "column_name2"]) # read csv with custom header
以下為讀 blast format 6 並且做一些事情的範例
pandas 還有很多功能的,這個 example 只示範了 select filter sort append
。其實還有 pivot melt merge groupby
這些好用的功能ㄋ
Docker
docker 講簡單點是個虛擬環境(容器)的執行器,總之東西都幫你安裝好了,即使在不同機器直接 run 就對了
詳細介紹,可以參考這篇
- 找 image
先找到 Image(環境)的名字與版本,對生物資訊而言,可以去 biocontainer https://biocontainers.pro/#/registry 搜尋工具
2. 跑起來
比如說你想跑 blast,就搜尋 blast 然後找個你想要的版本(e.g. 2.9.0),跑起來就像這樣
docker run -it --rm -v $PWD:/app quay.io/biocontainers/blast:2.9.0--pl526he19e7b1_7 tblastx -help
3. 放進 Ipython
因為每次 docker 前面參數都很長,所以可以先用 alias , Image 的名字也另外放,這樣也就很簡潔
%alias dk docker run -it --rm -v $PWD:/app -w /app
image_blast = "quay.io/biocontainers/blast:2.9.0--pl526he19e7b1_7"
%dk {image_blast} \
tblastx -help
Naming 命名方式
對,就是一直加後綴,即使不用看 document 也知道你的檔案的順序(上圖就是 simlow 這個 sample name ,做了 trinity transabyss rnaspades 再分別做 kallisto rsem salmon transrate)
格式會像這樣 SampleName.method1.method2.FileFormat
,以 Read Mapping 為例,檔案名稱可以這樣命名 Sample.fq
-> Sample.trim.fq
-> Sample.trim.bam
-> Sample.trim.sorted.bam
-> Sample.trim.sorted.bai
(雖然如此,但是做完 trim 再 read-mapping 是常識,所以Sample.bam
其實就可以ㄌ)
Pipeline 流程 function
其實每個步驟都有三個子步驟
- 前處理: 準備工具
- 主程式: 對每個 Sample 跑一次
- (Optional) 後處理: 整理數據
以 Read-mapping 為例
- 下載工具,開新的資料夾,建造 index (e.g. kallisto index)
- 每個 Sample 跑 mapping (e.g. kallisto quant)
- 整合: 把 abundance 拿來比較之類的
所以在 code 中,也分成三個 function,如果懶一點,當然可以把全部寫在一起。
blastPre() # Prepare data for blast
blastRun() # blast for each sample
blastPost() # Merge the blast result into one file
Debug
第一,如果你把 function 切的越細,其實比較容易重跑,所以像 xxPre
我通常一次就成功,但常常 xxRun xxPost
會重跑很多次,基本上是資料處理的不好導致跑工具會 error
第二是,不要第一次就跑完所有的 Samples 這是很花時間的,所以在最前面的地方,原本是這樣
samples = list(download_url.keys())
你可以手動在最上面寫死,這樣你就只會跑一個 sample,這樣比較方便,而且呼叫函式的其他選項根本沒有變
samples = ['dog']
Json 交換格式
因為我把每個步驟分開跑,然而有時候步驟間需要傳遞一些資料,我的做法是把中間過程存起來,下個步驟要的話在讀取。可以存成
- csv 也就是 table 的長相
- json 比較有 structure 的格式 可以儲存數字、array、string、dictionary、null 都可以
Parameters
Arguments
通常會用 command line 的一些選項來給使用者改參數,畢竟沒有人想動 code 來改(而且容易改壞)
最常見的就是根據每個電腦不同,CPU 數不一樣,所以一定會有選項可以調。所以從原本的寫死的
thread=32
改成可以讀參數的 argparse (python default package) ,其實沒差多少行, 而且還附贈 help 給使用者去了解。
使用時也很簡單(不過因為 ipyhton 也會讀參數,所以用 --
來避免
$ ipython pipeline.ipy -- --thread=15
$ ipython pipeline.ipy # default thread=32
$ ipython pipeline.ipy -- --help
usage: pipeline.ipy [-h] [-t THREAD] [-m MEMORY]Pipeline of pipeline Demooptional arguments:
-h, --help show this help message and exit
-t THREAD, --thread THREAD
Threads
-m MEMORY, --memory MEMORY
Memory
yaml
如果你覺得弄成參數還是太亂,或許可以用檔案傳入,這個檔案格式為 yaml
一種很類似 json 格式的東西,但主打人可讀而且人也好寫入,如下圖
所以meta.yml
長這樣(yaml 會幫你認出那些是字串 所以不一定要加 "
)
download:
yeast: ftp://ftp.ensembl.org/pub/release-90/fasta/saccharomyces_cerevisiae/dna/Saccharomyces_cerevisiae.R64-1-1.dna.toplevel.fa.gz
dog: ftp://ftp.ensembl.org/pub/release-90/fasta/canis_familiaris/dna/Canis_familiaris.CanFam3.1.dna.toplevel.fa.gz
mouse: ftp://ftp.ensembl.org/pub/release-90/fasta/mus_musculus/dna/Mus_musculus.GRCm38.dna.toplevel.fa.gz
那ㄇ 剛剛的下載連結又更簡化拉
import yaml
meta = yaml.load(open("meta.yaml"), Loader=yaml.Loader)
download_url = meta['download']
把所有資料都丟到 yaml 檔去,這樣 code 就會更乾淨了,不過開發中的話,不用把資料分得這麼開。
Jupyter notebook
剛剛講的 Ipython 可以全部放在一個檔案,然後用 command line 執行 ipython pipeline.ipy
。當然,如果你想用更多介面也可以。Jupyter notebook 可以一個個區段的執行的 code ,然後把你的 outupt 全部儲存下來,不過要開網頁,有點麻煩。
我使用時通常會在 server 裡面開,所以參數要特別下 --no-broswer
,然後用 ssh reverse proxy 把 Local 的 port 8787 map 到 Remote 的 8787,就可以在你的本機瀏覽器上看 jupyter notebook ,這樣即使我電腦關機都沒關係,因為都在伺服器跑。
remote-machine$ jupyter notebook --no-browser --port 8787
local-machine$ ssh -L 8787:localhost:8787 REMOTE-IP -p SSH-PORT
local-machine$ firefox http://localhost:8787/?token=7b3db67aee5d4556c8xxx0
Notebook 存下了 run 每個 command 的 output(stdout and stderr)
完整的範例這裡
https://gist.github.com/linnil1/c4aba3746b8d8c167660bedd51ee0b6f
大概要跑 30 mins 需要 15G 空間
把學長的 paper 的 pipeline 整合,可以看我之前寫的這幾篇
看完覺得有幫助的話,按 claps 讚美作者ㄅ