From 69c0defe2f9d8a562b199048451e7a000103750a Mon Sep 17 00:00:00 2001 From: Runsheng Date: Thu, 27 Oct 2022 20:40:28 +0800 Subject: [PATCH] expose the user config file to primerdesign.py --- bin/primerdesign.py | 23 +++++++++++++++--- primerdiffer/__init__.py | 2 +- primerdiffer/walk_chr.py | 13 +++++++---- readme.md | 50 +++++++++++++++++++++++++++++++++++----- test/test_walk_chr.py | 6 +++++ test/user_settings.py | 19 +++++++++++++++ 6 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 test/user_settings.py diff --git a/bin/primerdesign.py b/bin/primerdesign.py index f25ca1d..1f11753 100644 --- a/bin/primerdesign.py +++ b/bin/primerdesign.py @@ -9,14 +9,16 @@ """ import argparse -import os,sys +import os +import sys +import json #currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) #parentdir = os.path.dirname(os.path.dirname(currentdir)) #sys.path.insert(0,parentdir) # self import -from primerdiffer.walk_chr import flow_walk_chr +from primerdiffer.walk_chr import flow_walk_chr, primer3_general_settings parser=argparse.ArgumentParser() parser.add_argument("-d", "--wkdir", default=None, @@ -53,11 +55,25 @@ parser.add_argument("--prefix", default="primers", help="prefix of output file, default is primers") +# add user settings +parser.add_argument("--primer3config", default=None, + help="the config file for the primer3 ") # default handler args = parser.parse_args(args=None if sys.argv[1:] else ['--help']) wkdir=os.getcwd() if args.wkdir is None else args.wkdir + +# deal with config +primer3_setting = primer3_general_settings +if args.primer3config is None: + pass +else: # update the primer3 setting from the givien parameters + with open(args.primer3config, "r") as f: + primer3_user_setting = eval(f.read()) # read the config as a dict + primer3_setting.update(primer3_user_setting) + + flow_walk_chr(wkdir=wkdir, genome1=args.genome1, genome2=args.genome2, @@ -69,4 +85,5 @@ db2_maxhit=args.hit2, interval=args.interval, jump=args.jump, - out_prefix=args.prefix) + out_prefix=args.prefix, + primer3_settings=primer3_setting) diff --git a/primerdiffer/__init__.py b/primerdiffer/__init__.py index 33a3f8d..4f7fa76 100644 --- a/primerdiffer/__init__.py +++ b/primerdiffer/__init__.py @@ -1 +1 @@ -__version__= "0.1.2" \ No newline at end of file +__version__= "0.1.4" \ No newline at end of file diff --git a/primerdiffer/walk_chr.py b/primerdiffer/walk_chr.py index 4227a70..8bde78c 100644 --- a/primerdiffer/walk_chr.py +++ b/primerdiffer/walk_chr.py @@ -12,12 +12,15 @@ from primerdiffer.primer_check import my_design_primer, primer_check from primerdiffer.utils import dic2dic, fasta2dic, chr_select, tuple_to_pos_str, pos_str_to_tuple, checkblastdb +from primerdiffer.general_settings import primer3_general_settings def walk_chr_dense(genome, chro, start, end, db1, db2, cutoff_alignlength=16, cutoff_free3=2, product_cutoff=2000, db1_maxhit=1, db2_maxhit=0, - interval=500000, jump=4000, out_prefix="primers", debugmod=False): + interval=500000, jump=4000, out_prefix="primers", debugmod=False, + primer3_settings=primer3_general_settings + ): """ :param genome: genome is a dict in name:seq, :param chro: @@ -41,7 +44,7 @@ def walk_chr_dense(genome, chro, start, end, db1, db2, if "N" in seq.upper(): offset += 1 else: - myprimer = my_design_primer(name=name, seq=seq) + myprimer = my_design_primer(name=name, seq=seq, primer3_settings=primer3_settings) primer_used = primer_check(myprimer,db1,db2, cutoff_alignlength, cutoff_free3, product_cutoff, db1_maxhit, db2_maxhit, @@ -67,7 +70,8 @@ def walk_chr_dense(genome, chro, start, end, db1, db2, def flow_walk_chr(wkdir, genome1, genome2, pos_str, cutoff_alignlength=16, cutoff_free3=2, product_cutoff=2000, db1_maxhit=1, db2_maxhit=0, - interval=4000, jump=400, out_prefix="primers"): + interval=4000, jump=400, out_prefix="primers", + primer3_settings = primer3_general_settings): """ genome1: the genome fasta file used to design primers @@ -94,5 +98,6 @@ def flow_walk_chr(wkdir, genome1, genome2, pos_str, product_cutoff=product_cutoff, db1_maxhit=db1_maxhit, db2_maxhit=db2_maxhit, - interval=interval, jump=jump, out_prefix=out_prefix) + interval=interval, jump=jump, out_prefix=out_prefix, + primer3_settings=primer3_settings) print(primer_dict) diff --git a/readme.md b/readme.md index da97d77..3547a1c 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,7 @@ pip install primerdiffer # will also install primer3-py and biopython conda install -c bioconda blast # install ncbi blast, which is not included in pip installation ``` -## Case example: primerdesign.py for primerdiffer +## Case example: used primerdesign.py to design primers for two haplotypes Design genome-wide specific primers for two species/sub-species/divergent sequences: - Greedy design primers for a region in genome1 and make a specificity check using genome2 - The dis-similarity between genome1 and genome2 >= 5%. @@ -63,8 +63,8 @@ from [cb5.fa](https://github.com/Runsheng/cbgenome/releases/download/cb5pre_cn3p The _C. nigoni_ genome is cn3_new.fa and _C. briggsae_ genome is cb5.fa. To design _C. briggsae_ unique primer, which would not amplify any region in _C. nigoni_, and amplify only one region in _C. briggsae_. -The targeted region for C. briggsae is ChrX:12881200-15106660 (-pos), -one primer is designed for every 4kb interval (--interval). +The targeted region for C. briggsae is ChrX:12881200-15106660 (-pos or --position), +one primer is designed for every 4kb interval (-i or --interval). ```bash primerdesign.py -g1 cb5.fa -g2 cn3_new.fa -pos "ChrX:12881200-15106660" --interval 4000 ``` @@ -119,9 +119,47 @@ head ispcr.fa #ATGATGATGATGATGGTGGGGTGAGAATAGAGT ``` +## Case example: Design general purpose primers with given parameters +The default primer design parameter is as described in [general_setting.py](https://github.com/Runsheng/primerdiffer/blob/master/primerdiffer/general_settings.py): +```python +primer3_general_settings = { + 'PRIMER_OPT_SIZE': 20, + 'PRIMER_PICK_LEFT_PRIMER':1, + 'PRIMER_PICK_RIGHT_PRIMER':1, + 'PRIMER_PICK_INTERNAL_OLIGO': 0, + 'PRIMER_MIN_SIZE': 18, + 'PRIMER_MAX_SIZE': 23, + 'PRIMER_OPT_TM': 57.0, + 'PRIMER_MIN_TM': 46.0, + 'PRIMER_MAX_TM': 63.0, + 'PRIMER_MIN_GC': 20.0, + 'PRIMER_MAX_GC': 80.0, + 'PRIMER_PRODUCT_SIZE_RANGE': [[250, 650]], + 'PRIMER_NUM_RETURN':10, + 'PRIMER_MIN_THREE_PRIME_DISTANCE':10, + 'PRIMER_LIB_AMBIGUITY_CODES_CONSENSUS':0 +} +``` +The new parameter can be supplemnted as a file with the terms which need to be changed, for example, create a file with name of config.txt +```python +# content of config.txt +# only changed the product size, the others are the same the default +{'PRIMER_PRODUCT_SIZE_RANGE': [[100, 200]]} +``` +Run primerdesign.py to design a qPCR primer(product size 100-20bp, use the config.txt for primer3config) for _C. briggsae_ mitochondrial DNA sequence +[NC_009885.1](https://www.ncbi.nlm.nih.gov/nuccore/NC_009885.1?report=fasta) in any region (use 0:-1 means from the first +nucleotide to the last); check the _C. briggsae_ genome cb5.fa for false priming, make sure the hit is 0. +```bash +primerdesign.py -g1 NC_009885.fa -g2 cb5.fa -pos "NC_009885.1:0:-1" \ + --interval 1000 --hit1 1 --hit2 0 \ + --primer3config config.txt +``` + + + + ## Roadmap for other functions: -1. To use user-provided primer parameters.Primer design parameter now is fine-tuned for general purpose PCR, which can be found in "general_settings.py".This file may need be modified to generate primers for specific purpose PCR like real-time qPCR. -2. To update the RFLP method for primer design to differ sequences with almost identical sequence. -3. To update the primer design using VCF file for closely related haplotypes. +1. To update the RFLP method for primer design to differ sequences with almost identical sequence. +2. To update the primer design using VCF file for closely related haplotypes. \ No newline at end of file diff --git a/test/test_walk_chr.py b/test/test_walk_chr.py index 41b8851..29b5987 100644 --- a/test/test_walk_chr.py +++ b/test/test_walk_chr.py @@ -27,6 +27,12 @@ def setUp(self): self.cb4_genome = "/t1/ref_BN/cb5.fa" #self.name, self.seq = chr_select(self.cb4_genome, "ChrX", 19424476,19655212) + def test_config_dump_load(self): + import json + from primerdiffer.general_settings import primer3_general_settings + with open("./test/primer3config", "w") as fw: + json.dump(primer3_general_settings, ) + def test_walk_chr_dense(self): wkdir=os.getcwd() diff --git a/test/user_settings.py b/test/user_settings.py new file mode 100644 index 0000000..cf25210 --- /dev/null +++ b/test/user_settings.py @@ -0,0 +1,19 @@ +# use the user setting +# a minimal config can keep only the terms which need to be changed, like +# {'PRIMER_PRODUCT_SIZE_RANGE': [[100,200]]} +{ 'PRIMER_OPT_SIZE': 20, + 'PRIMER_PICK_LEFT_PRIMER':1, + 'PRIMER_PICK_RIGHT_PRIMER':1, + 'PRIMER_PICK_INTERNAL_OLIGO': 0, + 'PRIMER_MIN_SIZE': 18, + 'PRIMER_MAX_SIZE': 23, + 'PRIMER_OPT_TM': 57.0, + 'PRIMER_MIN_TM': 46.0, + 'PRIMER_MAX_TM': 63.0, + 'PRIMER_MIN_GC': 20.0, + 'PRIMER_MAX_GC': 80.0, + 'PRIMER_PRODUCT_SIZE_RANGE': [[100,200]], + 'PRIMER_NUM_RETURN':10, + 'PRIMER_MIN_THREE_PRIME_DISTANCE':10, + 'PRIMER_LIB_AMBIGUITY_CODES_CONSENSUS':0 +}