Upload app.py
Browse files
app.py
ADDED
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from Bio.Blast import NCBIWWW, NCBIXML
|
2 |
+
from Bio.Seq import Seq
|
3 |
+
from Bio import SeqIO
|
4 |
+
from Bio.SeqUtils import GC
|
5 |
+
import time
|
6 |
+
import warnings
|
7 |
+
import streamlit as st
|
8 |
+
from PIL import Image
|
9 |
+
from io import StringIO
|
10 |
+
|
11 |
+
img = Image.open("image.png")
|
12 |
+
|
13 |
+
st.image(img, use_column_width=True)
|
14 |
+
|
15 |
+
st.write(""" ## **Your results will display here :**
|
16 |
+
""")
|
17 |
+
def set_button_style():
|
18 |
+
button_style = """
|
19 |
+
<style>
|
20 |
+
.stButton button {
|
21 |
+
background-color: #FF6F61;
|
22 |
+
color: white;
|
23 |
+
border-radius: 100px;
|
24 |
+
border: 2px solid #FFFFFF;
|
25 |
+
box-shadow: 2px 2px 5px #000000;
|
26 |
+
width: 160px;
|
27 |
+
}
|
28 |
+
</style>
|
29 |
+
"""
|
30 |
+
st.markdown(button_style, unsafe_allow_html=True)
|
31 |
+
|
32 |
+
|
33 |
+
st.sidebar.title('Protein alignment with BLAST')
|
34 |
+
|
35 |
+
up = st.sidebar.file_uploader("Choose an existing fasta file", accept_multiple_files=False)
|
36 |
+
if up :
|
37 |
+
fasta = up.read()
|
38 |
+
|
39 |
+
|
40 |
+
seq = st.sidebar.text_area('Or enter a sequence to analyze : ')
|
41 |
+
|
42 |
+
b1 = st.sidebar.button("Calculate GC")
|
43 |
+
b2 = st.sidebar.button("Replicate")
|
44 |
+
b3 = st.sidebar.button("Transcribe")
|
45 |
+
b4 = st.sidebar.button("Back-Transcribe")
|
46 |
+
b5 = st.sidebar.button("Translate")
|
47 |
+
|
48 |
+
type = st.sidebar.text_input('Enter BLAST type : ',placeholder='exemple : blastp, blastn ...')
|
49 |
+
data = st.sidebar.text_input('Enter the database : ', placeholder='exemple : nt, nr ...')
|
50 |
+
detailed = st.sidebar.text_input('Enter detailed search : ', placeholder='Homo sapiens')
|
51 |
+
set_button_style()
|
52 |
+
b = st.sidebar.button("Run BLAST")
|
53 |
+
s = st.sidebar.button("Run detailed search")
|
54 |
+
|
55 |
+
|
56 |
+
|
57 |
+
def blast(seq, type, data):
|
58 |
+
|
59 |
+
st.write("""Starting BLAST search...""")
|
60 |
+
start_time = time.time()
|
61 |
+
result_handle2 = NCBIWWW.qblast(type, data, seq)
|
62 |
+
end_time = time.time()
|
63 |
+
|
64 |
+
st.write("""BLAST search completed.""")
|
65 |
+
st.write(f"Time taken: {end_time - start_time:.2f} seconds.")
|
66 |
+
|
67 |
+
with open("output.xml", "w") as out_handle:
|
68 |
+
out_handle.write(result_handle2.read())
|
69 |
+
st.write("Results saved to output.xml")
|
70 |
+
st.write("===================================")
|
71 |
+
result_handle = open("output.xml")
|
72 |
+
blast_record = NCBIXML.read(result_handle)
|
73 |
+
st.write(""" **Results :** """)
|
74 |
+
count = 0
|
75 |
+
for alignment in blast_record.alignments:
|
76 |
+
st.write("**"+str(alignment.title)+"**")
|
77 |
+
for hsp in alignment.hsps:
|
78 |
+
st.write(str(hsp.query[0:50]))
|
79 |
+
st.write(str(hsp.query[0:50]))
|
80 |
+
st.write(str(hsp.query[0:50]))
|
81 |
+
percentage_result = (hsp.query_end - hsp.query_start + 1) / hsp.align_length * 100
|
82 |
+
st.write(str(hsp))
|
83 |
+
if percentage_result >= 50:
|
84 |
+
st.write(f'<p style="color:green;">{percentage_result:.2f}</p>', unsafe_allow_html=True)
|
85 |
+
else:
|
86 |
+
st.write(f'<p style="color:red;">{percentage_result:.2f}</p>', unsafe_allow_html=True)
|
87 |
+
count += 1
|
88 |
+
if count == 10:
|
89 |
+
break
|
90 |
+
|
91 |
+
def detailed_search(detailed):
|
92 |
+
|
93 |
+
result_handle = open("output.xml")
|
94 |
+
blast_record = NCBIXML.read(result_handle)
|
95 |
+
|
96 |
+
st.write(" Detailed search on : " + "**" + str(detailed) + "**")
|
97 |
+
for alignment in blast_record.alignments:
|
98 |
+
if detailed in alignment.title:
|
99 |
+
st.write(str(alignment.title))
|
100 |
+
for hsp in alignment.hsps:
|
101 |
+
st.write(str(hsp.query[0:50]))
|
102 |
+
st.write(str(hsp.match[0:50]))
|
103 |
+
st.write(str(hsp.sbjct[0:50]))
|
104 |
+
st.write(str(hsp.positives) + str(hsp.score) + str(hsp.expect) + str(hsp.bits) + str(hsp.gaps))
|
105 |
+
|
106 |
+
def save_seq(seq):
|
107 |
+
with open("sequenceinput.fsa", "w") as file:
|
108 |
+
file.write(str(seq))
|
109 |
+
st.write("sequence saved to sequenceinput.fsa")
|
110 |
+
|
111 |
+
if seq :
|
112 |
+
save_seq(seq)
|
113 |
+
|
114 |
+
if (seq and type and data and b) :
|
115 |
+
blast(seq, type, data)
|
116 |
+
elif (up and type and data and b) :
|
117 |
+
blast(fasta, type, data)
|
118 |
+
|
119 |
+
if detailed and s :
|
120 |
+
detailed_search(detailed)
|
121 |
+
|
122 |
+
|
123 |
+
def calculate(seq):
|
124 |
+
with warnings.catch_warnings():
|
125 |
+
warnings.simplefilter("ignore") # Ignore all warnings
|
126 |
+
gc_content = GC(seq)
|
127 |
+
st.write(f"### **GC :** {gc_content}")
|
128 |
+
|
129 |
+
if seq and b1 :
|
130 |
+
calculate(seq)
|
131 |
+
elif up and b1 :
|
132 |
+
calculate(fasta.decode())
|
133 |
+
|
134 |
+
def reverse(seq):
|
135 |
+
sequence = Seq(seq)
|
136 |
+
r_seq = sequence.reverse_complement()
|
137 |
+
chunked_r_seq = [r_seq[i:i+50] for i in range(0, len(r_seq), 50)]
|
138 |
+
|
139 |
+
st.write("### **Reversed sequence :**")
|
140 |
+
for chunk in chunked_r_seq:
|
141 |
+
st.write("#### " + str(chunk))
|
142 |
+
|
143 |
+
if seq and b2 :
|
144 |
+
reverse(seq)
|
145 |
+
elif up and b2 :
|
146 |
+
reverse(fasta)
|
147 |
+
|
148 |
+
def transcribe_seq(seq):
|
149 |
+
sequence = Seq(seq)
|
150 |
+
r_seq = sequence.transcribe()
|
151 |
+
chunked_r_seq = [r_seq[i:i+50] for i in range(0, len(r_seq), 50)]
|
152 |
+
|
153 |
+
st.write("### **Transcribed sequence :** ")
|
154 |
+
for chunk in chunked_r_seq:
|
155 |
+
st.write("#### " + str(chunk))
|
156 |
+
|
157 |
+
if seq and b3 :
|
158 |
+
transcribe_seq(seq)
|
159 |
+
elif up and b3 :
|
160 |
+
transcribe_seq(fasta)
|
161 |
+
|
162 |
+
def back_transcribe_seq(seq):
|
163 |
+
sequence = Seq(seq)
|
164 |
+
r_seq = sequence.back_transcribe()
|
165 |
+
chunked_r_seq = [r_seq[i:i+50] for i in range(0, len(r_seq), 50)]
|
166 |
+
|
167 |
+
st.write("### **Back-Transcribed sequence :** ")
|
168 |
+
for chunk in chunked_r_seq:
|
169 |
+
st.write("#### " + str(chunk))
|
170 |
+
|
171 |
+
if seq and b4 :
|
172 |
+
back_transcribe_seq(seq)
|
173 |
+
elif up and b4 :
|
174 |
+
back_transcribe_seq(fasta)
|
175 |
+
|
176 |
+
def translate_seq(seq):
|
177 |
+
try :
|
178 |
+
sequence = Seq(seq)
|
179 |
+
r_seq = sequence.translate()
|
180 |
+
chunked_r_seq = [r_seq[i:i+50] for i in range(0, len(r_seq), 50)]
|
181 |
+
|
182 |
+
st.write("### **Translated sequence :** ")
|
183 |
+
for chunk in chunked_r_seq:
|
184 |
+
st.write("#### " + str(chunk))
|
185 |
+
except Exception as e:
|
186 |
+
st.write(f"#### Unable to translate this sequence! {e}")
|
187 |
+
|
188 |
+
if seq and b5 :
|
189 |
+
translate_seq(seq)
|
190 |
+
elif up and b5 :
|
191 |
+
transcribe_seq(fasta)
|