這次 code review 背景是 學長這篇 Effect of de novo transcriptome assembly on transcript quantification
如果不了解原始論文在做什麼的,請先去看前篇
這篇是我第一個 code review 所以會從 0 開始講(應該)(結果沒有)
這個 paper 的 pipeline 長這樣,總共有 3x2x2x3x3=108 種組合,所以code 有可能會很混亂,但也因為如此,如果寫的整齊,是一個很好的範例。
說明
原始的 code:
我重新魔改的 code(本文使用):
首頁
首先要看說明 README
也就是進這個 github repo 第一個地方
非常重要,通常會寫怎麼跑 怎麼安裝 怎麼設定
一定要寫,務必要寫,而且要寫的精簡
系統工具安裝
我很推薦 docker,docker 講簡單點是個虛擬環境(容器)的執行器,你可以下載環境(Image),然後執行他,執行時你的環境(container) 是跟外界隔離的,所以:
- 資料不會髒掉,即使髒掉在重開新的環境就好ㄌ
- 你可以隨時使用不同的版本的環境
- 環境別人都包好了,所以通常直接使用就可以了,直接省去安裝步驟
- 你也可以包環境,避免妳自己也重現不出來自己的 code
Example: docker run -it --rm -v $PWD:/app docker.io/library/alpine ls /app
解釋一下,
-it
是 interactive--rm
是 執行完後刪除環境- 那執行什麼呢
ls /app
/app
是你把現在的資料夾(PWD) mount 進去環境裡面的位置,稱之 volume 所以是-v
,也只有 mount 進去的才能被改到,存在環境(container)的其他地方重開就不見了ls
是在docker.io/library/alpine
這個環境裡面的 script 這樣,假設library/alpine
這個環境你沒有,他會自動幫你下載
Python 部分
通常 Python 會把需要的套件都會放在一個叫 requirements.txt
的檔案裡,然後你就安裝 pip3 install -r requirments.txt
然後我蠻推薦 ipython 的 (Jupyter notebook 是 ipython 再把它弄成 web 介面這樣),ipython 我覺得最好用的功能是
- 有 python 功能,要操作複雜的字串處理就很簡單
- 執行 shell command 也很方便
根本就可以取代 shell script ㄌ,等等我們就會看到效果
Pipeline 部分
首先要做到的是 code 跟 meta 資料 分離,
meta 資料
我把東西放在 metadata/
裡面,比如說模擬的參數,還有一些設定
最主要的設定在 metadata/meta.yml
,yaml 是個很適合人類閱讀與編輯的類似 json格式
比如說,下面的 yaml 檔,我設定了有那些 species 與 species 的 reference 的 檔案在哪裡
又或者你設定該工具的 docker 版本(images 那排),與執行時的參數( trimmomatic 那行),這樣的話,檢查跟維護就很輕鬆
Pipeline code
首先我們用 argparser
把剩下的參數讀進來,比如說 threads memory
所以操作起來變成這樣: ipython3 pipeline.ipy --method=all -t 32
可以讓使用者輕鬆修改他想用的資源但不會動到 code (尤其是資料夾路徑)
最後一行我們就把 meta 資料讀進來
然後我們看看 ipython 的威力,用 assemble 這個操作為例(下圖)
- 用 python 的 function 包起來,然後用 docstring(就是那幾行註解),去說明這個做了什麼,input 什麼 output 什麼
- 可以在裡面 import 其他 python code,執行你想要的事情(
from xx import xx
那裏), 比如說這裡就是一個簡單的 code 把 contig < 500bp 的 contig 去掉 - 因為我們對 每個 species(e.g. yeast) 每個 dataset(e.g. simulation low, simulation high, …) 做 我們想要的 assemble 方式(e.g trinity) 所以用三個 for 迴圈
- 跟 shell code 只差一點,加個
!
就可以執行,重點是可以塞 python 變數(e.g.!mkdir -p {xx_folder}
) - 執行 docker,前面有定義 dk 是執行 docker 的 alias,把那段全部展開就是像這樣
docker run -it --rm -v $PWD:/app -w /app docker.io/trinityrnaseq/trinityrnaseq:2.11.0 Trinity --max_memory 300G --CPU 32 ...
就這樣 剩下的都差不多
總之這樣寫就全部都統一了,不會有東一個 .sh檔 西一個 .py 檔 而且變數名稱還可能不同
Connected-component 部分
先呼叫上篇的 pipeline 圖,其中最看不懂的可能是 for each segment 跟 for each sequence 這裡,我們就從 code 分析
先對每一個 local alignment 做 Threshold
再把每個 pair 丟進去 Match 這個 class,extend 完後 計算 Identity(其實就是 accuracy 跟 recovery)
Extend 做了什麼,其實就是把 Sequence Align 到的地方 給一個 identity
所以以上的 code 大概可以視覺化成這樣
最後 每個 sequence 的 recovery & coverage 如果 > 90 (整份 code 單位都是 %,單位要一致,才不會後面 debug 很辛苦) 就可以當作一個 edge ,然後我用 scipy 的 connected-component 直接拿到答案(原作者是自己寫)
其他
Dataframe
接下來的操作就是 pandas dataframe 的操作了
就像這樣
可以自己去看 code ,我盡量把 code 寫的簡單易懂ㄌ
命名
除了 function 的名字,檔案的命名也很重要,不然你還要翻 code 才會知道那個檔案再幹嘛
example
大家都是速食主義的,大家想看到的就是 code 能馬上動,
- 提供 example,本 repo 放在
example/
- 或者是是截圖成功的樣子,別人至少會認為你的東西能跑
- 包成一份環境,或者是包成一個 bin 檔之類的
結論
這份 code 我重寫了一個禮拜,看起來應該都沒有寫錯 但是
- 拜託寫註解
- code style 要統一
- function 的命名要合理
不然不會有人想看ㄉ 大家都很忙
最後
按 claps 好ㄇ
也可以順便按我的 code 跟學長的 code 一個 Star