Update app.py
Browse files
app.py
CHANGED
@@ -5,13 +5,7 @@
|
|
5 |
import streamlit as st
|
6 |
import pandas as pd
|
7 |
import numpy as np
|
8 |
-
# --- FIX FOR FLICKERING PLOTS IN DOCKER ---
|
9 |
-
# Explicitly set the Matplotlib backend to 'Agg' for headless environments.
|
10 |
-
# This must be done *before* importing pyplot.
|
11 |
-
import matplotlib
|
12 |
-
matplotlib.use('Agg')
|
13 |
import matplotlib.pyplot as plt
|
14 |
-
# -----------------------------------------
|
15 |
import seaborn as sns
|
16 |
import requests
|
17 |
import io
|
@@ -237,15 +231,12 @@ def plot_properties_dashboard(df: pd.DataFrame):
|
|
237 |
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
|
238 |
fig.suptitle("Molecular Properties Analysis", fontsize=16)
|
239 |
|
240 |
-
# Set transparent backgrounds
|
241 |
fig.patch.set_facecolor('none')
|
242 |
for ax_row in axes:
|
243 |
for ax in ax_row:
|
244 |
ax.set_facecolor('none')
|
245 |
|
246 |
-
|
247 |
-
drug_like_colors = df['Drug_Like'].map({True: 'green', False: 'red'})
|
248 |
-
axes[0,0].scatter(df['MW'], df['LogP'], c=drug_like_colors, s=80, alpha=0.7)
|
249 |
axes[0,0].set_title('Molecular Weight vs LogP')
|
250 |
axes[0,0].set_xlabel('Molecular Weight (Da)')
|
251 |
axes[0,0].set_ylabel('LogP')
|
@@ -253,8 +244,7 @@ def plot_properties_dashboard(df: pd.DataFrame):
|
|
253 |
axes[0,0].axhline(5, color='r', linestyle='--', alpha=0.6, label='LogP < 5')
|
254 |
axes[0,0].legend()
|
255 |
|
256 |
-
|
257 |
-
axes[0,1].scatter(df['HBD'], df['HBA'], c=drug_like_colors, s=80, alpha=0.7)
|
258 |
axes[0,1].set_title('Hydrogen Bonding Properties')
|
259 |
axes[0,1].set_xlabel('Hydrogen Bond Donors')
|
260 |
axes[0,1].set_ylabel('Hydrogen Bond Acceptors')
|
@@ -262,13 +252,11 @@ def plot_properties_dashboard(df: pd.DataFrame):
|
|
262 |
axes[0,1].axhline(10, color='r', linestyle='--', alpha=0.6, label='HBA < 10')
|
263 |
axes[0,1].legend()
|
264 |
|
265 |
-
|
266 |
-
axes[1,0].scatter(df['TPSA'], df['RotBonds'], c=drug_like_colors, s=80, alpha=0.7)
|
267 |
axes[1,0].set_title('TPSA vs Flexibility')
|
268 |
axes[1,0].set_xlabel('Topological Polar Surface Area (Ų)')
|
269 |
axes[1,0].set_ylabel('Rotatable Bonds')
|
270 |
|
271 |
-
# Plot 4: Drug-likeness pie chart
|
272 |
drug_like_counts = df['Drug_Like'].value_counts()
|
273 |
labels = ['Drug-like' if i else 'Non-drug-like' for i in drug_like_counts.index]
|
274 |
colors = ['green' if i else 'red' for i in drug_like_counts.index]
|
@@ -276,10 +264,8 @@ def plot_properties_dashboard(df: pd.DataFrame):
|
|
276 |
axes[1,1].set_title('Drug-likeness Distribution')
|
277 |
|
278 |
plt.tight_layout(rect=[0, 0, 1, 0.96])
|
279 |
-
|
280 |
-
# Return the figure without calling plt.show()
|
281 |
return fig, "✅ Generated properties dashboard."
|
282 |
-
|
283 |
# ===== Phase 2 Functions =====
|
284 |
def get_phase2_molecules():
|
285 |
return {
|
@@ -437,13 +423,12 @@ def simulate_rwd_analysis(adverse_event_text):
|
|
437 |
base_events = list(np.random.choice(['headache', 'nausea', 'fatigue', 'dizziness', 'rash', 'fever'], 100, p=[0.25, 0.2, 0.15, 0.15, 0.15, 0.1]))
|
438 |
user_events = [e.strip().lower() for e in adverse_event_text.split(',') if e.strip()]
|
439 |
all_events = base_events + user_events
|
440 |
-
|
441 |
log = f"✅ Analyzed {len(all_events)} simulated adverse event reports.\n"
|
442 |
|
443 |
plt.style.use('dark_background')
|
444 |
fig_bar, ax_bar = plt.subplots(figsize=(10, 6))
|
445 |
|
446 |
-
# Set transparent backgrounds
|
447 |
fig_bar.patch.set_facecolor('none')
|
448 |
ax_bar.set_facecolor('none')
|
449 |
|
@@ -455,7 +440,7 @@ def simulate_rwd_analysis(adverse_event_text):
|
|
455 |
plt.tight_layout()
|
456 |
|
457 |
return event_counts.reset_index().rename(columns={'index': 'Event', 0: 'Count'}), fig_bar, log
|
458 |
-
|
459 |
def get_ethical_framework():
|
460 |
framework = {'Pillar': ['1. Beneficence & Non-Maleficence', '2. Justice & Fairness', '3. Transparency & Explainability', '4. Accountability & Governance'],
|
461 |
'Description': ['AI should help patients and do no harm. Requires rigorous validation and safety monitoring.',
|
@@ -545,16 +530,7 @@ with tab1:
|
|
545 |
st.subheader("Protein 3D Structure (Interactive)")
|
546 |
st.components.v1.html(res1.get('protein_view_html', '<p>No data</p>'), height=600, scrolling=False)
|
547 |
st.subheader("FASTA Sequence Information")
|
548 |
-
|
549 |
-
# Added a label and set visibility to "collapsed" to remove the warning
|
550 |
-
# without changing the visual layout.
|
551 |
-
st.text_area(
|
552 |
-
"FASTA log output",
|
553 |
-
res1.get('fasta_log', 'No data'),
|
554 |
-
height=200,
|
555 |
-
key="fasta_info_area",
|
556 |
-
label_visibility="collapsed"
|
557 |
-
)
|
558 |
with p1_tabs[1]:
|
559 |
st.subheader("Drug-Likeness Assessment (Lipinski's Rule of Five)")
|
560 |
st.dataframe(res1.get('lipinski_subset_df', pd.DataFrame()), use_container_width=True)
|
@@ -563,7 +539,7 @@ with tab1:
|
|
563 |
with p1_tabs[2]:
|
564 |
st.subheader("Molecular Properties Dashboard")
|
565 |
if res1.get('props_plot'):
|
566 |
-
st.pyplot(res1['props_plot']
|
567 |
|
568 |
# ===== TAB 2: LEAD GENERATION & OPTIMIZATION =====
|
569 |
with tab2:
|
@@ -707,8 +683,7 @@ with tab4:
|
|
707 |
p4_tabs = st.tabs(["Pharmacovigilance Analysis", "Regulatory & Ethical Frameworks"])
|
708 |
with p4_tabs[0]:
|
709 |
st.subheader("Simulated Adverse Event Analysis")
|
710 |
-
|
711 |
-
st.pyplot(res4['plot_bar'], clear_figure=True)
|
712 |
st.dataframe(res4['rwd_df'], use_container_width=True)
|
713 |
|
714 |
with p4_tabs[1]:
|
|
|
5 |
import streamlit as st
|
6 |
import pandas as pd
|
7 |
import numpy as np
|
|
|
|
|
|
|
|
|
|
|
8 |
import matplotlib.pyplot as plt
|
|
|
9 |
import seaborn as sns
|
10 |
import requests
|
11 |
import io
|
|
|
231 |
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
|
232 |
fig.suptitle("Molecular Properties Analysis", fontsize=16)
|
233 |
|
|
|
234 |
fig.patch.set_facecolor('none')
|
235 |
for ax_row in axes:
|
236 |
for ax in ax_row:
|
237 |
ax.set_facecolor('none')
|
238 |
|
239 |
+
axes[0,0].scatter(df['MW'], df['LogP'], c=df['Drug_Like'].map({True: 'green', False: 'red'}), s=80, alpha=0.7)
|
|
|
|
|
240 |
axes[0,0].set_title('Molecular Weight vs LogP')
|
241 |
axes[0,0].set_xlabel('Molecular Weight (Da)')
|
242 |
axes[0,0].set_ylabel('LogP')
|
|
|
244 |
axes[0,0].axhline(5, color='r', linestyle='--', alpha=0.6, label='LogP < 5')
|
245 |
axes[0,0].legend()
|
246 |
|
247 |
+
axes[0,1].scatter(df['HBD'], df['HBA'], c=df['Drug_Like'].map({True: 'green', False: 'red'}), s=80, alpha=0.7)
|
|
|
248 |
axes[0,1].set_title('Hydrogen Bonding Properties')
|
249 |
axes[0,1].set_xlabel('Hydrogen Bond Donors')
|
250 |
axes[0,1].set_ylabel('Hydrogen Bond Acceptors')
|
|
|
252 |
axes[0,1].axhline(10, color='r', linestyle='--', alpha=0.6, label='HBA < 10')
|
253 |
axes[0,1].legend()
|
254 |
|
255 |
+
axes[1,0].scatter(df['TPSA'], df['RotBonds'], c=df['Drug_Like'].map({True: 'green', False: 'red'}), s=80, alpha=0.7)
|
|
|
256 |
axes[1,0].set_title('TPSA vs Flexibility')
|
257 |
axes[1,0].set_xlabel('Topological Polar Surface Area (Ų)')
|
258 |
axes[1,0].set_ylabel('Rotatable Bonds')
|
259 |
|
|
|
260 |
drug_like_counts = df['Drug_Like'].value_counts()
|
261 |
labels = ['Drug-like' if i else 'Non-drug-like' for i in drug_like_counts.index]
|
262 |
colors = ['green' if i else 'red' for i in drug_like_counts.index]
|
|
|
264 |
axes[1,1].set_title('Drug-likeness Distribution')
|
265 |
|
266 |
plt.tight_layout(rect=[0, 0, 1, 0.96])
|
|
|
|
|
267 |
return fig, "✅ Generated properties dashboard."
|
268 |
+
|
269 |
# ===== Phase 2 Functions =====
|
270 |
def get_phase2_molecules():
|
271 |
return {
|
|
|
423 |
base_events = list(np.random.choice(['headache', 'nausea', 'fatigue', 'dizziness', 'rash', 'fever'], 100, p=[0.25, 0.2, 0.15, 0.15, 0.15, 0.1]))
|
424 |
user_events = [e.strip().lower() for e in adverse_event_text.split(',') if e.strip()]
|
425 |
all_events = base_events + user_events
|
426 |
+
event_counts = pd.Series(all_events).value_counts()
|
427 |
log = f"✅ Analyzed {len(all_events)} simulated adverse event reports.\n"
|
428 |
|
429 |
plt.style.use('dark_background')
|
430 |
fig_bar, ax_bar = plt.subplots(figsize=(10, 6))
|
431 |
|
|
|
432 |
fig_bar.patch.set_facecolor('none')
|
433 |
ax_bar.set_facecolor('none')
|
434 |
|
|
|
440 |
plt.tight_layout()
|
441 |
|
442 |
return event_counts.reset_index().rename(columns={'index': 'Event', 0: 'Count'}), fig_bar, log
|
443 |
+
|
444 |
def get_ethical_framework():
|
445 |
framework = {'Pillar': ['1. Beneficence & Non-Maleficence', '2. Justice & Fairness', '3. Transparency & Explainability', '4. Accountability & Governance'],
|
446 |
'Description': ['AI should help patients and do no harm. Requires rigorous validation and safety monitoring.',
|
|
|
530 |
st.subheader("Protein 3D Structure (Interactive)")
|
531 |
st.components.v1.html(res1.get('protein_view_html', '<p>No data</p>'), height=600, scrolling=False)
|
532 |
st.subheader("FASTA Sequence Information")
|
533 |
+
st.text_area("", res1.get('fasta_log', 'No data'), height=200, key="fasta_info_area")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
534 |
with p1_tabs[1]:
|
535 |
st.subheader("Drug-Likeness Assessment (Lipinski's Rule of Five)")
|
536 |
st.dataframe(res1.get('lipinski_subset_df', pd.DataFrame()), use_container_width=True)
|
|
|
539 |
with p1_tabs[2]:
|
540 |
st.subheader("Molecular Properties Dashboard")
|
541 |
if res1.get('props_plot'):
|
542 |
+
st.pyplot(res1['props_plot'])
|
543 |
|
544 |
# ===== TAB 2: LEAD GENERATION & OPTIMIZATION =====
|
545 |
with tab2:
|
|
|
683 |
p4_tabs = st.tabs(["Pharmacovigilance Analysis", "Regulatory & Ethical Frameworks"])
|
684 |
with p4_tabs[0]:
|
685 |
st.subheader("Simulated Adverse Event Analysis")
|
686 |
+
st.pyplot(res4['plot_bar'])
|
|
|
687 |
st.dataframe(res4['rwd_df'], use_container_width=True)
|
688 |
|
689 |
with p4_tabs[1]:
|