varvamp 1.2.0__tar.gz → 1.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {varvamp-1.2.0 → varvamp-1.2.2}/PKG-INFO +14 -7
- {varvamp-1.2.0 → varvamp-1.2.2}/README.md +3 -5
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/__init__.py +1 -1
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/command.py +24 -15
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/logging.py +13 -4
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/reporting.py +56 -58
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/scheme.py +2 -2
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp.egg-info/PKG-INFO +14 -7
- {varvamp-1.2.0 → varvamp-1.2.2}/setup.cfg +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/setup.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/__main__.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/__init__.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/alignment.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/blast.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/consensus.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/default_config.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/get_config.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/param_estimation.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/primers.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/qpcr.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp/scripts/regions.py +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp.egg-info/SOURCES.txt +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp.egg-info/dependency_links.txt +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp.egg-info/entry_points.txt +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp.egg-info/not-zip-safe +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp.egg-info/requires.txt +0 -0
- {varvamp-1.2.0 → varvamp-1.2.2}/varvamp.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: varvamp
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: Variable VirusAMPlicons (varVAMP) is a tool to design primers for highly diverse viruses
|
|
5
5
|
Home-page: https://github.com/jonas-fuchs/varVAMP
|
|
6
6
|
Author: Dr. Jonas Fuchs
|
|
@@ -15,6 +15,15 @@ Requires-Dist: primer3-py>=1.1.0
|
|
|
15
15
|
Requires-Dist: pandas>=1.4.4
|
|
16
16
|
Requires-Dist: numpy>=1.23.3
|
|
17
17
|
Requires-Dist: seqfold>=0.7.15
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: author-email
|
|
20
|
+
Dynamic: classifier
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: description-content-type
|
|
23
|
+
Dynamic: home-page
|
|
24
|
+
Dynamic: requires-dist
|
|
25
|
+
Dynamic: requires-python
|
|
26
|
+
Dynamic: summary
|
|
18
27
|
|
|
19
28
|
|
|
20
29
|
**var**iable **V**irus**AMP**licons (varVAMP) is a tool to design primers for highly diverse viruses. The input is an alignment of your viral (full-genome) sequences.
|
|
@@ -61,15 +70,13 @@ For a lot of virus genera it is difficult to design pan-specific primers. varVAM
|
|
|
61
70
|
|
|
62
71
|
We, in collaboration with specialists for the respective viruses, have already designed and wet-lab evaluated primer schemes for various viral pathogens. All the input data and varVAMP outputs are freely available [here](https://github.com/jonas-fuchs/ViralPrimerSchemes).
|
|
63
72
|
|
|
64
|
-
|
|
73
|
+
Moreover, varVAMP primers are now available at [primerschemes](https://labs.primalscheme.com/). varVAMP now reports primer bed files in ARTICv3 format. Feel free to contribute newly designed schemes via this [Github repository of the QuickLab](https://github.com/quick-lab/primerschemes). Use [primal-page](https://github.com/ChrisgKent/primal-page) developed by [Chris Kent](https://github.com/ChrisgKent) to generate data for compatible pull-requests.
|
|
65
74
|
|
|
66
|
-
# Citing varVAMP
|
|
67
|
-
|
|
68
|
-
Please cite with the respective DOI of the version you used:
|
|
75
|
+
# Citing varVAMP
|
|
69
76
|
|
|
70
77
|
**varVAMP: automated pan-specific primer design for tiled full genome sequencing and qPCR of highly diverse viral pathogens.**
|
|
71
78
|
|
|
72
|
-
(
|
|
79
|
+
[biorxiv preprint](https://doi.org/10.1101/2024.05.08.593102)
|
|
73
80
|
|
|
74
81
|
---
|
|
75
82
|
|
|
@@ -43,15 +43,13 @@ For a lot of virus genera it is difficult to design pan-specific primers. varVAM
|
|
|
43
43
|
|
|
44
44
|
We, in collaboration with specialists for the respective viruses, have already designed and wet-lab evaluated primer schemes for various viral pathogens. All the input data and varVAMP outputs are freely available [here](https://github.com/jonas-fuchs/ViralPrimerSchemes).
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Moreover, varVAMP primers are now available at [primerschemes](https://labs.primalscheme.com/). varVAMP now reports primer bed files in ARTICv3 format. Feel free to contribute newly designed schemes via this [Github repository of the QuickLab](https://github.com/quick-lab/primerschemes). Use [primal-page](https://github.com/ChrisgKent/primal-page) developed by [Chris Kent](https://github.com/ChrisgKent) to generate data for compatible pull-requests.
|
|
47
47
|
|
|
48
|
-
# Citing varVAMP
|
|
49
|
-
|
|
50
|
-
Please cite with the respective DOI of the version you used:
|
|
48
|
+
# Citing varVAMP
|
|
51
49
|
|
|
52
50
|
**varVAMP: automated pan-specific primer design for tiled full genome sequencing and qPCR of highly diverse viral pathogens.**
|
|
53
51
|
|
|
54
|
-
(
|
|
52
|
+
[biorxiv preprint](https://doi.org/10.1101/2024.05.08.593102)
|
|
55
53
|
|
|
56
54
|
---
|
|
57
55
|
|
|
@@ -89,6 +89,13 @@ def get_args(sysargs):
|
|
|
89
89
|
type=int,
|
|
90
90
|
default=1
|
|
91
91
|
)
|
|
92
|
+
par.add_argument(
|
|
93
|
+
"--name",
|
|
94
|
+
help="name of the scheme",
|
|
95
|
+
metavar="varVAMP",
|
|
96
|
+
type=str,
|
|
97
|
+
default="varVAMP"
|
|
98
|
+
)
|
|
92
99
|
for par in (SINGLE_parser, TILED_parser):
|
|
93
100
|
par.add_argument(
|
|
94
101
|
"-ol",
|
|
@@ -112,7 +119,7 @@ def get_args(sysargs):
|
|
|
112
119
|
type=int,
|
|
113
120
|
metavar="100",
|
|
114
121
|
default=100,
|
|
115
|
-
help="min overlap of the
|
|
122
|
+
help="min overlap of the amplicon inserts"
|
|
116
123
|
)
|
|
117
124
|
SINGLE_parser.add_argument(
|
|
118
125
|
"-n",
|
|
@@ -261,10 +268,10 @@ def shared_workflow(args, log_file):
|
|
|
261
268
|
ambiguous_consensus,
|
|
262
269
|
alignment_cleaned
|
|
263
270
|
)
|
|
264
|
-
for
|
|
271
|
+
for primer_type, primer_candidates in [("+", left_primer_candidates), ("-", right_primer_candidates)]:
|
|
265
272
|
if not primer_candidates:
|
|
266
273
|
logging.raise_error(
|
|
267
|
-
f"no {
|
|
274
|
+
f"no {primer_type} primers found.\n",
|
|
268
275
|
log_file,
|
|
269
276
|
exit=True
|
|
270
277
|
)
|
|
@@ -330,7 +337,7 @@ def single_and_tiled_shared_workflow(args, left_primer_candidates, right_primer_
|
|
|
330
337
|
return all_primers, amplicons
|
|
331
338
|
|
|
332
339
|
|
|
333
|
-
def single_workflow(args, amplicons,
|
|
340
|
+
def single_workflow(args, amplicons, log_file):
|
|
334
341
|
"""
|
|
335
342
|
workflow part specific for single mode
|
|
336
343
|
"""
|
|
@@ -477,13 +484,13 @@ def qpcr_workflow(args, data_dir, alignment_cleaned, ambiguous_consensus, majori
|
|
|
477
484
|
return probe_regions, final_schemes
|
|
478
485
|
|
|
479
486
|
|
|
480
|
-
def main(
|
|
487
|
+
def main():
|
|
481
488
|
"""
|
|
482
489
|
main varvamp workflow
|
|
483
490
|
"""
|
|
484
491
|
|
|
485
492
|
# start varVAMP
|
|
486
|
-
args = get_args(
|
|
493
|
+
args = get_args(sys.argv[1:])
|
|
487
494
|
if not args.verbose:
|
|
488
495
|
sys.stdout = open(os.devnull, 'w')
|
|
489
496
|
start_time = datetime.datetime.now()
|
|
@@ -496,10 +503,10 @@ def main(sysargs=sys.argv[1:]):
|
|
|
496
503
|
alignment_cleaned, majority_consensus, ambiguous_consensus, primer_regions, left_primer_candidates, right_primer_candidates = shared_workflow(args, log_file)
|
|
497
504
|
|
|
498
505
|
# write files that are shared in all modes
|
|
499
|
-
reporting.write_regions_to_bed(primer_regions, data_dir)
|
|
506
|
+
reporting.write_regions_to_bed(primer_regions, args.name, data_dir)
|
|
500
507
|
reporting.write_alignment(data_dir, alignment_cleaned)
|
|
501
|
-
reporting.write_fasta(data_dir, "majority_consensus", majority_consensus)
|
|
502
|
-
reporting.write_fasta(results_dir, "ambiguous_consensus", ambiguous_consensus)
|
|
508
|
+
reporting.write_fasta(data_dir, f"majority_consensus", f"{args.name}_majority_consensus",majority_consensus)
|
|
509
|
+
reporting.write_fasta(results_dir, f"ambiguous_consensus", f"{args.name}_ambiguous_consensus", ambiguous_consensus)
|
|
503
510
|
|
|
504
511
|
# Functions called from here on return lists of amplicons that are refined step-wise into final schemes.
|
|
505
512
|
# These lists that are passed between functions and later used for reporting consist of dictionary elemnts,
|
|
@@ -526,7 +533,6 @@ def main(sysargs=sys.argv[1:]):
|
|
|
526
533
|
amplicon_scheme = single_workflow(
|
|
527
534
|
args,
|
|
528
535
|
amplicons,
|
|
529
|
-
all_primers,
|
|
530
536
|
log_file
|
|
531
537
|
)
|
|
532
538
|
elif args.mode == "tiled":
|
|
@@ -549,11 +555,12 @@ def main(sysargs=sys.argv[1:]):
|
|
|
549
555
|
else:
|
|
550
556
|
# make sure amplicons with no off-target products and with low penalties get the lowest numbers
|
|
551
557
|
amplicon_scheme.sort(key=lambda x: (x.get("off_targets", False), x["penalty"]))
|
|
552
|
-
reporting.write_all_primers(data_dir, all_primers)
|
|
558
|
+
reporting.write_all_primers(data_dir, args.name, all_primers)
|
|
553
559
|
reporting.write_scheme_to_files(
|
|
554
560
|
results_dir,
|
|
555
561
|
amplicon_scheme,
|
|
556
562
|
ambiguous_consensus,
|
|
563
|
+
args.name,
|
|
557
564
|
args.mode,
|
|
558
565
|
log_file
|
|
559
566
|
)
|
|
@@ -561,10 +568,11 @@ def main(sysargs=sys.argv[1:]):
|
|
|
561
568
|
results_dir,
|
|
562
569
|
alignment_cleaned,
|
|
563
570
|
primer_regions,
|
|
571
|
+
args.name,
|
|
564
572
|
all_primers=all_primers,
|
|
565
573
|
amplicon_scheme=amplicon_scheme,
|
|
566
574
|
)
|
|
567
|
-
reporting.per_base_mismatch_plot(results_dir, amplicon_scheme, args.threshold)
|
|
575
|
+
reporting.per_base_mismatch_plot(results_dir, amplicon_scheme, args.threshold, args.name)
|
|
568
576
|
|
|
569
577
|
# QPCR mode
|
|
570
578
|
if args.mode == "qpcr":
|
|
@@ -583,16 +591,17 @@ def main(sysargs=sys.argv[1:]):
|
|
|
583
591
|
|
|
584
592
|
# make sure amplicons with no off-target products and with low penalties get the lowest numbers
|
|
585
593
|
final_schemes.sort(key=lambda x: (x.get("off_targets", False), x["penalty"]))
|
|
586
|
-
reporting.write_regions_to_bed(probe_regions, data_dir, "probe")
|
|
587
|
-
reporting.write_qpcr_to_files(results_dir, final_schemes, ambiguous_consensus, log_file)
|
|
594
|
+
reporting.write_regions_to_bed(probe_regions, args.name, data_dir, "probe")
|
|
595
|
+
reporting.write_qpcr_to_files(results_dir, final_schemes, ambiguous_consensus, args.name, log_file)
|
|
588
596
|
reporting.varvamp_plot(
|
|
589
597
|
results_dir,
|
|
590
598
|
alignment_cleaned,
|
|
591
599
|
primer_regions,
|
|
600
|
+
args.name,
|
|
592
601
|
probe_regions=probe_regions,
|
|
593
602
|
amplicon_scheme=final_schemes
|
|
594
603
|
)
|
|
595
|
-
reporting.per_base_mismatch_plot(results_dir, final_schemes, args.threshold, mode="QPCR")
|
|
604
|
+
reporting.per_base_mismatch_plot(results_dir, final_schemes, args.threshold, args.name, mode="QPCR")
|
|
596
605
|
|
|
597
606
|
# varVAMP finished
|
|
598
607
|
logging.varvamp_progress(log_file, progress=1, start_time=start_time)
|
|
@@ -15,12 +15,12 @@ from varvamp.scripts import config
|
|
|
15
15
|
from varvamp import __version__
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def create_dir_structure(
|
|
18
|
+
def create_dir_structure(dir_path):
|
|
19
19
|
"""
|
|
20
20
|
create output folders and log file
|
|
21
21
|
"""
|
|
22
22
|
cwd = os.getcwd()
|
|
23
|
-
results_dir = os.path.join(cwd,
|
|
23
|
+
results_dir = os.path.join(cwd, dir_path)
|
|
24
24
|
data_dir = os.path.join(results_dir, "data/")
|
|
25
25
|
# create folders
|
|
26
26
|
if not os.path.exists(results_dir):
|
|
@@ -147,7 +147,7 @@ def raise_arg_errors(args, log_file):
|
|
|
147
147
|
log_file,
|
|
148
148
|
exit=True
|
|
149
149
|
)
|
|
150
|
-
if args.overlap <
|
|
150
|
+
if args.overlap < 10:
|
|
151
151
|
raise_error(
|
|
152
152
|
"small overlaps might hinder downstream analyses. Consider increasing.",
|
|
153
153
|
log_file
|
|
@@ -567,7 +567,7 @@ def goodbye_message():
|
|
|
567
567
|
"Thank you. Come again.",
|
|
568
568
|
">Placeholder for your advertisement<",
|
|
569
569
|
"Make primers great again!",
|
|
570
|
-
"Ciao cacao!"
|
|
570
|
+
"Ciao cacao!",
|
|
571
571
|
"And now lets pray to the PCR gods.",
|
|
572
572
|
"**bibobibobop** task finished",
|
|
573
573
|
"Thank you for traveling with varVAMP.",
|
|
@@ -581,5 +581,14 @@ def goodbye_message():
|
|
|
581
581
|
"Barba non facit philosophum.",
|
|
582
582
|
"Task failed successfully.",
|
|
583
583
|
"Never gonna give you up, never gonna let you down.",
|
|
584
|
+
"Have you tried turning it off and on again?",
|
|
585
|
+
"Look, I am your primer scheme.",
|
|
586
|
+
"Quod erat demonstrandum.",
|
|
587
|
+
"Miau?",
|
|
588
|
+
"This is an automated message informing you that you are awsome.",
|
|
589
|
+
"Why was the negative-sense virus angry at the positive-sense virus?\nBecause he was left stranded!",
|
|
590
|
+
"If you see this message twice, you are an experienced user.",
|
|
591
|
+
"No one expects the spanish inquisition!",
|
|
592
|
+
"Primer design you must."
|
|
584
593
|
]
|
|
585
594
|
print(f"\n{random.choice(messages)}")
|
|
@@ -19,11 +19,11 @@ from varvamp.scripts import config
|
|
|
19
19
|
from varvamp.scripts import logging
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def write_fasta(path, seq_id, seq):
|
|
22
|
+
def write_fasta(path, file_name, seq_id, seq):
|
|
23
23
|
"""
|
|
24
24
|
write fasta files
|
|
25
25
|
"""
|
|
26
|
-
name = f"{
|
|
26
|
+
name = f"{file_name}.fasta"
|
|
27
27
|
out = os.path.join(path, name)
|
|
28
28
|
with open(out, 'w') as o:
|
|
29
29
|
print(f">{seq_id}\n{seq}", file=o)
|
|
@@ -40,7 +40,7 @@ def write_alignment(path, alignment):
|
|
|
40
40
|
print(f">{seq[0]}\n{seq[1]}", file=o)
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
def write_regions_to_bed(primer_regions, path, mode=None):
|
|
43
|
+
def write_regions_to_bed(primer_regions, scheme_name, path, mode=None):
|
|
44
44
|
"""
|
|
45
45
|
write primer regions as bed file
|
|
46
46
|
"""
|
|
@@ -53,7 +53,7 @@ def write_regions_to_bed(primer_regions, path, mode=None):
|
|
|
53
53
|
with open(outfile, 'w') as o:
|
|
54
54
|
for counter, region in enumerate(primer_regions):
|
|
55
55
|
print(
|
|
56
|
-
"
|
|
56
|
+
f"{scheme_name}_ambiguous_consensus",
|
|
57
57
|
region[0],
|
|
58
58
|
region[1],
|
|
59
59
|
"REGION_"+str(counter),
|
|
@@ -62,24 +62,28 @@ def write_regions_to_bed(primer_regions, path, mode=None):
|
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
def write_primers_to_bed(outfile, primer_name, primer_properties, direction):
|
|
65
|
+
def write_primers_to_bed(outfile, scheme_name, primer_name, primer_properties, numeric_value, direction, sequence=None):
|
|
66
66
|
"""
|
|
67
67
|
write primers as bed file
|
|
68
68
|
"""
|
|
69
69
|
with open(outfile, 'a') as o:
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
# write header for primer bed
|
|
71
|
+
data = [f"{scheme_name}_ambiguous_consensus",
|
|
72
72
|
primer_properties[1], # start
|
|
73
73
|
primer_properties[2], # stop
|
|
74
74
|
primer_name,
|
|
75
|
-
|
|
76
|
-
direction
|
|
75
|
+
numeric_value, # can be pool or score
|
|
76
|
+
direction]
|
|
77
|
+
if sequence is not None:
|
|
78
|
+
data.append(sequence)
|
|
79
|
+
print(
|
|
80
|
+
*data,
|
|
77
81
|
sep="\t",
|
|
78
82
|
file=o
|
|
79
83
|
)
|
|
80
84
|
|
|
81
85
|
|
|
82
|
-
def write_all_primers(path, all_primers):
|
|
86
|
+
def write_all_primers(path, scheme_name, all_primers):
|
|
83
87
|
"""
|
|
84
88
|
write all primers that varVAMP designed as bed file
|
|
85
89
|
"""
|
|
@@ -87,7 +91,7 @@ def write_all_primers(path, all_primers):
|
|
|
87
91
|
|
|
88
92
|
for direction in all_primers:
|
|
89
93
|
for primer in all_primers[direction]:
|
|
90
|
-
write_primers_to_bed(outfile, primer, all_primers[direction][primer], direction)
|
|
94
|
+
write_primers_to_bed(outfile, scheme_name, primer, all_primers[direction][primer], round(all_primers[direction][primer][3], 2), direction)
|
|
91
95
|
|
|
92
96
|
|
|
93
97
|
def get_permutations(seq):
|
|
@@ -120,7 +124,7 @@ def calc_mean_stats(permutations):
|
|
|
120
124
|
return round(gc/len(permutations), 1), round(temp/len(permutations), 1)
|
|
121
125
|
|
|
122
126
|
|
|
123
|
-
def write_qpcr_to_files(path, final_schemes, ambiguous_consensus, log_file):
|
|
127
|
+
def write_qpcr_to_files(path, final_schemes, ambiguous_consensus, scheme_name, log_file):
|
|
124
128
|
"""
|
|
125
129
|
write all relevant bed files and tsv file for the qPCR design
|
|
126
130
|
"""
|
|
@@ -141,10 +145,10 @@ def write_qpcr_to_files(path, final_schemes, ambiguous_consensus, log_file):
|
|
|
141
145
|
file=tsv
|
|
142
146
|
)
|
|
143
147
|
for n, amp in enumerate(final_schemes):
|
|
144
|
-
amp_name = f"
|
|
148
|
+
amp_name = f"{scheme_name}_{n}"
|
|
145
149
|
# write bed amplicon file
|
|
146
150
|
print(
|
|
147
|
-
"
|
|
151
|
+
f"{scheme_name}_ambiguous_consensus",
|
|
148
152
|
amp["LEFT"][1],
|
|
149
153
|
amp["RIGHT"][2],
|
|
150
154
|
amp_name,
|
|
@@ -188,6 +192,7 @@ def write_qpcr_to_files(path, final_schemes, ambiguous_consensus, log_file):
|
|
|
188
192
|
|
|
189
193
|
permutations = get_permutations(seq)
|
|
190
194
|
gc, temp = calc_mean_stats(permutations)
|
|
195
|
+
primer_name = f"{amp_name}_{oligo_type}"
|
|
191
196
|
|
|
192
197
|
print(
|
|
193
198
|
amp_name,
|
|
@@ -208,15 +213,18 @@ def write_qpcr_to_files(path, final_schemes, ambiguous_consensus, log_file):
|
|
|
208
213
|
# write primer bed file
|
|
209
214
|
write_primers_to_bed(
|
|
210
215
|
primer_bed_file,
|
|
211
|
-
|
|
216
|
+
scheme_name,
|
|
217
|
+
primer_name,
|
|
212
218
|
amp[oligo_type],
|
|
213
|
-
|
|
219
|
+
round(amp[oligo_type][3], 2),
|
|
220
|
+
direction,
|
|
221
|
+
seq.upper()
|
|
214
222
|
)
|
|
215
223
|
# write fasta
|
|
216
|
-
print(f">{
|
|
224
|
+
print(f">{primer_name}\n{seq.upper()}", file=fasta)
|
|
217
225
|
|
|
218
226
|
|
|
219
|
-
def write_scheme_to_files(path, amplicon_scheme, ambiguous_consensus, mode, log_file):
|
|
227
|
+
def write_scheme_to_files(path, amplicon_scheme, ambiguous_consensus, scheme_name, mode, log_file):
|
|
220
228
|
"""
|
|
221
229
|
write all relevant bed files and a tsv file with all primer stats
|
|
222
230
|
"""
|
|
@@ -229,7 +237,7 @@ def write_scheme_to_files(path, amplicon_scheme, ambiguous_consensus, mode, log_
|
|
|
229
237
|
with open(tsv_file, "w") as tsv, open(amplicon_bed_file, "w") as bed, open(tabular_file, "w") as tabular:
|
|
230
238
|
# write header for primer tsv
|
|
231
239
|
print(
|
|
232
|
-
"amlicon_name\tamplicon_length\tprimer_name\
|
|
240
|
+
"amlicon_name\tamplicon_length\tprimer_name\tprimer_name_all_primers\tpool\tstart\tstop\tseq\tsize\tgc_best\ttemp_best\tmean_gc\tmean_temp\tpenalty\toff_target_amplicons",
|
|
233
241
|
file=tsv
|
|
234
242
|
)
|
|
235
243
|
amplicon_bed_records = []
|
|
@@ -240,12 +248,12 @@ def write_scheme_to_files(path, amplicon_scheme, ambiguous_consensus, mode, log_
|
|
|
240
248
|
if mode == "single":
|
|
241
249
|
primer_fasta_file = os.path.join(path, "primers.fasta")
|
|
242
250
|
else:
|
|
243
|
-
primer_fasta_file = os.path.join(path, f"primers_pool_{pool}.fasta")
|
|
251
|
+
primer_fasta_file = os.path.join(path, f"primers_pool_{pool+1}.fasta")
|
|
244
252
|
with open(primer_fasta_file, "w") as primer_fasta:
|
|
245
253
|
for counter, amp in enumerate(amplicon_scheme[pool::len(pools)]):
|
|
246
254
|
# give a new amplicon name
|
|
247
255
|
amplicon_index = counter*len(pools) + pool
|
|
248
|
-
|
|
256
|
+
amp_name = f"{scheme_name}_{amplicon_index}"
|
|
249
257
|
# get left and right primers and their names
|
|
250
258
|
amp_length = amp["RIGHT"][2] - amp["LEFT"][1]
|
|
251
259
|
if "off_targets" in amp:
|
|
@@ -258,14 +266,14 @@ def write_scheme_to_files(path, amplicon_scheme, ambiguous_consensus, mode, log_
|
|
|
258
266
|
amplicon_has_off_target = "n.d."
|
|
259
267
|
# write amplicon bed
|
|
260
268
|
if mode == "tiled":
|
|
261
|
-
bed_score = pool
|
|
269
|
+
bed_score = pool+1
|
|
262
270
|
elif mode == "single":
|
|
263
271
|
bed_score = round(amp["LEFT"][3] + amp["RIGHT"][3], 1)
|
|
264
272
|
amplicon_bed_records.append(
|
|
265
273
|
(
|
|
266
274
|
amp["LEFT"][1],
|
|
267
275
|
amp["RIGHT"][2],
|
|
268
|
-
|
|
276
|
+
amp_name,
|
|
269
277
|
bed_score
|
|
270
278
|
)
|
|
271
279
|
)
|
|
@@ -273,7 +281,7 @@ def write_scheme_to_files(path, amplicon_scheme, ambiguous_consensus, mode, log_
|
|
|
273
281
|
(
|
|
274
282
|
# will need amplicon_index for sorting
|
|
275
283
|
amplicon_index,
|
|
276
|
-
(f"{
|
|
284
|
+
(f"{amp_name}_LEFT", f"{amp_name}_RIGHT")
|
|
277
285
|
)
|
|
278
286
|
)
|
|
279
287
|
# write primer tsv and primer bed
|
|
@@ -281,9 +289,9 @@ def write_scheme_to_files(path, amplicon_scheme, ambiguous_consensus, mode, log_
|
|
|
281
289
|
seq = ambiguous_consensus[primer[1]:primer[2]]
|
|
282
290
|
if direction == "-":
|
|
283
291
|
seq = primers.rev_complement(seq)
|
|
284
|
-
primer_name = f"{
|
|
292
|
+
primer_name = f"{amp_name}_RIGHT"
|
|
285
293
|
else:
|
|
286
|
-
primer_name = f"{
|
|
294
|
+
primer_name = f"{amp_name}_LEFT"
|
|
287
295
|
# write primers to fasta pool file
|
|
288
296
|
print(f">{primer_name}\n{seq.upper()}", file=primer_fasta)
|
|
289
297
|
# calc primer parameters for all permutations
|
|
@@ -291,11 +299,11 @@ def write_scheme_to_files(path, amplicon_scheme, ambiguous_consensus, mode, log_
|
|
|
291
299
|
gc, temp = calc_mean_stats(permutations)
|
|
292
300
|
# write tsv file
|
|
293
301
|
print(
|
|
294
|
-
|
|
302
|
+
amp_name,
|
|
295
303
|
amp_length,
|
|
296
304
|
primer_name,
|
|
297
305
|
primer[-1],
|
|
298
|
-
pool,
|
|
306
|
+
pool+1,
|
|
299
307
|
primer[1] + 1,
|
|
300
308
|
primer[2],
|
|
301
309
|
seq.upper(),
|
|
@@ -313,13 +321,13 @@ def write_scheme_to_files(path, amplicon_scheme, ambiguous_consensus, mode, log_
|
|
|
313
321
|
(
|
|
314
322
|
# will need amplicon_index for sorting
|
|
315
323
|
amplicon_index,
|
|
316
|
-
(primer_name, primer, direction)
|
|
324
|
+
(primer_name, primer, pool+1, direction, seq.upper())
|
|
317
325
|
)
|
|
318
326
|
)
|
|
319
327
|
# write amplicon bed with amplicons sorted by start position
|
|
320
328
|
for record in sorted(amplicon_bed_records, key=lambda x: x[0]):
|
|
321
329
|
print(
|
|
322
|
-
"
|
|
330
|
+
f"{scheme_name}_ambiguous_consensus",
|
|
323
331
|
*record,
|
|
324
332
|
".",
|
|
325
333
|
sep="\t",
|
|
@@ -336,6 +344,7 @@ def write_scheme_to_files(path, amplicon_scheme, ambiguous_consensus, mode, log_
|
|
|
336
344
|
for record in sorted(primer_bed_records):
|
|
337
345
|
write_primers_to_bed(
|
|
338
346
|
primer_bed_file,
|
|
347
|
+
scheme_name,
|
|
339
348
|
*record[1]
|
|
340
349
|
)
|
|
341
350
|
|
|
@@ -352,7 +361,7 @@ def write_dimers(path, primer_dimers):
|
|
|
352
361
|
)
|
|
353
362
|
for pool, primer1, primer2 in primer_dimers:
|
|
354
363
|
print(
|
|
355
|
-
pool,
|
|
364
|
+
pool+1,
|
|
356
365
|
primer1[1],
|
|
357
366
|
primer2[1],
|
|
358
367
|
round(primers.calc_dimer(primer1[2][0], primer2[2][0]).tm, 1),
|
|
@@ -405,7 +414,7 @@ def alignment_entropy(alignment_cleaned):
|
|
|
405
414
|
return entropy_df
|
|
406
415
|
|
|
407
416
|
|
|
408
|
-
def entropy_subplot(ax, alignment_cleaned):
|
|
417
|
+
def entropy_subplot(ax, alignment_cleaned, scheme_name):
|
|
409
418
|
"""
|
|
410
419
|
creates the entropy subplot
|
|
411
420
|
"""
|
|
@@ -417,7 +426,7 @@ def entropy_subplot(ax, alignment_cleaned):
|
|
|
417
426
|
ax[0].set_ylim((0, 1))
|
|
418
427
|
ax[0].set_xlim(0, max(entropy_df["position"]))
|
|
419
428
|
ax[0].set_ylabel("normalized Shannon's entropy")
|
|
420
|
-
ax[0].set_title("
|
|
429
|
+
ax[0].set_title(f"{scheme_name} amplicon design")
|
|
421
430
|
ax[0].spines['top'].set_visible(False)
|
|
422
431
|
ax[0].spines['right'].set_visible(False)
|
|
423
432
|
|
|
@@ -501,7 +510,7 @@ def qpcr_subplot(ax, amplicon_scheme):
|
|
|
501
510
|
ax[1].hlines(0.75, probe[1], probe[2], linewidth=5, color="darkgrey", label="probe")
|
|
502
511
|
|
|
503
512
|
|
|
504
|
-
def varvamp_plot(path, alignment_cleaned, primer_regions, all_primers=None, amplicon_scheme=None, probe_regions=None):
|
|
513
|
+
def varvamp_plot(path, alignment_cleaned, primer_regions, scheme_name, all_primers=None, amplicon_scheme=None, probe_regions=None):
|
|
505
514
|
"""
|
|
506
515
|
creates overview plot for the amplicon design
|
|
507
516
|
and per base coverage plots
|
|
@@ -514,7 +523,7 @@ def varvamp_plot(path, alignment_cleaned, primer_regions, all_primers=None, ampl
|
|
|
514
523
|
fig, ax = plt.subplots(2, 1, figsize=[22, 6], squeeze=True, sharex=True, gridspec_kw={'height_ratios': [4, 1]})
|
|
515
524
|
fig.subplots_adjust(hspace=0)
|
|
516
525
|
# entropy plot
|
|
517
|
-
entropy_subplot(ax, alignment_cleaned)
|
|
526
|
+
entropy_subplot(ax, alignment_cleaned, scheme_name)
|
|
518
527
|
# primer regions plot
|
|
519
528
|
region_subplot(ax, primer_regions)
|
|
520
529
|
# probe region plot for probes
|
|
@@ -540,43 +549,32 @@ def varvamp_plot(path, alignment_cleaned, primer_regions, all_primers=None, ampl
|
|
|
540
549
|
plt.close()
|
|
541
550
|
|
|
542
551
|
|
|
543
|
-
def
|
|
552
|
+
def get_primers_for_plot(amplicon_scheme, scheme_name, mode):
|
|
544
553
|
"""
|
|
545
554
|
get the primers for per base pair plot (single, tiled)
|
|
546
555
|
"""
|
|
547
556
|
amplicon_primers = []
|
|
548
557
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
return amplicon_primers
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
def get_QPCR_primers_for_plot(amplicon_schemes):
|
|
558
|
-
"""
|
|
559
|
-
get the primers for per base pair plot (qpcr)
|
|
560
|
-
"""
|
|
561
|
-
amplicon_primers = []
|
|
558
|
+
if mode == "SINGLE/TILED":
|
|
559
|
+
oligo_types = ["LEFT", "RIGHT"]
|
|
560
|
+
else:
|
|
561
|
+
oligo_types = ["PROBE", "LEFT", "RIGHT"]
|
|
562
562
|
|
|
563
|
-
for counter, amp in enumerate(
|
|
564
|
-
for
|
|
565
|
-
primer_name = f"
|
|
566
|
-
amplicon_primers.append((primer_name, amp[
|
|
563
|
+
for counter, amp in enumerate(amplicon_scheme):
|
|
564
|
+
for oligo_type in oligo_types:
|
|
565
|
+
primer_name = f"{scheme_name}_{counter}_{oligo_type}"
|
|
566
|
+
amplicon_primers.append((primer_name, amp[oligo_type]))
|
|
567
567
|
|
|
568
568
|
return amplicon_primers
|
|
569
569
|
|
|
570
570
|
|
|
571
|
-
def per_base_mismatch_plot(path, amplicon_scheme, threshold, mode="SINGLE/TILED"):
|
|
571
|
+
def per_base_mismatch_plot(path, amplicon_scheme, threshold, scheme_name, mode="SINGLE/TILED"):
|
|
572
572
|
"""
|
|
573
573
|
per base pair mismatch multiplot
|
|
574
574
|
"""
|
|
575
575
|
out = os.path.join(path, "per_base_mismatches.pdf")
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
elif mode == "QPCR":
|
|
579
|
-
amplicon_primers = get_QPCR_primers_for_plot(amplicon_scheme)
|
|
576
|
+
|
|
577
|
+
amplicon_primers = get_primers_for_plot(amplicon_scheme, scheme_name, mode)
|
|
580
578
|
# ini multi pdf
|
|
581
579
|
with PdfPages(out) as pdf:
|
|
582
580
|
# always print 4 primers to one page
|
|
@@ -102,14 +102,14 @@ def create_amplicon_graph(amplicons, min_overlap):
|
|
|
102
102
|
|
|
103
103
|
# add the maximum len of a primer to ensure that possible amplicon starts
|
|
104
104
|
# before the min overlap
|
|
105
|
-
min_overlap = min_overlap + config.PRIMER_SIZES[
|
|
105
|
+
min_overlap = min_overlap + config.PRIMER_SIZES[1]
|
|
106
106
|
|
|
107
107
|
for current_amplicon in amplicons:
|
|
108
108
|
# remember all vertices
|
|
109
109
|
amplicon_id = current_amplicon["id"]
|
|
110
110
|
nodes.append(amplicon_id)
|
|
111
111
|
start = current_amplicon["LEFT"][1] + current_amplicon["length"]/2
|
|
112
|
-
stop = current_amplicon["RIGHT"][
|
|
112
|
+
stop = current_amplicon["RIGHT"][1] - min_overlap
|
|
113
113
|
for next_amplicon in amplicons:
|
|
114
114
|
# check if the next amplicon lies within the start/stop range of
|
|
115
115
|
# the current amplicon and if its non-overlapping part is large
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: varvamp
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: Variable VirusAMPlicons (varVAMP) is a tool to design primers for highly diverse viruses
|
|
5
5
|
Home-page: https://github.com/jonas-fuchs/varVAMP
|
|
6
6
|
Author: Dr. Jonas Fuchs
|
|
@@ -15,6 +15,15 @@ Requires-Dist: primer3-py>=1.1.0
|
|
|
15
15
|
Requires-Dist: pandas>=1.4.4
|
|
16
16
|
Requires-Dist: numpy>=1.23.3
|
|
17
17
|
Requires-Dist: seqfold>=0.7.15
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: author-email
|
|
20
|
+
Dynamic: classifier
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: description-content-type
|
|
23
|
+
Dynamic: home-page
|
|
24
|
+
Dynamic: requires-dist
|
|
25
|
+
Dynamic: requires-python
|
|
26
|
+
Dynamic: summary
|
|
18
27
|
|
|
19
28
|
|
|
20
29
|
**var**iable **V**irus**AMP**licons (varVAMP) is a tool to design primers for highly diverse viruses. The input is an alignment of your viral (full-genome) sequences.
|
|
@@ -61,15 +70,13 @@ For a lot of virus genera it is difficult to design pan-specific primers. varVAM
|
|
|
61
70
|
|
|
62
71
|
We, in collaboration with specialists for the respective viruses, have already designed and wet-lab evaluated primer schemes for various viral pathogens. All the input data and varVAMP outputs are freely available [here](https://github.com/jonas-fuchs/ViralPrimerSchemes).
|
|
63
72
|
|
|
64
|
-
|
|
73
|
+
Moreover, varVAMP primers are now available at [primerschemes](https://labs.primalscheme.com/). varVAMP now reports primer bed files in ARTICv3 format. Feel free to contribute newly designed schemes via this [Github repository of the QuickLab](https://github.com/quick-lab/primerschemes). Use [primal-page](https://github.com/ChrisgKent/primal-page) developed by [Chris Kent](https://github.com/ChrisgKent) to generate data for compatible pull-requests.
|
|
65
74
|
|
|
66
|
-
# Citing varVAMP
|
|
67
|
-
|
|
68
|
-
Please cite with the respective DOI of the version you used:
|
|
75
|
+
# Citing varVAMP
|
|
69
76
|
|
|
70
77
|
**varVAMP: automated pan-specific primer design for tiled full genome sequencing and qPCR of highly diverse viral pathogens.**
|
|
71
78
|
|
|
72
|
-
(
|
|
79
|
+
[biorxiv preprint](https://doi.org/10.1101/2024.05.08.593102)
|
|
73
80
|
|
|
74
81
|
---
|
|
75
82
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|