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 Assembly
GTGGCGCGAGCTTCTGAAACTAGGCGGCAGAGGCGGAGCCGCTGTGGCACTGCTGCGCCTCTGCTGCGCC
TCGGGTGTCTTTTGCGGCGGTGGGTCGCCGCCGGGAGAAGCGTGAGGGGACAGATTTGTGACCGGCGCGG
TTTTTGTCAGCTTACTCCGGCCAAAAAAGAACTGCACCTCTGGAGCGGGTTAGTGGTGGTGGTAGTGGGT
来源于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 Assembly
GTGGCGCGAGCTTCTGAAACTAGGCGGCAGAGGCGGAGCCGCTGTGGCACTGCTGCGCCTCTGCTGCGCC
TCGGGTGTCTTTTGCGGCGGTGGGTCGCCGCCGGGAGAAGCGTGAGGGGACAGATTTGTGACCGGCGCGG
TTTTTGTCAGCTTACTCCGGCCAAAAAAGAACTGCACCTCTGGAGCGGGTTAGTGGTGGTGGTAGTGGGT
"""
# 计算引物 Tm 值
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) """
# 计算引物 3'端稳定性
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 文档示例参数用来演示, 在下一篇文章里会挑重点和结果一起分析。
# Primer3 序列和设计参数,必须要有
seq_args = {
'SEQUENCE_ID': 'BRCA2_SEGMENT',
'SEQUENCE_TEMPLATE': "GTGGCGCGAGCTTCTGAAACTAGGCGGCAGAGGCGGAGCCGCTGTGGCACTGCTGCGCCTCTGCTGCGCCTCGGGTGTCTTTTGCGGCGGTGGGTCGCCGCCGGGAGAAGCGTGAGGGGACAGATTTGTGACCGGCGCGGTTTTTGTCAGCTTACTCCGGCCAAAAAAGAACTGCACCTCTGGAGCGGGTTAGTGGTGGTGGTAGTGGGT",
'SEQUENCE_INCLUDED_REGION': [0,210],
}
# Primer3 全局参数,这个可选
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
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 返回结果的处理
先看看处理完的效果:
PRIMER_PAIR_0 | PRIMER_PAIR_1 | PRIMER_PAIR_2 | PRIMER_PAIR_3 | PRIMER_PAIR_4 | |
---|---|---|---|---|---|
PRIMER_PAIR_PENALTY | 0.0720322 | 0.232344 | 0.284299 | 0.286536 | 0.357675 |
PRIMER_LEFT_PENALTY | 0.03601 | 0.0407811 | 0.03601 | 0.250513 | 0.321653 |
PRIMER_RIGHT_PENALTY | 0.0360222 | 0.191563 | 0.248289 | 0.0360222 | 0.0360222 |
PRIMER_INTERNAL_PENALTY | 0.0467264 | 0.175959 | 0.0467264 | 0.0467264 | 0.0467264 |
PRIMER_LEFT_SEQUENCE | AGCGTGAGGGGACAGATTTG | GCGCGGTTTTTGTCAGCTTA | AGCGTGAGGGGACAGATTTG | GAAGCGTGAGGGGACAGATT | GCGTGAGGGGACAGATTTGT |
PRIMER_RIGHT_SEQUENCE | GCTCCAGAGGTGCAGTTCTT | ACCCACTACCACCACCACTA | CTACCACCACCACTAACCCG | GCTCCAGAGGTGCAGTTCTT | GCTCCAGAGGTGCAGTTCTT |
PRIMER_INTERNAL_SEQUENCE | CCGGCGCGGTTTTTGTCAGC | ACTGCACCTCTGGAGCGGGT | CCGGCGCGGTTTTTGTCAGC | CCGGCGCGGTTTTTGTCAGC | CCGGCGCGGTTTTTGTCAGC |
PRIMER_LEFT | (108, 20) | (134, 20) | (108, 20) | (106, 20) | (109, 20) |
PRIMER_RIGHT | (185, 20) | (209, 20) | (204, 20) | (185, 20) | (185, 20) |
PRIMER_INTERNAL | (131, 20) | (170, 20) | (131, 20) | (131, 20) | (131, 20) |
PRIMER_LEFT_TM | 60.036 | 60.0408 | 60.036 | 59.7495 | 60.3217 |
PRIMER_RIGHT_TM | 59.964 | 59.8084 | 59.7517 | 59.964 | 59.964 |
PRIMER_INTERNAL_TM | 60.0467 | 59.824 | 60.0467 | 60.0467 | 60.0467 |
PRIMER_LEFT_GC_PERCENT | 55 | 50 | 55 | 55 | 55 |
PRIMER_RIGHT_GC_PERCENT | 55 | 55 | 60 | 55 | 55 |
PRIMER_INTERNAL_GC_PERCENT | 65 | 65 | 65 | 65 | 65 |
PRIMER_LEFT_SELF_ANY_TH | 0 | 8.83456 | 0 | 0 | 0 |
PRIMER_RIGHT_SELF_ANY_TH | 5.30899 | 0 | 0 | 5.30899 | 5.30899 |
PRIMER_INTERNAL_SELF_ANY_TH | 6.71556 | 13.0545 | 6.71556 | 6.71556 | 6.71556 |
PRIMER_LEFT_SELF_END_TH | 0 | 0 | 0 | 0 | 0 |
PRIMER_RIGHT_SELF_END_TH | 0 | 0 | 0 | 0 | 0 |
PRIMER_INTERNAL_SELF_END_TH | 0 | 4.71137 | 0 | 0 | 0 |
PRIMER_LEFT_HAIRPIN_TH | 0 | 0 | 0 | 0 | 41.1819 |
PRIMER_RIGHT_HAIRPIN_TH | 41.2675 | 0 | 0 | 41.2675 | 41.2675 |
PRIMER_INTERNAL_HAIRPIN_TH | 38.9901 | 41.819 | 38.9901 | 38.9901 | 38.9901 |
PRIMER_LEFT_END_STABILITY | 2.32 | 3.09 | 2.32 | 2.4 | 2.83 |
PRIMER_RIGHT_END_STABILITY | 2.52 | 2.74 | 5.28 | 2.52 | 2.52 |
PRIMER_PAIR_COMPL_ANY_TH | 0 | 0 | 0 | 0 | 0 |
PRIMER_PAIR_COMPL_END_TH | 0 | 0 | 0 | 0 | 0 |
PRIMER_PAIR_PRODUCT_SIZE | 78 | 76 | 97 | 80 | 77 |
通过处理之后,将看起来没有头绪的“字典”处理成了比较易读的“数据框” ( 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 pd
index = []
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
# 导出成文件,可以用Excel或者其他编辑器打开查看
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