PCR引物設計應該算是生物實驗基本技能吧,工具也非常多。Primer-BLAST、Primer Premier 都是比較經典的軟體,除此之外還有很多新的在線設計軟體,也很方便。不過今天不是要講怎麼用這些現成軟體來設計引物,而是要講講怎麼用Python來做引物設計。
Python擁有眾多的第三方包,其中有個叫: Primer3-py
https://pypi.org/project/primer3-py/
Primer3-py 是 Primer3 在 Python 中的一個「包裝」,用 Primer3-py 官方的說法就是:提供一個簡單可靠的方式讓你能更好的自動化設計引物 (The intention is to provide a simple and reliable interface for automated oligo analysis and design)。
註:有人可能沒怎麼聽過 Primer3,這是個引物設計的程序,NCBI 的 Primer-BLAST 引物設計部分用的就是 Primer3。除此之外,Primer3 還有幾個網頁版和命令行版本,引用次數非常高,高到你難以想像 ... 可以檢索一下 Primer3 on the WWW for General Users And For Biologist Programmers
安裝:
有兩種方法,都非常方便:
方法一,使用 pip:
pip install Cython pip install primer3-py
方法二,使用 Bioconda:
conda install -c bioconda primer3-py
安裝好 Primer3-py 之後,不需要另外再單獨安裝 Primer3。
註:我個人推薦使用 Bioconda 來安裝生物及編程相關的各種軟體和包,非常出色的一個管理器,雖然有些小瑕疵,但瑕不掩瑜,對做生信分析的人來說算得上是福音,特別是在你被各種軟體各種包的安裝問題折磨千百遍之後。(這裡特指在 Linux 下,其他類型的系統上沒有用過,就不評價了)
功能
Primer3-py 的功能其實分兩部分:一部分是其本身自帶的 引物「熱力學計算」 功能,另一部分就是 調用 Primer3 進行引物設計 的功能。
後文用做示例的模板序列來自於部分 BRCA2 的 DNA 序列,FASTA 序列如下:
>NC_000013.11:32315480-32399672 Homo sapiens chromosome 13, GRCh38.p12 Primary AssemblyGTGGCGCGAGCTTCTGAAACTAGGCGGCAGAGGCGGAGCCGCTGTGGCACTGCTGCGCCTCTGCTGCGCCTCGGGTGTCTTTTGCGGCGGTGGGTCGCCGCCGGGAGAAGCGTGAGGGGACAGATTTGTGACCGGCGCGGTTTTTGTCAGCTTACTCCGGCCAAAAAAGAACTGCACCTCTGGAGCGGGTTAGTGGTGGTGGTAGTGGGT
來源於NCBI:
https://www.ncbi.nlm.nih.gov/nuccore/NC_000013.11report=fasta&from=32315480&to=32399672
Primer3-py 自帶功能:引物熱力學參數評估
主要有5個可用的命令,分別評估幾個引物的熱力學參數:
熱力學參數Primer3-py 命令Tm值calcTm()髮夾結構calcHairpin()同源二聚體calcHomodimer()異質二聚體calcHeterodimer()3'端穩定性calcEndStability()具體例子:
FASTA = """>NC_000013.11:32315480-32399672 Homo sapiens chromosome 13, GRCh38.p12 Primary AssemblyGTGGCGCGAGCTTCTGAAACTAGGCGGCAGAGGCGGAGCCGCTGTGGCACTGCTGCGCCTCTGCTGCGCCTCGGGTGTCTTTTGCGGCGGTGGGTCGCCGCCGGGAGAAGCGTGAGGGGACAGATTTGTGACCGGCGCGGTTTTTGTCAGCTTACTCCGGCCAAAAAAGAACTGCACCTCTGGAGCGGGTTAGTGGTGGTGGTAGTGGGT"""
primer3.calcTm("GTGGCGCGAGCTTCTGAAAC")
""" 結 果 >>> 56.89119991230376 """
primer3.calcHairpin("GTGGCGCGAGCTTCTGAAAC")
""" 結 果 >>> ThermoResult(structure_found=True, tm=57.92, dg=-1484.80, dh=-23500.00, ds=-70.98)"""
primer3.calcHomodimer("GTGGCGCGAGCTTCTGAAAC")
""" 結 果 >>> ThermoResult(structure_found=True, tm=9.76, dg=-6863.20, dh=-45200.00, ds=-123.61) """
primer3.calcHeterodimer("GTGGCGCGAGCTTCTGAAAC", FASTA)
""" 結 果 >>> ThermoResult(structure_found=True, tm=21.59, dg=-6561.64, dh=-89000.00, ds=-265.80) """
primer3.bindings.calcEndStability("GTGGCGCGAGCTTCTGAAAC", FASTA)
""" 結 果 >>> ThermoResult(structure_found=True, tm=15.21, dg=-3968.79, dh=-95900.00, ds=-296.41) """
這部分就先簡單介紹一下最基本用法,詳細參數和結果下一篇再進一步講解。也可以自行查看官方文檔:https://libnano.github.io/primer3-py/quickstart.html
通過 Primer3-py 調用 Primer3:設計引物
用 Primer3-py 來調用 Primer3 可以說是非常方便了,一行代碼的事:
primer3.bindings.designPrimers()
不過這行命令的主要參數有兩個:seq_args(Primer3 序列和設計參數)和 global_args(Primer3 全局參數)
而這兩個參數包含了 Primer3 裡的參數,那麼麻煩就來了。因為 Primer3 需要讀取一個配置文件(Setting File),包含用於引物設計所有參數,而包括序列本身在內,Primer3 配置文件中可選的參數大概有100~200個,版本不同參數還會有些出入( Primer3-py 內置的是 v2.3.7 )。因為參數實在是太多,具體的使用和解釋要參考 Primer3 的官方文檔:http://primer3.sourceforge.net/primer3_manual.htm
在這裡就先不一一細說了,修改了 Primer3-py 文檔示例參數用來演示, 在下一篇文章裡會挑重點和結果一起分析。
seq_args = {
'SEQUENCE_ID': 'BRCA2_SEGMENT',
'SEQUENCE_TEMPLATE': "GTGGCGCGAGCTTCTGAAACTAGGCGGCAGAGGCGGAGCCGCTGTGGCACTGCTGCGCCTCTGCTGCGCCTCGGGTGTCTTTTGCGGCGGTGGGTCGCCGCCGGGAGAAGCGTGAGGGGACAGATTTGTGACCGGCGCGGTTTTTGTCAGCTTACTCCGGCCAAAAAAGAACTGCACCTCTGGAGCGGGTTAGTGGTGGTGGTAGTGGGT",
'SEQUENCE_INCLUDED_REGION': [0,210],}
global_args = {
'PRIMER_OPT_SIZE': 20,
'PRIMER_PICK_INTERNAL_OLIGO': 1,
'PRIMER_INTERNAL_MAX_SELF_END': 8,
'PRIMER_MIN_SIZE': 18,
'PRIMER_MAX_SIZE': 25,
'PRIMER_OPT_TM': 60.0,
'PRIMER_MIN_TM': 57.0,
'PRIMER_MAX_TM': 63.0,
'PRIMER_MIN_GC': 20.0,
'PRIMER_MAX_GC': 80.0,
'PRIMER_MAX_POLY_X': 100,
'PRIMER_INTERNAL_MAX_POLY_X': 100,
'PRIMER_SALT_MONOVALENT': 50.0,
'PRIMER_DNA_CONC': 50.0,
'PRIMER_MAX_NS_ACCEPTED': 0,
'PRIMER_MAX_SELF_ANY': 12,
'PRIMER_MAX_SELF_END': 8,
'PRIMER_PAIR_MAX_COMPL_ANY': 12,
'PRIMER_PAIR_MAX_COMPL_END': 8,
'PRIMER_PRODUCT_SIZE_RANGE': [[75,100],[100,125],[125,150],[150,175],[175,200]],}
primer3_result = primer3.bindings.designPrimers(seq_args, global_args)
primer3_primary_result = primer3.bindings.designPrimers(seq_args)
返回的結果是一個Python字典,內容非常多,乍一看毫無頭緒,不過處理一下就會清晰很多
{'PRIMER_LEFT_EXPLAIN': 'considered 1088, GC content failed 57, low tm 31, high tm 833, ok 167', 'PRIMER_RIGHT_EXPLAIN': 'considered 1088, GC content failed 47, low tm 93, high tm 644, ok 304', 'PRIMER_INTERNAL_EXPLAIN': 'considered 1885, GC content failed 67, low tm 453, high tm 661, ok 704', 'PRIMER_PAIR_EXPLAIN': 'considered 186, unacceptable product size 181, ok 5', 'PRIMER_LEFT_NUM_RETURNED': 5, 'PRIMER_RIGHT_NUM_RETURNED': 5, 'PRIMER_INTERNAL_NUM_RETURNED': 5, 'PRIMER_PAIR_NUM_RETURNED': 5, 'PRIMER_PAIR_0_PENALTY': 0.07203216442314897, 'PRIMER_LEFT_0_PENALTY': 0.0360099993838503, 'PRIMER_RIGHT_0_PENALTY': 0.03602216503929867, 'PRIMER_INTERNAL_0_PENALTY': 0.04672637428285498, 'PRIMER_LEFT_0_SEQUENCE': 'AGCGTGAGGGGACAGATTTG', 'PRIMER_RIGHT_0_SEQUENCE': 'GCTCCAGAGGTGCAGTTCTT', 'PRIMER_INTERNAL_0_SEQUENCE': 'CCGGCGCGGTTTTTGTCAGC', 'PRIMER_LEFT_0': (108, 20), 'PRIMER_RIGHT_0': (185, 20), 'PRIMER_INTERNAL_0': (131, 20), 'PRIMER_LEFT_0_TM': 60.03600999938385, 'PRIMER_RIGHT_0_TM': 59.9639778349607, 'PRIMER_INTERNAL_0_TM': 60.046726374282855, 'PRIMER_LEFT_0_GC_PERCENT': 55.0, 'PRIMER_RIGHT_0_GC_PERCENT': 55.0, 'PRIMER_INTERNAL_0_GC_PERCENT': 65.0, 'PRIMER_LEFT_0_SELF_ANY_TH': 0.0, 'PRIMER_RIGHT_0_SELF_ANY_TH': 5.308994554799938, 'PRIMER_INTERNAL_0_SELF_ANY_TH': 6.715563508517448, 'PRIMER_LEFT_0_SELF_END_TH': 0.0, 'PRIMER_RIGHT_0_SELF_END_TH': 0.0, 'PRIMER_INTERNAL_0_SELF_END_TH': 0.0, 'PRIMER_LEFT_0_HAIRPIN_TH': 0.0, 'PRIMER_RIGHT_0_HAIRPIN_TH': 41.267496973905224, 'PRIMER_INTERNAL_0_HAIRPIN_TH': 38.99011028469272, 'PRIMER_LEFT_0_END_STABILITY': 2.32, 'PRIMER_RIGHT_0_END_STABILITY': 2.52, 'PRIMER_PAIR_0_COMPL_ANY_TH': 0.0, 'PRIMER_PAIR_0_COMPL_END_TH': 0.0, 'PRIMER_PAIR_0_PRODUCT_SIZE': 78, 'PRIMER_PAIR_1_PENALTY': 0.2323444485285222, 'PRIMER_LEFT_1_PENALTY': 0.04078105057766379, 'PRIMER_RIGHT_1_PENALTY': 0.19156339795085842, 'PRIMER_INTERNAL_1_PENALTY': 0.1759585850769554, 'PRIMER_LEFT_1_SEQUENCE': 'GCGCGGTTTTTGTCAGCTTA', 'PRIMER_RIGHT_1_SEQUENCE': 'ACCCACTACCACCACCACTA', 'PRIMER_INTERNAL_1_SEQUENCE': 'ACTGCACCTCTGGAGCGGGT', 'PRIMER_LEFT_1': (134, 20), 'PRIMER_RIGHT_1': (209, 20), 'PRIMER_INTERNAL_1': (170, 20), 'PRIMER_LEFT_1_TM': 60.040781050577664, 'PRIMER_RIGHT_1_TM': 59.80843660204914, 'PRIMER_INTERNAL_1_TM': 59.824041414923045, 'PRIMER_LEFT_1_GC_PERCENT': 50.0, 'PRIMER_RIGHT_1_GC_PERCENT': 55.0, 'PRIMER_INTERNAL_1_GC_PERCENT': 65.0, 'PRIMER_LEFT_1_SELF_ANY_TH': 8.834562170276627, 'PRIMER_RIGHT_1_SELF_ANY_TH': 0.0, 'PRIMER_INTERNAL_1_SELF_ANY_TH': 13.054545961563008, 'PRIMER_LEFT_1_SELF_END_TH': 0.0, 'PRIMER_RIGHT_1_SELF_END_TH': 0.0, 'PRIMER_INTERNAL_1_SELF_END_TH': 4.711373579171379, 'PRIMER_LEFT_1_HAIRPIN_TH': 0.0, 'PRIMER_RIGHT_1_HAIRPIN_TH': 0.0, 'PRIMER_INTERNAL_1_HAIRPIN_TH': 41.81896803359854, 'PRIMER_LEFT_1_END_STABILITY': 3.09, 'PRIMER_RIGHT_1_END_STABILITY': 2.74, 'PRIMER_PAIR_1_COMPL_ANY_TH': 0.0, 'PRIMER_PAIR_1_COMPL_END_TH': 0.0, 'PRIMER_PAIR_1_PRODUCT_SIZE': 76, 'PRIMER_PAIR_2_PENALTY': 0.2842985295354765, 'PRIMER_LEFT_2_PENALTY': 0.0360099993838503, 'PRIMER_RIGHT_2_PENALTY': 0.24828853015162622, 'PRIMER_INTERNAL_2_PENALTY': 0.04672637428285498, 'PRIMER_LEFT_2_SEQUENCE': 'AGCGTGAGGGGACAGATTTG', 'PRIMER_RIGHT_2_SEQUENCE': 'CTACCACCACCACTAACCCG', 'PRIMER_INTERNAL_2_SEQUENCE': 'CCGGCGCGGTTTTTGTCAGC', 'PRIMER_LEFT_2': (108, 20), 'PRIMER_RIGHT_2': (204, 20), 'PRIMER_INTERNAL_2': (131, 20), 'PRIMER_LEFT_2_TM': 60.03600999938385, 'PRIMER_RIGHT_2_TM': 59.751711469848374, 'PRIMER_INTERNAL_2_TM': 60.046726374282855, 'PRIMER_LEFT_2_GC_PERCENT': 55.0, 'PRIMER_RIGHT_2_GC_PERCENT': 60.0, 'PRIMER_INTERNAL_2_GC_PERCENT': 65.0, 'PRIMER_LEFT_2_SELF_ANY_TH': 0.0, 'PRIMER_RIGHT_2_SELF_ANY_TH': 0.0, 'PRIMER_INTERNAL_2_SELF_ANY_TH': 6.715563508517448, 'PRIMER_LEFT_2_SELF_END_TH': 0.0, 'PRIMER_RIGHT_2_SELF_END_TH': 0.0, 'PRIMER_INTERNAL_2_SELF_END_TH': 0.0, 'PRIMER_LEFT_2_HAIRPIN_TH': 0.0, 'PRIMER_RIGHT_2_HAIRPIN_TH': 0.0, 'PRIMER_INTERNAL_2_HAIRPIN_TH': 38.99011028469272, 'PRIMER_LEFT_2_END_STABILITY': 2.32, 'PRIMER_RIGHT_2_END_STABILITY': 5.28, 'PRIMER_PAIR_2_COMPL_ANY_TH': 0.0, 'PRIMER_PAIR_2_COMPL_END_TH': 0.0, 'PRIMER_PAIR_2_PRODUCT_SIZE': 97, 'PRIMER_PAIR_3_PENALTY': 0.28653552146357697, 'PRIMER_LEFT_3_PENALTY': 0.2505133564242783, 'PRIMER_RIGHT_3_PENALTY': 0.03602216503929867, 'PRIMER_INTERNAL_3_PENALTY': 0.04672637428285498, 'PRIMER_LEFT_3_SEQUENCE': 'GAAGCGTGAGGGGACAGATT', 'PRIMER_RIGHT_3_SEQUENCE': 'GCTCCAGAGGTGCAGTTCTT', 'PRIMER_INTERNAL_3_SEQUENCE': 'CCGGCGCGGTTTTTGTCAGC', 'PRIMER_LEFT_3': (106, 20), 'PRIMER_RIGHT_3': (185, 20), 'PRIMER_INTERNAL_3': (131, 20), 'PRIMER_LEFT_3_TM': 59.74948664357572, 'PRIMER_RIGHT_3_TM': 59.9639778349607, 'PRIMER_INTERNAL_3_TM': 60.046726374282855, 'PRIMER_LEFT_3_GC_PERCENT': 55.0, 'PRIMER_RIGHT_3_GC_PERCENT': 55.0, 'PRIMER_INTERNAL_3_GC_PERCENT': 65.0, 'PRIMER_LEFT_3_SELF_ANY_TH': 0.0, 'PRIMER_RIGHT_3_SELF_ANY_TH': 5.308994554799938, 'PRIMER_INTERNAL_3_SELF_ANY_TH': 6.715563508517448, 'PRIMER_LEFT_3_SELF_END_TH': 0.0, 'PRIMER_RIGHT_3_SELF_END_TH': 0.0, 'PRIMER_INTERNAL_3_SELF_END_TH': 0.0, 'PRIMER_LEFT_3_HAIRPIN_TH': 0.0, 'PRIMER_RIGHT_3_HAIRPIN_TH': 41.267496973905224, 'PRIMER_INTERNAL_3_HAIRPIN_TH': 38.99011028469272, 'PRIMER_LEFT_3_END_STABILITY': 2.4, 'PRIMER_RIGHT_3_END_STABILITY': 2.52, 'PRIMER_PAIR_3_COMPL_ANY_TH': 0.0, 'PRIMER_PAIR_3_COMPL_END_TH': 0.0, 'PRIMER_PAIR_3_PRODUCT_SIZE': 80, 'PRIMER_PAIR_4_PENALTY': 0.3576746687102741, 'PRIMER_LEFT_4_PENALTY': 0.3216525036709754, 'PRIMER_RIGHT_4_PENALTY': 0.03602216503929867, 'PRIMER_INTERNAL_4_PENALTY': 0.04672637428285498, 'PRIMER_LEFT_4_SEQUENCE': 'GCGTGAGGGGACAGATTTGT', 'PRIMER_RIGHT_4_SEQUENCE': 'GCTCCAGAGGTGCAGTTCTT', 'PRIMER_INTERNAL_4_SEQUENCE': 'CCGGCGCGGTTTTTGTCAGC', 'PRIMER_LEFT_4': (109, 20), 'PRIMER_RIGHT_4': (185, 20), 'PRIMER_INTERNAL_4': (131, 20), 'PRIMER_LEFT_4_TM': 60.321652503670975, 'PRIMER_RIGHT_4_TM': 59.9639778349607, 'PRIMER_INTERNAL_4_TM': 60.046726374282855, 'PRIMER_LEFT_4_GC_PERCENT': 55.0, 'PRIMER_RIGHT_4_GC_PERCENT': 55.0, 'PRIMER_INTERNAL_4_GC_PERCENT': 65.0, 'PRIMER_LEFT_4_SELF_ANY_TH': 0.0, 'PRIMER_RIGHT_4_SELF_ANY_TH': 5.308994554799938, 'PRIMER_INTERNAL_4_SELF_ANY_TH': 6.715563508517448, 'PRIMER_LEFT_4_SELF_END_TH': 0.0, 'PRIMER_RIGHT_4_SELF_END_TH': 0.0, 'PRIMER_INTERNAL_4_SELF_END_TH': 0.0, 'PRIMER_LEFT_4_HAIRPIN_TH': 41.18192535348908, 'PRIMER_RIGHT_4_HAIRPIN_TH': 41.267496973905224, 'PRIMER_INTERNAL_4_HAIRPIN_TH': 38.99011028469272, 'PRIMER_LEFT_4_END_STABILITY': 2.83, 'PRIMER_RIGHT_4_END_STABILITY': 2.52, 'PRIMER_PAIR_4_COMPL_ANY_TH': 0.0, 'PRIMER_PAIR_4_COMPL_END_TH': 0.0, 'PRIMER_PAIR_4_PRODUCT_SIZE': 77}
註:引物設計參數和結果的具體釋義還是要回到Primer3文檔中去找,下一篇會進一步介紹
Primer3 返回結果的處理
先看看處理完的效果:
通過處理之後,將看起來沒有頭緒的「字典」處理成了比較易讀的「數據框」 ( Dataframe ),這是一種在 R 語言裡非常基礎的數據格式,最大的優點就是直觀,Excel 的表格也長類似的樣子。在處理結果的過程當中使用了另外一個強大的 Python 包:Pandas
註:最初開發 Pandas 的目的就是為了將 R 語言的數據處理方式移植到 Python 裡,後來隨著 Python 被廣泛應用於數據分析和人工智慧,Pandas 成為了 Python 處理數據時不可或缺的工具包。
要處理 Primer3 返回的結果,第一反應肯定是回頭再仔細觀察一下 Primer3 返回的結果,看是不是有規律可循。果不其然,除了前幾行是一些統計信息外,剩下都是引物對本身的信息,每對引物都有共同的信息,不同引物對間通過數字編號加以區分。另外從 _'PRIMER_PAIR_NUM_RETURNED': 5_ 這一行知道總共有5對引物。有規律可循,那接下來事情就好辦了。
第一步:將結果轉換成以「引物信息」為鍵值的新形式的「字典」:
primer3_result_table_dict = {}
for i in range(primer3_result["PRIMER_PAIR_NUM_RETURNED"]): primer_id = str(i)
for key in primer3_result:
if primer_id in key:
info_tag = key.replace("_" + primer_id, "")
try: primer3_result_table_dict[info_tag] except: primer3_result_table_dict[info_tag] = []
finally: primer3_result_table_dict[info_tag].append(primer3_result[key])
第二步:用 Pandas 將新「字典」轉換成「數據框」:
import pandas as pdindex = []
for i in range(primer3_result["PRIMER_PAIR_NUM_RETURNED"]):
index.append("PRIMER_PAIR_" + str(i))
primer3_result_df = pd.DataFrame(primer3_result_table_dict, index=index)
primer3_result_df = primer3_result_df.T
primer3_result_df.to_csv("primer3_result.csv", sep="\t")print(primer3_result_df)
如果覺得看表格還是不夠直觀,那麼通過可視化來變得更直觀一些。用引物 TM 值的數據來做個例子(動圖):
這是用 Plotly 包做的可視化,因為與主題相關性不大就不放了代碼了,除了 Plotly 之外優秀的 Python 可視化包還有很多。不過與其他包相比,Plotly 最大的優點是它的交互性非常好,如果有興趣了解,之後會有可視化相關的文章進行詳細介紹。
總結:
實話說,現在的引物設計軟體已經非常方便了,很多人會覺得實在想不出來為什麼還要多此一舉,趟這個渾水自己寫代碼。如果你只是偶爾設計一兩對引物,那麼確實是完全沒有必要。不過當需要設計高通量測序 Panel(什麼是 Panel ?往期易微升文章有介紹)的時候,你可能要同時設計幾十甚至上百對引物,完了之後還要通過參數進行微調,以減小每對引物之間的相互影響。這對於一般的設計軟體是不是就成了幾乎不可能完成的任務。而 Primer3-py 的優勢在這裡就體現出來了,不僅可以通過調用 Primer3 來進行細緻和精準的引物設計和調整,還能便捷的銜接 Python 將引物設計的前後處理流程化,使批量引物設計變得更高效和可控。這些內容的細節,也是之後要介紹的「多重PCR引物設計」中的一部分,對於喜歡鼓搗的人來說,完成這個任務是個不錯的挑戰。隨著「多重PCR捕獲-高通量測序」不斷被應用於各個場景,「多重PCR引物設計」的實用性也在隨之增加。
文章中測試使用的環境:
Ubuntu: 18.04.1 LTS
Python: v3.6.7
Jupyterlab: v0.35.4
Primer3-py: v0.5.7
Pandas: v0.23.4
易微升