"""Proteobench Streamlit-based web server."""
from pathlib import Path
import streamlit as st
from _base import StreamlitPage
from pages.base_pages.tour_steps import get_homepage_tour_steps
# Optional guided-tour overlay; disable gracefully if streamlit_tour cannot be
# imported (e.g. version-incompatible with the installed streamlit). See base.py.
try:
from streamlit_tour import Tour
except Exception: # noqa: BLE001 - any import/component-registration failure
Tour = None
from UI_utils import (
build_submissions_figure,
build_tool_pie_chart,
get_monthly_visits,
get_n_modules,
get_n_modules_proposed,
get_n_submitted_points,
get_n_supported_tools,
stat_box,
)
@st.dialog("Tool Breakdown", width="large")
def _show_tool_breakdown(module_title, tool_counts):
pie_fig = build_tool_pie_chart(module_title, tool_counts)
st.plotly_chart(pie_fig, use_container_width=True)
fig_path = Path(__file__).resolve().parent.parent / "img" / "icons" / "png" # Adjusted to match the new structure
[docs]
class StreamlitPageHome(StreamlitPage):
"""
This class sets up the main page layout for the Streamlit application.
"""
# overwrites _main_page from StreamlitPage
# is called by initializer along sidebar and other setup
def _main_page(self):
"""
Set up the main page layout for the Streamlit application.
"""
# Navigate to DIA Astral when the homepage tour ends (finish or dismiss).
_home_tour_key = "onboarding_home"
_home_tour_active = f"stTour--{_home_tour_key}-active"
if st.session_state.get("_home_tour_in_progress", False) and not st.session_state.get(_home_tour_active, False):
st.session_state.pop("_home_tour_in_progress", None)
st.switch_page("pages/6_Quant_LFQ_DIA_ion_Astral.py")
# Placeholders TODO: replace with actual data
n_modules_all = get_n_modules()
n_modules_proposed = get_n_modules_proposed()
n_tools_supported = get_n_supported_tools()
n_of_points_submitted = get_n_submitted_points() # This function should return the number of submitted points
if (
"tracking" in st.secrets
and "matomo_endpoint" in st.secrets["tracking"]
and "matomo_idsite" in st.secrets["tracking"]
and "matomo_token" in st.secrets["tracking"]
):
monthly_visits = get_monthly_visits(
st.secrets["tracking"]["matomo_endpoint"],
st.secrets["tracking"]["matomo_token"],
st.secrets["tracking"]["matomo_idsite"],
)
else:
monthly_visits = "not configured"
if st.sidebar.button("Take a Tour", key="home_tour_trigger"):
st.session_state["start_home_tour"] = True
st.header("ProteoBench Overview")
if "_tour_opted_in" not in st.session_state:
with st.container(border=True):
col_text, col_yes, col_no = st.columns([7, 2, 1.5])
with col_text:
st.markdown(
"**Want a quick guided tour?** We will walk you through a benchmark module step by step."
)
with col_yes:
if st.button("Yes, show me!", type="primary", use_container_width=True, key="tour_opt_in_yes"):
st.session_state["_tour_opted_in"] = True
st.rerun()
with col_no:
if st.button("No, thanks!", use_container_width=True, key="tour_opt_in_no"):
st.session_state["_tour_opted_in"] = False
st.rerun()
st.markdown(
"""
<style>
.stat-card-glass {
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.6);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.3);
padding: 12px;
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.1);
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
}
.stat-card-glass h3 {
font-size: 1rem;
font-weight: 600;
margin-bottom: 8px;
}
.stat-card-glass .metric {
font-size: 1.5rem;
font-weight: 700;
margin: 0;
}
.stat-card-glass .icon {
font-size: 1.8rem;
margin-bottom: 8px;
}
</style>
""",
unsafe_allow_html=True,
)
with st.container(key="tour_stats_area"):
# First row
row1_col1, row1_col2 = st.columns(2)
with row1_col1:
st.markdown(
stat_box(
"Active modules",
n_modules_all,
fig_path / "module.png",
url="https://proteobench.readthedocs.io/en/stable/available-modules/",
),
unsafe_allow_html=True,
)
with row1_col2:
st.markdown(
stat_box(
"Modules in discussion or in development",
n_modules_proposed,
fig_path / "module-construction.png",
url="https://github.com/orgs/Proteobench/discussions",
),
unsafe_allow_html=True,
)
st.markdown("<br>", unsafe_allow_html=True)
# Second row
row2_col1, row2_col2 = st.columns(2)
with row2_col1:
st.markdown(
stat_box(
"Supported workflows and tools",
n_tools_supported,
fig_path / "workflow-run.png",
url="https://proteobench.readthedocs.io/en/stable/available-modules/12-parsed-parameters-for-public-submission/",
),
unsafe_allow_html=True,
)
with row2_col2:
st.markdown(
stat_box(
"Submitted points",
n_of_points_submitted,
fig_path / "scatter-plot.png",
url="https://proteobench.cubimed.rub.de/datasets/",
),
unsafe_allow_html=True,
)
st.markdown("<br>", unsafe_allow_html=True)
# Third row
row3 = st.columns(1)
with row3[0]:
st.markdown(
stat_box("Monthly visits", monthly_visits, fig_path / "user.png"),
unsafe_allow_html=True,
)
with st.container(key="tour_submissions_chart"):
# Submissions per module barplot
st.markdown("<br>", unsafe_allow_html=True)
st.subheader("Submissions per Module")
bar_fig, tool_data = build_submissions_figure()
if bar_fig is not None:
event = st.plotly_chart(
bar_fig,
use_container_width=True,
on_select="rerun",
selection_mode="points",
key="submissions_chart",
)
# Show pie chart in a dialog popup when a bar is clicked
selection = event.get("selection", {}) if event else {}
points = selection.get("points", [])
if points:
module_title = points[0].get("x")
if module_title and module_title in tool_data and tool_data[module_title]:
_show_tool_breakdown(module_title, tool_data[module_title])
else:
st.info("Submission data is currently unavailable.")
if Tour is not None:
tour = Tour(
get_homepage_tour_steps(),
key=_home_tour_key,
show_progress=True,
animate=True,
overlay_opacity=0.75,
one_time_tour=False,
)
if st.session_state.pop("start_home_tour", False):
# Manual button: always start regardless of opt-in.
st.session_state["_home_tour_in_progress"] = True
tour.start()
elif "_tour_opted_in" in st.session_state and "_tour_auto_home" not in st.session_state:
# User has made a decision and auto-start has not been handled yet.
st.session_state["_tour_auto_home"] = True
if st.session_state["_tour_opted_in"] is True:
st.session_state["_home_tour_in_progress"] = True
tour.start()
# Opted out: mark handled, do not start.
if __name__ == "__main__":
StreamlitPageHome()