Sync from GitHub (preserve manual model files)
Browse files- .gitignore +4 -1
- StreamlitApp/StreamlitApp.py +54 -63
- StreamlitApp/utils/peptide_extras.py +29 -8
.gitignore
CHANGED
|
@@ -3,5 +3,8 @@ Data/**/*.tmp
|
|
| 3 |
Data/**/*.log
|
| 4 |
MLModels/**/*.pt
|
| 5 |
MLModels/**/*.pth
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
| 7 |
StreamlitApp/models/*.pt
|
|
|
|
| 3 |
Data/**/*.log
|
| 4 |
MLModels/**/*.pt
|
| 5 |
MLModels/**/*.pth
|
| 6 |
+
# Python bytecode (safe to ignore everywhere)
|
| 7 |
+
__pycache__/
|
| 8 |
+
*.py[cod]
|
| 9 |
+
*$py.class
|
| 10 |
StreamlitApp/models/*.pt
|
StreamlitApp/StreamlitApp.py
CHANGED
|
@@ -27,9 +27,9 @@ from utils.ui_helpers import (
|
|
| 27 |
from utils.peptide_extras import (
|
| 28 |
KNOWN_AMPS,
|
| 29 |
MAX_3D_SEQUENCE_LENGTH,
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
find_most_similar,
|
| 34 |
build_importance_map_html,
|
| 35 |
plot_helical_wheel,
|
|
@@ -405,7 +405,7 @@ elif page == "Analyze":
|
|
| 405 |
"left:50%;"
|
| 406 |
"top:125%;"
|
| 407 |
"transform:translateX(-50%);"
|
| 408 |
-
"max-width:
|
| 409 |
"white-space:normal;"
|
| 410 |
"padding:8px 10px;"
|
| 411 |
"background:rgba(30,30,30,0.95);"
|
|
@@ -558,24 +558,6 @@ elif page == "Optimize":
|
|
| 558 |
f"Hydrophobicity: **{summary['hydro_change']}** (orig {summary['hydro_orig']}, final {summary['hydro_final']})"
|
| 559 |
)
|
| 560 |
|
| 561 |
-
if improved_seq and str(improved_seq).strip():
|
| 562 |
-
st.divider()
|
| 563 |
-
st.subheader("Optimized Structure Visualization")
|
| 564 |
-
st.caption(
|
| 565 |
-
"Helix-like CA trace approximation for the optimized sequence (not an experimental fold)."
|
| 566 |
-
)
|
| 567 |
-
opt_clean = "".join(c for c in str(improved_seq).upper() if not c.isspace())
|
| 568 |
-
if len(opt_clean) > MAX_3D_SEQUENCE_LENGTH:
|
| 569 |
-
st.warning("Sequence too long for 3D visualization (max 60 residues).")
|
| 570 |
-
elif render_3d_structure(improved_seq, enhanced=False):
|
| 571 |
-
with st.expander("Visualization info", expanded=False):
|
| 572 |
-
st.markdown(STRUCTURE_3D_LEGEND_MARKDOWN)
|
| 573 |
-
st.markdown(STRUCTURE_3D_INTERPRETATION_MARKDOWN)
|
| 574 |
-
else:
|
| 575 |
-
st.info(
|
| 576 |
-
"3D view unavailable (install **py3dmol** in your environment, or try again after redeploy)."
|
| 577 |
-
)
|
| 578 |
-
|
| 579 |
st.divider()
|
| 580 |
# Mutation Heatmap
|
| 581 |
st.subheader("Mutation Heatmap (Changed Residues Highlighted)")
|
|
@@ -607,6 +589,23 @@ elif page == "Optimize":
|
|
| 607 |
# VISUALIZE PEPTIDE PAGE
|
| 608 |
elif page == "Visualize Peptide":
|
| 609 |
st.header("Visualize Peptide")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 610 |
st.caption(
|
| 611 |
"High-impact single-sequence view. **Blue / red / green / gray** match the 3D model, helical wheel, "
|
| 612 |
"and functional residue map."
|
|
@@ -617,28 +616,20 @@ elif page == "Visualize Peptide":
|
|
| 617 |
if sug:
|
| 618 |
st.session_state.visualize_peptide_input = sug
|
| 619 |
|
| 620 |
-
|
| 621 |
-
with c_btn:
|
| 622 |
-
if st.button("Use suggested sequence (Predict / Analyze / Optimize)", key="btn_viz_peptide_prefill"):
|
| 623 |
-
st.session_state.visualize_peptide_input = _prefill_peptide_viz_sequence()
|
| 624 |
-
rerun_fn = getattr(st, "rerun", None) or getattr(st, "experimental_rerun", None)
|
| 625 |
-
if rerun_fn:
|
| 626 |
-
rerun_fn()
|
| 627 |
-
with c_auto:
|
| 628 |
-
st.checkbox("Auto-run when sequence changes", value=False, key="viz_peptide_auto_run")
|
| 629 |
|
| 630 |
st.text_input(
|
| 631 |
"Peptide sequence",
|
| 632 |
key="visualize_peptide_input",
|
| 633 |
placeholder="One-letter amino-acid sequence",
|
| 634 |
-
help="
|
| 635 |
)
|
| 636 |
|
| 637 |
seq_viz = (st.session_state.get("visualize_peptide_input") or "").strip()
|
| 638 |
clean_viz = "".join(c for c in seq_viz.upper() if not c.isspace())
|
| 639 |
if not clean_viz:
|
| 640 |
st.session_state.viz_peptide_last_computed = ""
|
| 641 |
-
st.info("Enter a sequence above
|
| 642 |
else:
|
| 643 |
run_viz = st.button("Run visualization", type="primary", key="viz_peptide_run_btn")
|
| 644 |
auto_on = bool(st.session_state.get("viz_peptide_auto_run"))
|
|
@@ -666,12 +657,11 @@ elif page == "Visualize Peptide":
|
|
| 666 |
col_l, col_r = st.columns(2)
|
| 667 |
with col_l:
|
| 668 |
st.subheader("3D structural approximation (py3Dmol)")
|
| 669 |
-
st.caption("Smoothed helical CA trace; colored spheres follow the same scheme as the wheel
|
| 670 |
if len(clean_viz) <= MAX_3D_SEQUENCE_LENGTH:
|
| 671 |
-
if render_3d_structure(clean_viz, enhanced=True):
|
| 672 |
-
with st.expander("
|
| 673 |
-
st.markdown(
|
| 674 |
-
st.markdown(STRUCTURE_3D_INTERPRETATION_MARKDOWN)
|
| 675 |
else:
|
| 676 |
st.info("3D view unavailable (install **py3dmol** in your environment).")
|
| 677 |
else:
|
|
@@ -683,31 +673,32 @@ elif page == "Visualize Peptide":
|
|
| 683 |
fig_wheel = plot_helical_wheel(clean_viz)
|
| 684 |
st.pyplot(fig_wheel, use_container_width=True)
|
| 685 |
plt.close(fig_wheel)
|
| 686 |
-
with st.expander("
|
| 687 |
-
st.markdown(
|
| 688 |
-
|
| 689 |
-
|
| 690 |
-
|
| 691 |
-
|
| 692 |
-
|
| 693 |
-
|
| 694 |
-
|
| 695 |
-
|
| 696 |
-
|
| 697 |
-
|
| 698 |
-
)
|
| 699 |
-
|
| 700 |
-
|
| 701 |
-
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
|
| 705 |
-
|
| 706 |
-
|
| 707 |
-
|
| 708 |
-
st.error("Low similarity — sequence is distant from reference AMPs.")
|
| 709 |
else:
|
| 710 |
-
st.
|
|
|
|
|
|
|
| 711 |
|
| 712 |
elif clean_viz != (st.session_state.get("viz_peptide_last_computed") or ""):
|
| 713 |
st.caption("Click **Run visualization** or enable **Auto-run** to update the figures.")
|
|
@@ -816,7 +807,7 @@ PeptideAI is a lightweight Streamlit app for exploring antimicrobial peptide (AM
|
|
| 816 |
It uses a trained neural network to estimate whether a peptide is likely to be antimicrobial, then helps you interpret and improve candidates:
|
| 817 |
- **Predict**: batch predictions from multi-line or FASTA input, length warnings, persisted results, top-candidate highlight, and CSV export.
|
| 818 |
- **Analyze**: single-sequence numerical & textual analysis — AMP prediction, composition, physicochemical table + radar, and exportable report (no 3D on this page).
|
| 819 |
-
- **Optimize**: guided sequence optimization with mutation heatmap, step table, confidence vs. step plot
|
| 820 |
- **Visualize Peptide**: one sequence with consistent coloring across functional map, helical wheel, and optional 3D approximation, plus similarity to known AMPs.
|
| 821 |
- **Visualize t-SNE**: upload many sequences, embed with the model, run t-SNE, and explore clusters with filters and hover metadata.
|
| 822 |
- **About**: this overview and disclaimer.
|
|
|
|
| 27 |
from utils.peptide_extras import (
|
| 28 |
KNOWN_AMPS,
|
| 29 |
MAX_3D_SEQUENCE_LENGTH,
|
| 30 |
+
COMPACT_3D_LEGEND,
|
| 31 |
+
COMPACT_MAP_LEGEND,
|
| 32 |
+
COMPACT_WHEEL_LEGEND,
|
| 33 |
find_most_similar,
|
| 34 |
build_importance_map_html,
|
| 35 |
plot_helical_wheel,
|
|
|
|
| 405 |
"left:50%;"
|
| 406 |
"top:125%;"
|
| 407 |
"transform:translateX(-50%);"
|
| 408 |
+
"max-width:560px;"
|
| 409 |
"white-space:normal;"
|
| 410 |
"padding:8px 10px;"
|
| 411 |
"background:rgba(30,30,30,0.95);"
|
|
|
|
| 558 |
f"Hydrophobicity: **{summary['hydro_change']}** (orig {summary['hydro_orig']}, final {summary['hydro_final']})"
|
| 559 |
)
|
| 560 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 561 |
st.divider()
|
| 562 |
# Mutation Heatmap
|
| 563 |
st.subheader("Mutation Heatmap (Changed Residues Highlighted)")
|
|
|
|
| 589 |
# VISUALIZE PEPTIDE PAGE
|
| 590 |
elif page == "Visualize Peptide":
|
| 591 |
st.header("Visualize Peptide")
|
| 592 |
+
# Tighter legend expanders (summary row + scrollable body)
|
| 593 |
+
st.markdown(
|
| 594 |
+
"""
|
| 595 |
+
<style>
|
| 596 |
+
div[data-testid="stExpander"] details > summary {
|
| 597 |
+
padding-top: 0.3rem !important;
|
| 598 |
+
padding-bottom: 0.3rem !important;
|
| 599 |
+
min-height: 2rem !important;
|
| 600 |
+
}
|
| 601 |
+
div[data-testid="stExpander"] details div[data-testid="stMarkdownContainer"] {
|
| 602 |
+
max-height: 6.5rem;
|
| 603 |
+
overflow-y: auto;
|
| 604 |
+
}
|
| 605 |
+
</style>
|
| 606 |
+
""",
|
| 607 |
+
unsafe_allow_html=True,
|
| 608 |
+
)
|
| 609 |
st.caption(
|
| 610 |
"High-impact single-sequence view. **Blue / red / green / gray** match the 3D model, helical wheel, "
|
| 611 |
"and functional residue map."
|
|
|
|
| 616 |
if sug:
|
| 617 |
st.session_state.visualize_peptide_input = sug
|
| 618 |
|
| 619 |
+
st.checkbox("Auto-run when sequence changes", value=False, key="viz_peptide_auto_run")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 620 |
|
| 621 |
st.text_input(
|
| 622 |
"Peptide sequence",
|
| 623 |
key="visualize_peptide_input",
|
| 624 |
placeholder="One-letter amino-acid sequence",
|
| 625 |
+
help="When empty, your last optimized / analyzed / predicted sequence is filled in automatically.",
|
| 626 |
)
|
| 627 |
|
| 628 |
seq_viz = (st.session_state.get("visualize_peptide_input") or "").strip()
|
| 629 |
clean_viz = "".join(c for c in seq_viz.upper() if not c.isspace())
|
| 630 |
if not clean_viz:
|
| 631 |
st.session_state.viz_peptide_last_computed = ""
|
| 632 |
+
st.info("Enter a sequence above (or navigate from Predict / Analyze / Optimize to auto-fill when empty).")
|
| 633 |
else:
|
| 634 |
run_viz = st.button("Run visualization", type="primary", key="viz_peptide_run_btn")
|
| 635 |
auto_on = bool(st.session_state.get("viz_peptide_auto_run"))
|
|
|
|
| 657 |
col_l, col_r = st.columns(2)
|
| 658 |
with col_l:
|
| 659 |
st.subheader("3D structural approximation (py3Dmol)")
|
| 660 |
+
st.caption("Smoothed helical CA trace; colored spheres follow the same scheme as the wheel.")
|
| 661 |
if len(clean_viz) <= MAX_3D_SEQUENCE_LENGTH:
|
| 662 |
+
if render_3d_structure(clean_viz, enhanced=True, spin=False):
|
| 663 |
+
with st.expander("3D · legend", expanded=False):
|
| 664 |
+
st.markdown(COMPACT_3D_LEGEND)
|
|
|
|
| 665 |
else:
|
| 666 |
st.info("3D view unavailable (install **py3dmol** in your environment).")
|
| 667 |
else:
|
|
|
|
| 673 |
fig_wheel = plot_helical_wheel(clean_viz)
|
| 674 |
st.pyplot(fig_wheel, use_container_width=True)
|
| 675 |
plt.close(fig_wheel)
|
| 676 |
+
with st.expander("Wheel · legend", expanded=False):
|
| 677 |
+
st.markdown(COMPACT_WHEEL_LEGEND)
|
| 678 |
+
|
| 679 |
+
st.divider()
|
| 680 |
+
st.subheader("Functional region map")
|
| 681 |
+
st.caption("Residue-level chemistry; colors align with the 3D view and wheel.")
|
| 682 |
+
st.markdown(build_importance_map_html(clean_viz), unsafe_allow_html=True)
|
| 683 |
+
with st.expander("Map · legend", expanded=False):
|
| 684 |
+
st.markdown(COMPACT_MAP_LEGEND)
|
| 685 |
+
|
| 686 |
+
st.subheader("Most similar known AMP")
|
| 687 |
+
st.caption(
|
| 688 |
+
f"Compared to **{len(KNOWN_AMPS)}** unique AMP sequences (label = 1 in `Data/ampData.csv`)."
|
| 689 |
+
)
|
| 690 |
+
match_seq, sim_score = find_most_similar(clean_viz)
|
| 691 |
+
if match_seq is not None:
|
| 692 |
+
st.write(f"**Best match:** `{match_seq}`")
|
| 693 |
+
st.write(f"**Similarity score:** **{sim_score:.3f}** (position match / max length)")
|
| 694 |
+
if sim_score > 0.6:
|
| 695 |
+
st.success("High similarity to a known AMP in the reference set.")
|
| 696 |
+
elif sim_score > 0.3:
|
| 697 |
+
st.warning("Moderate similarity — interpret with care.")
|
|
|
|
| 698 |
else:
|
| 699 |
+
st.error("Low similarity — sequence is distant from reference AMPs.")
|
| 700 |
+
else:
|
| 701 |
+
st.warning("Could not compute similarity (empty sequence after cleaning).")
|
| 702 |
|
| 703 |
elif clean_viz != (st.session_state.get("viz_peptide_last_computed") or ""):
|
| 704 |
st.caption("Click **Run visualization** or enable **Auto-run** to update the figures.")
|
|
|
|
| 807 |
It uses a trained neural network to estimate whether a peptide is likely to be antimicrobial, then helps you interpret and improve candidates:
|
| 808 |
- **Predict**: batch predictions from multi-line or FASTA input, length warnings, persisted results, top-candidate highlight, and CSV export.
|
| 809 |
- **Analyze**: single-sequence numerical & textual analysis — AMP prediction, composition, physicochemical table + radar, and exportable report (no 3D on this page).
|
| 810 |
+
- **Optimize**: guided sequence optimization with mutation heatmap, step table, and confidence vs. step plot.
|
| 811 |
- **Visualize Peptide**: one sequence with consistent coloring across functional map, helical wheel, and optional 3D approximation, plus similarity to known AMPs.
|
| 812 |
- **Visualize t-SNE**: upload many sequences, embed with the model, run t-SNE, and explore clusters with filters and hover metadata.
|
| 813 |
- **About**: this overview and disclaimer.
|
StreamlitApp/utils/peptide_extras.py
CHANGED
|
@@ -172,38 +172,58 @@ HELIX_WHEEL_LEGEND_MARKDOWN: str = """
|
|
| 172 |
Residues are placed using a **100° step** per position (common α-helical wheel convention). This is a **2D projection**, not a solved 3D structure.
|
| 173 |
"""
|
| 174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
|
| 176 |
def plot_helical_wheel(sequence: str, figsize: Tuple[float, float] = (6.2, 6.2)) -> Any:
|
| 177 |
"""
|
| 178 |
Amphipathic-style helical wheel (matplotlib polar). Colors match 3D / HTML maps.
|
|
|
|
| 179 |
"""
|
| 180 |
import matplotlib.pyplot as plt
|
|
|
|
| 181 |
|
| 182 |
clean = "".join(c for c in (sequence or "").upper() if not c.isspace())
|
| 183 |
n = len(clean)
|
| 184 |
fig, ax = plt.subplots(figsize=figsize, subplot_kw={"projection": "polar"})
|
|
|
|
| 185 |
if n == 0:
|
|
|
|
| 186 |
ax.set_title("Helical wheel (empty sequence)", pad=12)
|
| 187 |
return fig
|
| 188 |
|
|
|
|
|
|
|
| 189 |
angles_deg = np.array([i * 100.0 for i in range(n)], dtype=float) % 360.0
|
| 190 |
angles_rad = np.deg2rad(angles_deg)
|
| 191 |
width = np.deg2rad(min(360.0 / max(n, 1) * 0.92, 0.45))
|
| 192 |
r0, r1 = 0.35, 1.0
|
|
|
|
| 193 |
for i, aa in enumerate(clean):
|
| 194 |
th = angles_rad[i]
|
| 195 |
color = residue_color_mpl(aa)
|
| 196 |
-
ax.bar(th, r1 - r0, width=width, bottom=r0, color=color, edgecolor="
|
| 197 |
-
ax.text(
|
| 198 |
th,
|
| 199 |
(r0 + r1) / 2.0,
|
| 200 |
aa,
|
| 201 |
ha="center",
|
| 202 |
va="center",
|
| 203 |
-
fontsize=
|
| 204 |
-
color="
|
| 205 |
fontweight="bold",
|
| 206 |
)
|
|
|
|
| 207 |
|
| 208 |
ax.set_theta_zero_location("N")
|
| 209 |
ax.set_theta_direction(-1)
|
|
@@ -211,8 +231,7 @@ def plot_helical_wheel(sequence: str, figsize: Tuple[float, float] = (6.2, 6.2))
|
|
| 211 |
ax.set_yticklabels([])
|
| 212 |
ax.set_xticklabels([])
|
| 213 |
ax.grid(False)
|
| 214 |
-
ax.set_title("Helical wheel (α-helix projection, approximate)", pad=14, fontsize=11)
|
| 215 |
-
fig.patch.set_facecolor("white")
|
| 216 |
return fig
|
| 217 |
|
| 218 |
|
|
@@ -299,10 +318,12 @@ def render_3d_structure(
|
|
| 299 |
iframe_height: int = 420,
|
| 300 |
*,
|
| 301 |
enhanced: bool = False,
|
|
|
|
| 302 |
) -> bool:
|
| 303 |
"""
|
| 304 |
Render py3Dmol view: gray stick backbone + colored spheres per residue (CA-only PDB).
|
| 305 |
-
When enhanced=True: smoother helix path, slightly larger spheres,
|
|
|
|
| 306 |
Not a real folded structure — helix-like CA trace only.
|
| 307 |
"""
|
| 308 |
import streamlit.components.v1 as components
|
|
@@ -373,7 +394,7 @@ def render_3d_structure(
|
|
| 373 |
|
| 374 |
view.zoomTo()
|
| 375 |
|
| 376 |
-
if
|
| 377 |
try:
|
| 378 |
view.spin(True)
|
| 379 |
except Exception:
|
|
|
|
| 172 |
Residues are placed using a **100° step** per position (common α-helical wheel convention). This is a **2D projection**, not a solved 3D structure.
|
| 173 |
"""
|
| 174 |
|
| 175 |
+
# Short blurbs for compact UI expanders (Visualize Peptide page)
|
| 176 |
+
COMPACT_3D_LEGEND: str = (
|
| 177 |
+
"**Blue** K,R,H · **Red** D,E · **Green** hydrophobic (AVLIMFWY) · **Gray** other. "
|
| 178 |
+
"Helix trace is an approximation, not an experimental structure."
|
| 179 |
+
)
|
| 180 |
+
COMPACT_WHEEL_LEGEND: str = (
|
| 181 |
+
"**100°** per residue. Cationic (blue) and hydrophobic (green) faces often matter for membrane-active helices."
|
| 182 |
+
)
|
| 183 |
+
COMPACT_MAP_LEGEND: str = (
|
| 184 |
+
"Same scheme as 3D and wheel: charged vs hydrophobic distribution along the sequence."
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
|
| 188 |
def plot_helical_wheel(sequence: str, figsize: Tuple[float, float] = (6.2, 6.2)) -> Any:
|
| 189 |
"""
|
| 190 |
Amphipathic-style helical wheel (matplotlib polar). Colors match 3D / HTML maps.
|
| 191 |
+
Uses dark text for contrast on all wedge colors (avoids white-on-light issues in Streamlit).
|
| 192 |
"""
|
| 193 |
import matplotlib.pyplot as plt
|
| 194 |
+
from matplotlib import patheffects as pe
|
| 195 |
|
| 196 |
clean = "".join(c for c in (sequence or "").upper() if not c.isspace())
|
| 197 |
n = len(clean)
|
| 198 |
fig, ax = plt.subplots(figsize=figsize, subplot_kw={"projection": "polar"})
|
| 199 |
+
fig.patch.set_facecolor("white")
|
| 200 |
if n == 0:
|
| 201 |
+
ax.set_facecolor("#f5f5f5")
|
| 202 |
ax.set_title("Helical wheel (empty sequence)", pad=12)
|
| 203 |
return fig
|
| 204 |
|
| 205 |
+
ax.set_facecolor("#f5f5f5")
|
| 206 |
+
|
| 207 |
angles_deg = np.array([i * 100.0 for i in range(n)], dtype=float) % 360.0
|
| 208 |
angles_rad = np.deg2rad(angles_deg)
|
| 209 |
width = np.deg2rad(min(360.0 / max(n, 1) * 0.92, 0.45))
|
| 210 |
r0, r1 = 0.35, 1.0
|
| 211 |
+
fs = max(7, min(12, int(240 / max(n, 1))))
|
| 212 |
for i, aa in enumerate(clean):
|
| 213 |
th = angles_rad[i]
|
| 214 |
color = residue_color_mpl(aa)
|
| 215 |
+
ax.bar(th, r1 - r0, width=width, bottom=r0, color=color, edgecolor="#222222", linewidth=0.5, align="center")
|
| 216 |
+
t = ax.text(
|
| 217 |
th,
|
| 218 |
(r0 + r1) / 2.0,
|
| 219 |
aa,
|
| 220 |
ha="center",
|
| 221 |
va="center",
|
| 222 |
+
fontsize=fs,
|
| 223 |
+
color="#111111",
|
| 224 |
fontweight="bold",
|
| 225 |
)
|
| 226 |
+
t.set_path_effects([pe.withStroke(linewidth=2.5, foreground="white")])
|
| 227 |
|
| 228 |
ax.set_theta_zero_location("N")
|
| 229 |
ax.set_theta_direction(-1)
|
|
|
|
| 231 |
ax.set_yticklabels([])
|
| 232 |
ax.set_xticklabels([])
|
| 233 |
ax.grid(False)
|
| 234 |
+
ax.set_title("Helical wheel (α-helix projection, approximate)", pad=14, fontsize=11, color="#111111")
|
|
|
|
| 235 |
return fig
|
| 236 |
|
| 237 |
|
|
|
|
| 318 |
iframe_height: int = 420,
|
| 319 |
*,
|
| 320 |
enhanced: bool = False,
|
| 321 |
+
spin: bool = False,
|
| 322 |
) -> bool:
|
| 323 |
"""
|
| 324 |
Render py3Dmol view: gray stick backbone + colored spheres per residue (CA-only PDB).
|
| 325 |
+
When enhanced=True: smoother helix path, slightly larger spheres, more labels.
|
| 326 |
+
When spin=True: enable viewer spin (off by default).
|
| 327 |
Not a real folded structure — helix-like CA trace only.
|
| 328 |
"""
|
| 329 |
import streamlit.components.v1 as components
|
|
|
|
| 394 |
|
| 395 |
view.zoomTo()
|
| 396 |
|
| 397 |
+
if spin:
|
| 398 |
try:
|
| 399 |
view.spin(True)
|
| 400 |
except Exception:
|