Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,63 +1,84 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
-
import
|
| 3 |
from Bio import SeqIO
|
| 4 |
-
from
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
st.write('Upload a FASTA file with your DNA sequence and specify the desired product size range for PCR primer design.')
|
| 9 |
|
| 10 |
-
#
|
| 11 |
-
|
| 12 |
-
|
| 13 |
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
sequence_data = StringIO(fasta_file.getvalue().decode("utf-8"))
|
| 18 |
-
record = next(SeqIO.parse(sequence_data, "fasta"))
|
| 19 |
-
sequence = str(record.seq).upper() # Ensure sequence is uppercase
|
| 20 |
|
| 21 |
-
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
'PRIMER_OPT_SIZE': 20,
|
| 28 |
'PRIMER_MIN_SIZE': 18,
|
| 29 |
'PRIMER_MAX_SIZE': 23,
|
|
|
|
| 30 |
'PRIMER_MIN_TM': 57.0,
|
| 31 |
-
'
|
| 32 |
-
'
|
| 33 |
-
'
|
| 34 |
-
'
|
| 35 |
-
'PRIMER_MAX_GC': 70.0,
|
| 36 |
-
'PRIMER_MAX_POLY_X': 4,
|
| 37 |
-
'PRIMER_SALT_MONOVALENT': 50.0,
|
| 38 |
-
'PRIMER_SALT_DIVALENT': 1.5,
|
| 39 |
-
'PRIMER_DNTP_CONC': 0.6,
|
| 40 |
-
'PRIMER_NUM_RETURN': 5,
|
| 41 |
-
'PRIMER_PRODUCT_SIZE_RANGE': size_range
|
| 42 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
-
#
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
st.write(f"Right Primer (5'-3'): {primers.get(f'PRIMER_RIGHT_{i}_SEQUENCE', 'Not available')}")
|
| 57 |
-
st.write(f"Left Primer Tm: {primers.get(f'PRIMER_LEFT_{i}_TM', 'Not available')}")
|
| 58 |
-
st.write(f"Right Primer Tm: {primers.get(f'PRIMER_RIGHT_{i}_TM', 'Not available')}")
|
| 59 |
-
st.write(f"Product Size: {primers.get(f'PRIMER_PAIR_{i}_PRODUCT_SIZE', 'Not available')}")
|
| 60 |
-
except Exception as e:
|
| 61 |
-
st.error(f"An error occurred while designing primers: {e}")
|
| 62 |
-
else:
|
| 63 |
-
st.error('Please upload a valid FASTA file and specify a product size range.')
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
from Bio import SeqIO
|
| 4 |
+
from Bio.SeqFeature import SeqFeature, FeatureLocation
|
| 5 |
+
import primer3
|
| 6 |
+
import os
|
| 7 |
+
from collections import Counter
|
|
|
|
| 8 |
|
| 9 |
+
# Ensure the 'temp' directory exists for saving temporary files
|
| 10 |
+
temp_dir = "temp"
|
| 11 |
+
os.makedirs(temp_dir, exist_ok=True)
|
| 12 |
|
| 13 |
+
# Streamlit UI setup
|
| 14 |
+
st.set_page_config(page_title="PCR Primer Design", page_icon="🧬", layout="wide")
|
| 15 |
+
uploaded_file = st.file_uploader("Upload a GenBank file", type=['gb', 'gbk'])
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
+
def extract_features(genbank_path, feature_type='CDS'):
|
| 18 |
+
"""Extracts features from a GenBank file."""
|
| 19 |
+
with open(genbank_path, 'r') as file:
|
| 20 |
+
record = SeqIO.read(file, "genbank")
|
| 21 |
+
features = [feature for feature in record.features if feature.type == feature_type]
|
| 22 |
+
return features, record
|
| 23 |
|
| 24 |
+
def design_primers_for_feature(feature, sequence, num_to_return=5):
|
| 25 |
+
"""Design primers for a specific feature."""
|
| 26 |
+
start, end = int(feature.location.start), int(feature.location.end)
|
| 27 |
+
sequence_template = str(sequence)
|
| 28 |
+
target = [start, end - start]
|
| 29 |
+
primer_design_results = primer3.bindings.designPrimers(
|
| 30 |
+
{
|
| 31 |
+
'SEQUENCE_ID': feature.qualifiers.get('gene', [''])[0],
|
| 32 |
+
'SEQUENCE_TEMPLATE': sequence_template,
|
| 33 |
+
'SEQUENCE_TARGET': target,
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
'PRIMER_OPT_SIZE': 20,
|
| 37 |
'PRIMER_MIN_SIZE': 18,
|
| 38 |
'PRIMER_MAX_SIZE': 23,
|
| 39 |
+
'PRIMER_OPT_TM': 60.0,
|
| 40 |
'PRIMER_MIN_TM': 57.0,
|
| 41 |
+
'PRIMER_MAX_TM': 63.0,
|
| 42 |
+
'PRIMER_MIN_GC': 20.0,
|
| 43 |
+
'PRIMER_MAX_GC': 80.0,
|
| 44 |
+
'PRIMER_NUM_RETURN': num_to_return,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
}
|
| 46 |
+
)
|
| 47 |
+
return primer_design_results
|
| 48 |
+
|
| 49 |
+
if uploaded_file is not None:
|
| 50 |
+
temp_gb_path = os.path.join(temp_dir, uploaded_file.name)
|
| 51 |
+
with open(temp_gb_path, 'wb') as f:
|
| 52 |
+
f.write(uploaded_file.getvalue())
|
| 53 |
+
|
| 54 |
+
features, record = extract_features(temp_gb_path)
|
| 55 |
+
gene_names = [feature.qualifiers.get('gene', ['N/A'])[0] for feature in features]
|
| 56 |
+
selected_gene = st.selectbox('Select a gene to design primers for:', gene_names)
|
| 57 |
+
|
| 58 |
+
if st.button('Design Primers'):
|
| 59 |
+
selected_feature = next(feature for feature in features if feature.qualifiers.get('gene', [''])[0] == selected_gene)
|
| 60 |
+
primers = design_primers_for_feature(selected_feature, record.seq)
|
| 61 |
+
primer_df = pd.DataFrame({
|
| 62 |
+
'Primer': ['Left Primer', 'Right Primer'] * len(primers) // 2,
|
| 63 |
+
'Sequence': [primers[f'PRIMER_LEFT_{i}_SEQUENCE'] for i in range(len(primers) // 2)] +
|
| 64 |
+
[primers[f'PRIMER_RIGHT_{i}_SEQUENCE'] for i in range(len(primers) // 2)],
|
| 65 |
+
'Tm (°C)': [primers[f'PRIMER_LEFT_{i}_TM'] for i in range(len(primers) // 2)] +
|
| 66 |
+
[primers[f'PRIMER_RIGHT_{i}_TM'] for i in range(len(primers) // 2)],
|
| 67 |
+
'Length': [primers[f'PRIMER_LEFT_{i}_SIZE'] for i in range(len(primers) // 2)] +
|
| 68 |
+
[primers[f'PRIMER_RIGHT_{i}_SIZE'] for i in range(len(primers) // 2)],
|
| 69 |
+
'GC%': [primers[f'PRIMER_LEFT_{i}_GC_PERCENT'] for i in range(len(primers) // 2)] +
|
| 70 |
+
[primers[f'PRIMER_RIGHT_{i}_GC_PERCENT'] for i in range(len(primers) // 2)],
|
| 71 |
+
})
|
| 72 |
|
| 73 |
+
st.write('### Designed Primers')
|
| 74 |
+
st.dataframe(primer_df)
|
| 75 |
+
csv = primer_df.to_csv(index=False).encode('utf-8')
|
| 76 |
+
st.download_button(
|
| 77 |
+
"Download Primers as CSV",
|
| 78 |
+
csv,
|
| 79 |
+
"primers.csv",
|
| 80 |
+
"text/csv",
|
| 81 |
+
key='download-csv'
|
| 82 |
+
)
|
| 83 |
+
else:
|
| 84 |
+
st.warning("Please upload a GenBank file.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|