Sync from GitHub (preserve manual model files)
Browse files- StreamlitApp/StreamlitApp.py +28 -85
StreamlitApp/StreamlitApp.py
CHANGED
|
@@ -323,11 +323,10 @@ elif page == "Analyze":
|
|
| 323 |
"Molecular Weight": "Acceptable" if 500 <= mw <= 5000 else "Extreme"
|
| 324 |
}
|
| 325 |
def _info_icon(tooltip_text: str) -> str:
|
| 326 |
-
safe = _html.escape(tooltip_text, quote=
|
| 327 |
-
# Use data-tooltip + custom JS tooltip for consistent rendering in Streamlit.
|
| 328 |
return (
|
| 329 |
"<span "
|
| 330 |
-
"class='amp-
|
| 331 |
f"data-tooltip='{safe}' "
|
| 332 |
"style=\"display:inline-flex; align-items:center; justify-content:center; "
|
| 333 |
"margin-left:6px; width:16px; height:16px; border-radius:50%; "
|
|
@@ -339,6 +338,29 @@ elif page == "Analyze":
|
|
| 339 |
hydro_label = f"Hydrophobic Fraction{_info_icon('Fraction of residues that prefer non-aqueous environments')}"
|
| 340 |
charge_label = f"Net Charge{_info_icon('Positive charge helps peptides bind bacterial membranes')}"
|
| 341 |
table_html = (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
"<table style='width:100%; border-collapse:collapse;'>"
|
| 343 |
"<thead>"
|
| 344 |
"<tr>"
|
|
@@ -357,74 +379,6 @@ elif page == "Analyze":
|
|
| 357 |
)
|
| 358 |
st.markdown(table_html, unsafe_allow_html=True)
|
| 359 |
|
| 360 |
-
# Custom tooltips for the inline (i) icons above.
|
| 361 |
-
# This avoids Streamlit/browser differences where `title=` may show as '?'.
|
| 362 |
-
components.html(
|
| 363 |
-
"""
|
| 364 |
-
<style>
|
| 365 |
-
.amp-tooltip {
|
| 366 |
-
position: fixed;
|
| 367 |
-
z-index: 9999;
|
| 368 |
-
display: none;
|
| 369 |
-
max-width: 320px;
|
| 370 |
-
padding: 8px 10px;
|
| 371 |
-
border-radius: 8px;
|
| 372 |
-
background: rgba(30, 30, 30, 0.95);
|
| 373 |
-
color: #fff;
|
| 374 |
-
font-size: 12px;
|
| 375 |
-
line-height: 1.3;
|
| 376 |
-
pointer-events: none;
|
| 377 |
-
box-shadow: 0 8px 30px rgba(0,0,0,0.25);
|
| 378 |
-
}
|
| 379 |
-
</style>
|
| 380 |
-
<script>
|
| 381 |
-
(function(){
|
| 382 |
-
try {
|
| 383 |
-
if (document.getElementById('amp-tooltip-script')) return;
|
| 384 |
-
var script = document.createElement('script');
|
| 385 |
-
script.id = 'amp-tooltip-script';
|
| 386 |
-
// Create tooltip container once.
|
| 387 |
-
var tooltip = document.createElement('div');
|
| 388 |
-
tooltip.id = 'amp-tooltip';
|
| 389 |
-
tooltip.className = 'amp-tooltip';
|
| 390 |
-
document.body.appendChild(tooltip);
|
| 391 |
-
|
| 392 |
-
document.addEventListener('mouseover', function(e){
|
| 393 |
-
var target = e.target;
|
| 394 |
-
if (!target) return;
|
| 395 |
-
var icon = target.closest && target.closest('.amp-info');
|
| 396 |
-
if (!icon) return;
|
| 397 |
-
var text = icon.getAttribute('data-tooltip');
|
| 398 |
-
if (!text) return;
|
| 399 |
-
var t = document.getElementById('amp-tooltip');
|
| 400 |
-
if (!t) return;
|
| 401 |
-
t.textContent = text;
|
| 402 |
-
t.style.display = 'block';
|
| 403 |
-
});
|
| 404 |
-
|
| 405 |
-
document.addEventListener('mousemove', function(e){
|
| 406 |
-
var t = document.getElementById('amp-tooltip');
|
| 407 |
-
if (!t || t.style.display !== 'block') return;
|
| 408 |
-
t.style.left = (e.clientX + 12) + 'px';
|
| 409 |
-
t.style.top = (e.clientY + 12) + 'px';
|
| 410 |
-
});
|
| 411 |
-
|
| 412 |
-
document.addEventListener('mouseout', function(e){
|
| 413 |
-
var target = e.target;
|
| 414 |
-
if (!target) return;
|
| 415 |
-
var icon = target.closest && target.closest('.amp-info');
|
| 416 |
-
if (!icon) return;
|
| 417 |
-
var t = document.getElementById('amp-tooltip');
|
| 418 |
-
if (!t) return;
|
| 419 |
-
t.style.display = 'none';
|
| 420 |
-
});
|
| 421 |
-
} catch (err) {}
|
| 422 |
-
})();
|
| 423 |
-
</script>
|
| 424 |
-
""",
|
| 425 |
-
height=0,
|
| 426 |
-
)
|
| 427 |
-
|
| 428 |
st.divider()
|
| 429 |
st.subheader("Property Radar Chart")
|
| 430 |
categories = ["Length", "Hydrophobic Fraction", "Net Charge", "Molecular Weight"]
|
|
@@ -523,20 +477,9 @@ elif page == "Optimize":
|
|
| 523 |
orig_seq, orig_conf, improved_seq, improved_conf, history = st.session_state.optimize_output
|
| 524 |
st.subheader("Results")
|
| 525 |
st.write(f"**Original Sequence:** {orig_seq} — Confidence: {round(orig_conf*100,1)}%")
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
st.write(
|
| 530 |
-
f"**Optimized Sequence:** {improved_seq} — Confidence: {round(improved_conf*100,1)}%"
|
| 531 |
-
)
|
| 532 |
-
with opt_cols[1]:
|
| 533 |
-
if st.button("Copy", key="copy_opt_seq"):
|
| 534 |
-
_try_copy_to_clipboard(improved_seq)
|
| 535 |
-
toast_fn = getattr(st, "toast", None)
|
| 536 |
-
if toast_fn is not None:
|
| 537 |
-
toast_fn("Copied to clipboard")
|
| 538 |
-
else:
|
| 539 |
-
st.success("Copied to clipboard")
|
| 540 |
|
| 541 |
# Optimization Summary box
|
| 542 |
summary = optimization_summary(orig_seq, orig_conf, improved_seq, improved_conf)
|
|
|
|
| 323 |
"Molecular Weight": "Acceptable" if 500 <= mw <= 5000 else "Extreme"
|
| 324 |
}
|
| 325 |
def _info_icon(tooltip_text: str) -> str:
|
| 326 |
+
safe = _html.escape(tooltip_text, quote=False)
|
|
|
|
| 327 |
return (
|
| 328 |
"<span "
|
| 329 |
+
"class='amp-i' "
|
| 330 |
f"data-tooltip='{safe}' "
|
| 331 |
"style=\"display:inline-flex; align-items:center; justify-content:center; "
|
| 332 |
"margin-left:6px; width:16px; height:16px; border-radius:50%; "
|
|
|
|
| 338 |
hydro_label = f"Hydrophobic Fraction{_info_icon('Fraction of residues that prefer non-aqueous environments')}"
|
| 339 |
charge_label = f"Net Charge{_info_icon('Positive charge helps peptides bind bacterial membranes')}"
|
| 340 |
table_html = (
|
| 341 |
+
"<style>"
|
| 342 |
+
".amp-i{position:relative; display:inline-flex;}"
|
| 343 |
+
".amp-i::after{"
|
| 344 |
+
"content:attr(data-tooltip);"
|
| 345 |
+
"position:absolute;"
|
| 346 |
+
"left:50%;"
|
| 347 |
+
"top:125%;"
|
| 348 |
+
"transform:translateX(-50%);"
|
| 349 |
+
"max-width:320px;"
|
| 350 |
+
"white-space:normal;"
|
| 351 |
+
"padding:8px 10px;"
|
| 352 |
+
"background:rgba(30,30,30,0.95);"
|
| 353 |
+
"color:#fff;"
|
| 354 |
+
"border-radius:8px;"
|
| 355 |
+
"font-size:12px;"
|
| 356 |
+
"line-height:1.25;"
|
| 357 |
+
"box-shadow:0 8px 30px rgba(0,0,0,0.25);"
|
| 358 |
+
"opacity:0;"
|
| 359 |
+
"pointer-events:none;"
|
| 360 |
+
"z-index:9999;"
|
| 361 |
+
"}"
|
| 362 |
+
".amp-i:hover::after{opacity:1;}"
|
| 363 |
+
"</style>"
|
| 364 |
"<table style='width:100%; border-collapse:collapse;'>"
|
| 365 |
"<thead>"
|
| 366 |
"<tr>"
|
|
|
|
| 379 |
)
|
| 380 |
st.markdown(table_html, unsafe_allow_html=True)
|
| 381 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 382 |
st.divider()
|
| 383 |
st.subheader("Property Radar Chart")
|
| 384 |
categories = ["Length", "Hydrophobic Fraction", "Net Charge", "Molecular Weight"]
|
|
|
|
| 477 |
orig_seq, orig_conf, improved_seq, improved_conf, history = st.session_state.optimize_output
|
| 478 |
st.subheader("Results")
|
| 479 |
st.write(f"**Original Sequence:** {orig_seq} — Confidence: {round(orig_conf*100,1)}%")
|
| 480 |
+
st.write(
|
| 481 |
+
f"**Optimized Sequence:** {improved_seq} — Confidence: {round(improved_conf*100,1)}%"
|
| 482 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
|
| 484 |
# Optimization Summary box
|
| 485 |
summary = optimization_summary(orig_seq, orig_conf, improved_seq, improved_conf)
|