使用 Ipython 建造生物資訊 pipeline

linnil1
13 min readSep 21, 2020

--

用 Ipython 可以把所有的步驟全部包成一份

Put everything in 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 註解

當然,每個步驟都應該放上註解,說明

  1. 做什麼
  2. Input Output 甚麼
  3. 那些參數 與其意義

剛好可以用 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 就對了

詳細介紹,可以參考這篇

  1. 找 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 命名方式

Copy from https://medium.com/@linnil1/reference-free-quantification-code-review-20d26aa14ab4

對,就是一直加後綴,即使不用看 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

其實每個步驟都有三個子步驟

  1. 前處理: 準備工具
  2. 主程式: 對每個 Sample 跑一次
  3. (Optional) 後處理: 整理數據

以 Read-mapping 為例

  1. 下載工具,開新的資料夾,建造 index (e.g. kallisto index)
  2. 每個 Sample 跑 mapping (e.g. kallisto quant)
  3. 整合: 把 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 格式的東西,但主打人可讀而且人也好寫入,如下圖

Copied from https://medium.com/@linnil1/reference-free-quantification-code-review-20d26aa14ab4

所以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 讚美作者ㄅ

--

--

linnil1
linnil1

Written by linnil1

目前做生物資訊與演算法,過去做過 Machine Vision(Deep learning),維護伺服器(k8s, docker),部分IOT(rpi, arduino)

No responses yet