Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve primer params options, funestus bugfix from v2.0.5 #61

Merged
merged 5 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 19 additions & 50 deletions AnoPrimer/design.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
_convert_results_dict_naming,
_return_oligo_list,
extract_trailing_digits,
load_params_json,
retrieve_data_resource,
)

Expand Down Expand Up @@ -46,9 +47,9 @@ def design_primers(
target : str
The target to design primers for. For gDNA primers, this should be a contig:position string,
for example '2L:28545767'. For cDNA primers, this should be an AGAP identifier.
primer_parameters : dict or 'default'
A dictionary of primer3 parameters to use for primer design. If 'default' is specified, default
primer3 parameters will be generated.
primer_parameters : dict or str ['default', 'stringent', 'relaxed']
A dictionary of primer3 parameters to use for primer design, or a string of either
'default', 'stringent' or 'relaxed' to generate default primer3 parameters.
cDNA_exon_junction : bool, optional
If True, cDNA primers will be designed to span an exon-exon junction. We strongly recommend
that this is set to True. In the case of gDNA primers, this parameter is ignored.
Expand All @@ -68,22 +69,13 @@ def design_primers(
amplicon_size_range = [[min_amplicon_size, max_amplicon_size]]

# adds some necessary parameters depending on assay type
if primer_parameters == "default":
primer_parameters = primer_params(
primer_parameters=None,
assay_type=assay_type,
n_primer_pairs=n_primer_pairs,
amplicon_size_range=amplicon_size_range,
generate_defaults=True,
)
else:
primer_parameters = primer_params(
primer_parameters=primer_parameters,
assay_type=assay_type,
n_primer_pairs=n_primer_pairs,
amplicon_size_range=amplicon_size_range,
generate_defaults=False,
)
primer_parameters = primer_params(
primer_parameters=primer_parameters,
assay_type=assay_type,
n_primer_pairs=n_primer_pairs,
amplicon_size_range=amplicon_size_range,
)

# load genome sequence
genome_seq = data_resource.genome_sequence(region=contig)
print(f"Our genome sequence for {contig} is {genome_seq.shape[0]} bp long")
Expand Down Expand Up @@ -134,7 +126,6 @@ def prepare_gDNA_sequence(
genome_seq,
assay_name,
assay_type,
probe_exclude_region_size=20,
):
"""
Extracts sequence of interest from genome sequence
Expand Down Expand Up @@ -302,7 +293,6 @@ def primer_params(
primer_parameters=None,
n_primer_pairs=None,
amplicon_size_range=None,
generate_defaults=False,
):
"""
adds necessary parameters depending on assay_type, or can
Expand All @@ -314,41 +304,20 @@ def primer_params(
The type of assay, either 'gDNA primers' or 'gDNA primers + probe', 'cDNA primers'
or 'probe'
primer_parameters : dict
A dictionary of primer3 parameters to use for primer design. If 'default' is specified, default
primer3 parameters will be generated.
Either, a dictionary of primer3 parameters to use for primer design, or a string of either
'default', 'stringent' or 'relaxed' to generate default primer3 parameters.
n_primer_pairs : int
The number of primer pairs to design.
amplicon_size_range : list
The minimum and maximum size of the amplicon to design primers for
generate_defaults : bool
If True, default primer3 parameters will be generated.
"""

if generate_defaults:
primer_parameters = {
"PRIMER_OPT_SIZE": 20,
"PRIMER_TASK": "generic",
"PRIMER_MIN_SIZE": 17,
"PRIMER_MAX_SIZE": 24,
"PRIMER_OPT_TM": 60.0,
"PRIMER_MIN_TM": 57.0,
"PRIMER_MAX_TM": 63.0,
"PRIMER_MIN_GC": 30.0,
"PRIMER_MAX_GC": 70.0,
# this parameter is the minimum distance between successive pairs.
# If 1, it means successive primer pairs could be identical bar one base shift
"PRIMER_MIN_THREE_PRIME_DISTANCE": 3,
# Probe size preferences if selected, otherwise ignored
"PRIMER_INTERNAL_OPT_SIZE": 16,
"PRIMER_INTERNAL_MIN_SIZE": 10,
"PRIMER_INTERNAL_MAX_SIZE": 22,
# Probe Tm considerations are quite relaxed, assumed that LNAs will be used
# later to affect TM
"PRIMER_INTERNAL_MIN_TM": 45,
"PRIMER_INTERNAL_MAX_TM": 65,
# Extra primer3 parameters can go here
# In the same format as above
}
if isinstance(primer_parameters, str):
primer_parameters = load_params_json(primer_parameters)
else:
assert isinstance(
primer_parameters, dict
), "primer_parameters must be a dictionary or a string"

primer_parameters["PRIMER_NUM_RETURN"] = n_primer_pairs
primer_parameters["PRIMER_PRODUCT_SIZE_RANGE"] = amplicon_size_range
Expand Down
2 changes: 1 addition & 1 deletion AnoPrimer/evaluate.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def plot_primer_locs(
return

# remove duplicate exons from different transcripts
locgff = locgff.drop_duplicates("Name")
locgff = locgff.drop_duplicates(exon_id_col)

# Set up the plot
fig, ax = plt.subplots(1, 1, figsize=[16, 4])
Expand Down
17 changes: 15 additions & 2 deletions AnoPrimer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,8 @@ def _plotly_primers(
showlegend=False,
)
if out_dir:
fig.write_html(f"{name}_{assay_type}.html")
fig.write_image(f"{name}_{assay_type}.pdf")
fig.write_html(f"{name}_{assay_type}_snps.html")
fig.write_image(f"{name}_{assay_type}_snps.pdf")
fig.show()


Expand Down Expand Up @@ -568,3 +568,16 @@ def _get_base_freqs(freqs, ref_alt_array):
base = ref_alt_array[i, i_base]
freq_df.loc[i, f"{base}_freq"] = freqs[i, i_base]
return freq_df


def load_params_json(param_type):
import requests

url = f"https://raw.githubusercontent.com/sanjaynagi/AnoPrimer/refs/heads/main/AnoPrimer/params/{param_type}.json"
# Send a GET request to the URL
response = requests.get(url)
# Raise an exception for bad status codes
response.raise_for_status()
# Parse the JSON content
data = response.json()
return data
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "AnoPrimer"
version = "2.0.5"
version = "2.0.6"
description = "A package to design primers in Anopheles gambiae whilst considering genetic variation with malariagen_data"
readme = "README.md"
documentation = "https://sanjaynagi.github.io/anoprimer/latest/"
Expand Down
Loading