Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- .streamlit/config.toml +8 -4
- Dockerfile +3 -1
- README.md +24 -25
- app.py +149 -99
- assets/theme.css +299 -0
- pages/1_Brain_Alignment.py +2 -0
- pages/2_Cognitive_Load.py +2 -0
- pages/3_Temporal_Dynamics.py +2 -0
- pages/4_Connectivity.py +2 -0
- pages/5_Brain_Viewer.py +2 -0
- requirements.txt +2 -0
- theme.py +131 -0
.streamlit/config.toml
CHANGED
|
@@ -1,9 +1,13 @@
|
|
| 1 |
[theme]
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
|
|
|
| 6 |
font = "sans serif"
|
| 7 |
|
| 8 |
[server]
|
| 9 |
headless = true
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
[theme]
|
| 2 |
+
base = "dark"
|
| 3 |
+
primaryColor = "#7C3AED"
|
| 4 |
+
backgroundColor = "#050510"
|
| 5 |
+
secondaryBackgroundColor = "#0F0F23"
|
| 6 |
+
textColor = "#F1F5F9"
|
| 7 |
font = "sans serif"
|
| 8 |
|
| 9 |
[server]
|
| 10 |
headless = true
|
| 11 |
+
|
| 12 |
+
[browser]
|
| 13 |
+
gatherUsageStats = false
|
Dockerfile
CHANGED
|
@@ -2,7 +2,9 @@ FROM python:3.10-slim
|
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
| 5 |
-
RUN apt-get update && apt-get install -y --no-install-recommends
|
|
|
|
|
|
|
| 6 |
|
| 7 |
COPY requirements.txt .
|
| 8 |
RUN pip install --no-cache-dir -r requirements.txt
|
|
|
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
| 5 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 6 |
+
build-essential xvfb libgl1-mesa-glx libglib2.0-0 \
|
| 7 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 8 |
|
| 9 |
COPY requirements.txt .
|
| 10 |
RUN pip install --no-cache-dir -r requirements.txt
|
README.md
CHANGED
|
@@ -1,29 +1,28 @@
|
|
| 1 |
-
---
|
| 2 |
-
title: CortexLab Dashboard
|
| 3 |
-
emoji: 🧠
|
| 4 |
-
colorFrom: purple
|
| 5 |
-
colorTo: blue
|
| 6 |
-
sdk: docker
|
| 7 |
-
app_port: 7860
|
| 8 |
-
license: cc-by-nc-4.0
|
| 9 |
-
short_description: Interactive 3D brain viewer and fMRI analysis toolkit
|
| 10 |
-
tags:
|
| 11 |
-
- neuroscience
|
| 12 |
-
- fmri
|
| 13 |
-
- brain-alignment
|
| 14 |
-
- streamlit
|
| 15 |
-
- 3d-visualization
|
| 16 |
-
pinned: false
|
| 17 |
-
---
|
| 18 |
-
|
| 19 |
# CortexLab Dashboard
|
| 20 |
|
| 21 |
-
Interactive analysis dashboard for [CortexLab](https://github.com/siddhant-rajhans/cortexlab).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
-
|
| 24 |
-
- Brain Alignment Benchmark (RSA, CKA, Procrustes + statistical testing)
|
| 25 |
-
- Cognitive Load Scorer (timeline, radar, comparison mode)
|
| 26 |
-
- Temporal Dynamics (peak latency, lag correlation, sustained/transient)
|
| 27 |
-
- ROI Connectivity (partial correlation, clustering, network graph)
|
| 28 |
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# CortexLab Dashboard
|
| 2 |
|
| 3 |
+
Interactive analysis dashboard for [CortexLab](https://github.com/siddhant-rajhans/cortexlab) - multimodal fMRI brain encoding toolkit.
|
| 4 |
+
|
| 5 |
+
## Pages
|
| 6 |
+
|
| 7 |
+
- **Brain Alignment Benchmark** - Compare AI model representations against brain responses (RSA, CKA, Procrustes)
|
| 8 |
+
- **Cognitive Load Scorer** - Visualize cognitive demand across visual, auditory, language, and executive dimensions
|
| 9 |
+
- **Temporal Dynamics** - Peak latency, lag correlations, sustained vs transient response decomposition
|
| 10 |
+
- **ROI Connectivity** - Correlation matrices, network clustering, degree centrality, graph visualization
|
| 11 |
+
|
| 12 |
+
## Quick Start
|
| 13 |
+
|
| 14 |
+
```bash
|
| 15 |
+
pip install -r requirements.txt
|
| 16 |
+
streamlit run Home.py
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
Runs on **synthetic data** by default - no GPU or real fMRI data required.
|
| 20 |
+
|
| 21 |
+
## Links
|
| 22 |
+
|
| 23 |
+
- [CortexLab Library](https://github.com/siddhant-rajhans/cortexlab)
|
| 24 |
+
- [CortexLab on HuggingFace](https://huggingface.co/SID2000/cortexlab)
|
| 25 |
|
| 26 |
+
## License
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
+
CC BY-NC 4.0
|
app.py
CHANGED
|
@@ -1,115 +1,165 @@
|
|
| 1 |
-
"""CortexLab Dashboard -
|
| 2 |
|
| 3 |
import streamlit as st
|
| 4 |
import numpy as np
|
| 5 |
|
| 6 |
-
from
|
|
|
|
| 7 |
from utils import make_roi_indices
|
|
|
|
| 8 |
|
| 9 |
-
st.set_page_config(page_title="CortexLab
|
| 10 |
init_session()
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
st.session_state["roi_indices"] = roi_indices
|
| 36 |
-
st.session_state["n_vertices"] = n_vertices
|
| 37 |
-
|
| 38 |
-
from synthetic import generate_realistic_predictions
|
| 39 |
-
predictions = generate_realistic_predictions(
|
| 40 |
-
st.session_state["n_timepoints"], roi_indices,
|
| 41 |
-
st.session_state["stimulus_type"], st.session_state["tr_seconds"],
|
| 42 |
-
seed=st.session_state["seed"],
|
| 43 |
-
)
|
| 44 |
-
st.session_state["brain_predictions"] = predictions
|
| 45 |
-
else:
|
| 46 |
-
uploaded = upload_npy_widget("Upload brain predictions (.npy, shape: timepoints x vertices)", "upload_predictions")
|
| 47 |
-
if uploaded is not None:
|
| 48 |
-
st.session_state["brain_predictions"] = uploaded
|
| 49 |
-
roi_indices, _ = make_roi_indices()
|
| 50 |
-
st.session_state["roi_indices"] = roi_indices
|
| 51 |
-
|
| 52 |
-
# --- Data Summary ---
|
| 53 |
-
roi_indices = st.session_state.get("roi_indices")
|
| 54 |
-
predictions = st.session_state.get("brain_predictions")
|
| 55 |
-
if predictions is not None and roi_indices is not None:
|
| 56 |
-
data_summary_widget(predictions, roi_indices)
|
| 57 |
-
|
| 58 |
-
# Show HRF-convolved signal preview
|
| 59 |
-
with st.expander("Data Preview", expanded=False):
|
| 60 |
-
import plotly.graph_objects as go
|
| 61 |
-
from utils import ROI_GROUPS
|
| 62 |
-
|
| 63 |
-
fig = go.Figure()
|
| 64 |
-
t = np.arange(predictions.shape[0]) * st.session_state.get("tr_seconds", 1.0)
|
| 65 |
-
colors = {"Visual": "#00D2FF", "Auditory": "#FF6B6B", "Language": "#A29BFE", "Executive": "#FFEAA7"}
|
| 66 |
-
for group, rois in ROI_GROUPS.items():
|
| 67 |
-
vals = []
|
| 68 |
-
for roi in rois:
|
| 69 |
-
if roi in roi_indices:
|
| 70 |
-
verts = roi_indices[roi]
|
| 71 |
-
valid = verts[verts < predictions.shape[1]]
|
| 72 |
-
if len(valid) > 0:
|
| 73 |
-
vals.append(np.abs(predictions[:, valid]).mean(axis=1))
|
| 74 |
-
if vals:
|
| 75 |
-
mean_tc = np.mean(vals, axis=0)
|
| 76 |
-
fig.add_trace(go.Scatter(x=t, y=mean_tc, name=group, line=dict(color=colors.get(group, "#888"), width=2)))
|
| 77 |
-
|
| 78 |
fig.update_layout(
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
legend=dict(orientation="h", yanchor="bottom", y=1.02),
|
| 82 |
)
|
| 83 |
st.plotly_chart(fig, use_container_width=True)
|
| 84 |
-
st.caption("Mean absolute activation per functional group. Note the hemodynamic response shape and modality-specific activation patterns.")
|
| 85 |
|
| 86 |
-
# ---
|
| 87 |
-
st.
|
| 88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
st.caption("RSA, CKA, Procrustes with permutation tests, bootstrap CIs, FDR correction, noise ceiling, and RDM visualization")
|
| 94 |
|
| 95 |
-
|
| 96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
|
| 98 |
with col2:
|
| 99 |
-
st.
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
st.
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
st.
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
show_analysis_log()
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""CortexLab Dashboard - Futuristic Landing Page."""
|
| 2 |
|
| 3 |
import streamlit as st
|
| 4 |
import numpy as np
|
| 5 |
|
| 6 |
+
from theme import inject_theme, hero_header, glow_card, section_header, feature_card
|
| 7 |
+
from session import init_session, show_analysis_log
|
| 8 |
from utils import make_roi_indices
|
| 9 |
+
from brain_mesh import load_fsaverage_mesh, generate_sample_activations, render_interactive_3d
|
| 10 |
|
| 11 |
+
st.set_page_config(page_title="CortexLab", page_icon="🧠", layout="wide", initial_sidebar_state="collapsed")
|
| 12 |
init_session()
|
| 13 |
+
inject_theme()
|
| 14 |
+
|
| 15 |
+
# --- Hero ---
|
| 16 |
+
hero_header(
|
| 17 |
+
"CortexLab",
|
| 18 |
+
"Enhanced multimodal fMRI brain encoding toolkit built on Meta's TRIBE v2",
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
# --- 3D Brain Hero ---
|
| 22 |
+
st.markdown("<div style='height: 0.5rem'></div>", unsafe_allow_html=True)
|
| 23 |
+
|
| 24 |
+
with st.spinner("Rendering brain..."):
|
| 25 |
+
coords, faces = load_fsaverage_mesh("left", "fsaverage5")
|
| 26 |
+
n_verts = coords.shape[0]
|
| 27 |
+
roi_indices, _ = make_roi_indices()
|
| 28 |
+
mesh_roi = {name: np.clip((idx * n_verts // 580).astype(int), 0, n_verts - 1) for name, idx in roi_indices.items()}
|
| 29 |
+
activations = generate_sample_activations(n_verts, mesh_roi, "multimodal", seed=42)
|
| 30 |
+
|
| 31 |
+
fig = render_interactive_3d(
|
| 32 |
+
coords, faces, activations, cmap="Inferno", vmin=0, vmax=0.8,
|
| 33 |
+
bg_color="#050510", initial_view="Lateral Left",
|
| 34 |
+
roi_indices=mesh_roi, show_labels=False,
|
| 35 |
+
)
|
| 36 |
+
if fig is not None:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
fig.update_layout(
|
| 38 |
+
height=500,
|
| 39 |
+
margin=dict(l=0, r=0, t=0, b=0),
|
|
|
|
| 40 |
)
|
| 41 |
st.plotly_chart(fig, use_container_width=True)
|
|
|
|
| 42 |
|
| 43 |
+
# --- Stats Bar ---
|
| 44 |
+
st.markdown("<div style='height: 0.5rem'></div>", unsafe_allow_html=True)
|
| 45 |
+
c1, c2, c3, c4, c5 = st.columns(5)
|
| 46 |
+
with c1: glow_card("Tests", "89", "All passing", "#10B981")
|
| 47 |
+
with c2: glow_card("Analysis Modules", "10", "Brain encoding", "#7C3AED")
|
| 48 |
+
with c3: glow_card("ROIs", "29", "HCP MMP1.0", "#3B82F6")
|
| 49 |
+
with c4: glow_card("Contributors", "4", "Open source", "#EC4899")
|
| 50 |
+
with c5: glow_card("License", "CC BY-NC", "Non-commercial", "#F59E0B")
|
| 51 |
|
| 52 |
+
# --- Feature Grid ---
|
| 53 |
+
st.markdown("<div style='height: 1.5rem'></div>", unsafe_allow_html=True)
|
| 54 |
+
section_header("Analysis Tools", "Everything you need for computational neuroscience research")
|
|
|
|
| 55 |
|
| 56 |
+
col1, col2, col3 = st.columns(3)
|
| 57 |
+
with col1:
|
| 58 |
+
st.markdown(feature_card(
|
| 59 |
+
"🎯", "Brain Alignment Benchmark",
|
| 60 |
+
"Score any AI model against brain responses. RSA, CKA, Procrustes with permutation tests, bootstrap CIs, and FDR correction.",
|
| 61 |
+
"#7C3AED"
|
| 62 |
+
), unsafe_allow_html=True)
|
| 63 |
+
st.page_link("pages/1_Brain_Alignment.py", label="Open Brain Alignment")
|
| 64 |
|
| 65 |
with col2:
|
| 66 |
+
st.markdown(feature_card(
|
| 67 |
+
"📊", "Cognitive Load Scorer",
|
| 68 |
+
"Predict cognitive demand across visual, auditory, language, and executive dimensions with confidence bands.",
|
| 69 |
+
"#3B82F6"
|
| 70 |
+
), unsafe_allow_html=True)
|
| 71 |
+
st.page_link("pages/2_Cognitive_Load.py", label="Open Cognitive Load")
|
| 72 |
+
|
| 73 |
+
with col3:
|
| 74 |
+
st.markdown(feature_card(
|
| 75 |
+
"⏱️", "Temporal Dynamics",
|
| 76 |
+
"Peak response latency, lag correlations, sustained vs transient decomposition, cross-ROI lag matrix.",
|
| 77 |
+
"#06B6D4"
|
| 78 |
+
), unsafe_allow_html=True)
|
| 79 |
+
st.page_link("pages/3_Temporal_Dynamics.py", label="Open Temporal Dynamics")
|
| 80 |
+
|
| 81 |
+
col4, col5, col6 = st.columns(3)
|
| 82 |
+
with col4:
|
| 83 |
+
st.markdown(feature_card(
|
| 84 |
+
"🔗", "ROI Connectivity",
|
| 85 |
+
"Functional connectivity, partial correlation, network clustering, modularity, degree and betweenness centrality.",
|
| 86 |
+
"#10B981"
|
| 87 |
+
), unsafe_allow_html=True)
|
| 88 |
+
st.page_link("pages/4_Connectivity.py", label="Open Connectivity")
|
| 89 |
+
|
| 90 |
+
with col5:
|
| 91 |
+
st.markdown(feature_card(
|
| 92 |
+
"🧠", "3D Brain Viewer",
|
| 93 |
+
"Interactive rotatable brain surface with activation overlays, publication-quality multi-view panels, ROI highlighting.",
|
| 94 |
+
"#EC4899"
|
| 95 |
+
), unsafe_allow_html=True)
|
| 96 |
+
st.page_link("pages/5_Brain_Viewer.py", label="Open Brain Viewer")
|
| 97 |
+
|
| 98 |
+
with col6:
|
| 99 |
+
st.markdown(feature_card(
|
| 100 |
+
"⚡", "Streaming Inference",
|
| 101 |
+
"Real-time sliding-window predictions for BCI pipelines. Cross-subject adaptation with minimal calibration data.",
|
| 102 |
+
"#F59E0B"
|
| 103 |
+
), unsafe_allow_html=True)
|
| 104 |
+
st.markdown(f"""
|
| 105 |
+
<a href="https://github.com/siddhant-rajhans/cortexlab" target="_blank" style="
|
| 106 |
+
display: inline-block; padding: 0.4rem 1rem;
|
| 107 |
+
color: #F59E0B; font-size: 0.85rem;
|
| 108 |
+
text-decoration: none;
|
| 109 |
+
">View on GitHub →</a>
|
| 110 |
+
""", unsafe_allow_html=True)
|
| 111 |
+
|
| 112 |
+
# --- Data Config (collapsed) ---
|
| 113 |
+
st.markdown("<div style='height: 1rem'></div>", unsafe_allow_html=True)
|
| 114 |
+
with st.expander("Data Configuration", expanded=False):
|
| 115 |
+
from session import data_summary_widget, upload_npy_widget
|
| 116 |
+
col_src, col_params = st.columns([1, 2])
|
| 117 |
+
|
| 118 |
+
with col_src:
|
| 119 |
+
source = st.radio("Data source", ["Synthetic (realistic)", "Upload your data"], index=0)
|
| 120 |
+
st.session_state["data_source"] = "synthetic" if "Synthetic" in source else "uploaded"
|
| 121 |
+
|
| 122 |
+
with col_params:
|
| 123 |
+
if st.session_state["data_source"] == "synthetic":
|
| 124 |
+
c1, c2, c3, c4 = st.columns(4)
|
| 125 |
+
st.session_state["stimulus_type"] = c1.selectbox("Stimulus", ["visual", "auditory", "language", "multimodal"])
|
| 126 |
+
st.session_state["n_timepoints"] = c2.slider("TRs", 30, 200, 80)
|
| 127 |
+
st.session_state["tr_seconds"] = c3.slider("TR (s)", 0.5, 2.0, 1.0, 0.1)
|
| 128 |
+
st.session_state["seed"] = c4.number_input("Seed", value=42, min_value=0)
|
| 129 |
+
|
| 130 |
+
roi_indices_full, n_vertices = make_roi_indices()
|
| 131 |
+
st.session_state["roi_indices"] = roi_indices_full
|
| 132 |
+
st.session_state["n_vertices"] = n_vertices
|
| 133 |
+
|
| 134 |
+
from synthetic import generate_realistic_predictions
|
| 135 |
+
predictions = generate_realistic_predictions(
|
| 136 |
+
st.session_state["n_timepoints"], roi_indices_full,
|
| 137 |
+
st.session_state["stimulus_type"], st.session_state["tr_seconds"],
|
| 138 |
+
seed=st.session_state["seed"],
|
| 139 |
+
)
|
| 140 |
+
st.session_state["brain_predictions"] = predictions
|
| 141 |
+
else:
|
| 142 |
+
uploaded = upload_npy_widget("Upload predictions (.npy)", "upload_home")
|
| 143 |
+
if uploaded is not None:
|
| 144 |
+
st.session_state["brain_predictions"] = uploaded
|
| 145 |
+
roi_indices_full, _ = make_roi_indices()
|
| 146 |
+
st.session_state["roi_indices"] = roi_indices_full
|
| 147 |
+
|
| 148 |
+
preds = st.session_state.get("brain_predictions")
|
| 149 |
+
roi_idx = st.session_state.get("roi_indices")
|
| 150 |
+
if preds is not None and roi_idx is not None:
|
| 151 |
+
data_summary_widget(preds, roi_idx)
|
| 152 |
+
|
| 153 |
+
# --- Footer ---
|
| 154 |
show_analysis_log()
|
| 155 |
+
st.markdown("""
|
| 156 |
+
<div style="text-align: center; padding: 2rem 0 1rem 0; color: #475569; font-size: 0.75rem;">
|
| 157 |
+
Built on <a href="https://github.com/facebookresearch/tribev2" style="color: #7C3AED; text-decoration: none;">Meta's TRIBE v2</a>
|
| 158 |
+
•
|
| 159 |
+
<a href="https://github.com/siddhant-rajhans/cortexlab" style="color: #3B82F6; text-decoration: none;">GitHub</a>
|
| 160 |
+
•
|
| 161 |
+
<a href="https://huggingface.co/SID2000/cortexlab" style="color: #06B6D4; text-decoration: none;">HuggingFace</a>
|
| 162 |
+
•
|
| 163 |
+
CC BY-NC 4.0
|
| 164 |
+
</div>
|
| 165 |
+
""", unsafe_allow_html=True)
|
assets/theme.css
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* CortexLab Futuristic Theme - Glassmorphism + Neon */
|
| 2 |
+
|
| 3 |
+
/* === GLOBAL === */
|
| 4 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
|
| 5 |
+
|
| 6 |
+
:root {
|
| 7 |
+
--bg-primary: #050510;
|
| 8 |
+
--bg-secondary: rgba(15, 15, 35, 0.7);
|
| 9 |
+
--bg-glass: rgba(20, 20, 50, 0.4);
|
| 10 |
+
--border-glass: rgba(100, 100, 255, 0.15);
|
| 11 |
+
--accent-purple: #7C3AED;
|
| 12 |
+
--accent-blue: #3B82F6;
|
| 13 |
+
--accent-cyan: #06B6D4;
|
| 14 |
+
--accent-pink: #EC4899;
|
| 15 |
+
--accent-green: #10B981;
|
| 16 |
+
--text-primary: #F1F5F9;
|
| 17 |
+
--text-secondary: #94A3B8;
|
| 18 |
+
--glow-purple: 0 0 20px rgba(124, 58, 237, 0.3);
|
| 19 |
+
--glow-blue: 0 0 20px rgba(59, 130, 246, 0.3);
|
| 20 |
+
--glow-cyan: 0 0 15px rgba(6, 182, 212, 0.2);
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
/* === HIDE STREAMLIT BRANDING === */
|
| 24 |
+
#MainMenu, footer, header {
|
| 25 |
+
visibility: hidden;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
div[data-testid="stToolbar"] {
|
| 29 |
+
display: none;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
div[data-testid="stDecoration"] {
|
| 33 |
+
display: none;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
/* === BASE === */
|
| 37 |
+
.stApp {
|
| 38 |
+
background: var(--bg-primary);
|
| 39 |
+
background-image:
|
| 40 |
+
radial-gradient(ellipse at 20% 50%, rgba(124, 58, 237, 0.08) 0%, transparent 50%),
|
| 41 |
+
radial-gradient(ellipse at 80% 20%, rgba(59, 130, 246, 0.06) 0%, transparent 50%),
|
| 42 |
+
radial-gradient(ellipse at 50% 80%, rgba(6, 182, 212, 0.04) 0%, transparent 50%);
|
| 43 |
+
color: var(--text-primary);
|
| 44 |
+
font-family: 'Inter', sans-serif;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
/* === SIDEBAR === */
|
| 48 |
+
section[data-testid="stSidebar"] {
|
| 49 |
+
background: linear-gradient(180deg, rgba(10, 10, 30, 0.95) 0%, rgba(5, 5, 20, 0.98) 100%);
|
| 50 |
+
border-right: 1px solid var(--border-glass);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
section[data-testid="stSidebar"] .stMarkdown h1,
|
| 54 |
+
section[data-testid="stSidebar"] .stMarkdown h2,
|
| 55 |
+
section[data-testid="stSidebar"] .stMarkdown h3 {
|
| 56 |
+
color: var(--accent-cyan);
|
| 57 |
+
font-weight: 600;
|
| 58 |
+
letter-spacing: -0.02em;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
/* === GLASSMORPHISM CONTAINERS === */
|
| 62 |
+
div[data-testid="stVerticalBlock"] > div[data-testid="stVerticalBlockBorderWrapper"] {
|
| 63 |
+
background: var(--bg-glass);
|
| 64 |
+
backdrop-filter: blur(12px);
|
| 65 |
+
-webkit-backdrop-filter: blur(12px);
|
| 66 |
+
border: 1px solid var(--border-glass);
|
| 67 |
+
border-radius: 16px;
|
| 68 |
+
padding: 1.5rem;
|
| 69 |
+
box-shadow: var(--glow-purple);
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
/* Expanders */
|
| 73 |
+
div[data-testid="stExpander"] {
|
| 74 |
+
background: var(--bg-glass);
|
| 75 |
+
backdrop-filter: blur(10px);
|
| 76 |
+
border: 1px solid var(--border-glass);
|
| 77 |
+
border-radius: 12px;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
div[data-testid="stExpander"] summary {
|
| 81 |
+
color: var(--text-primary);
|
| 82 |
+
font-weight: 500;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
/* === METRICS === */
|
| 86 |
+
div[data-testid="stMetric"] {
|
| 87 |
+
background: var(--bg-glass);
|
| 88 |
+
backdrop-filter: blur(10px);
|
| 89 |
+
border: 1px solid var(--border-glass);
|
| 90 |
+
border-radius: 12px;
|
| 91 |
+
padding: 1rem 1.2rem;
|
| 92 |
+
box-shadow: var(--glow-blue);
|
| 93 |
+
transition: all 0.3s ease;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
div[data-testid="stMetric"]:hover {
|
| 97 |
+
border-color: var(--accent-cyan);
|
| 98 |
+
box-shadow: var(--glow-cyan), 0 4px 20px rgba(6, 182, 212, 0.1);
|
| 99 |
+
transform: translateY(-2px);
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
div[data-testid="stMetric"] label {
|
| 103 |
+
color: var(--text-secondary);
|
| 104 |
+
font-size: 0.75rem;
|
| 105 |
+
text-transform: uppercase;
|
| 106 |
+
letter-spacing: 0.08em;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
div[data-testid="stMetric"] div[data-testid="stMetricValue"] {
|
| 110 |
+
color: var(--accent-cyan);
|
| 111 |
+
font-weight: 700;
|
| 112 |
+
font-size: 1.8rem;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
div[data-testid="stMetric"] div[data-testid="stMetricDelta"] {
|
| 116 |
+
color: var(--accent-green);
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
/* === HEADINGS === */
|
| 120 |
+
.stMarkdown h1 {
|
| 121 |
+
background: linear-gradient(135deg, var(--accent-purple), var(--accent-cyan));
|
| 122 |
+
-webkit-background-clip: text;
|
| 123 |
+
-webkit-text-fill-color: transparent;
|
| 124 |
+
background-clip: text;
|
| 125 |
+
font-weight: 700;
|
| 126 |
+
font-size: 2.5rem;
|
| 127 |
+
letter-spacing: -0.03em;
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
.stMarkdown h2 {
|
| 131 |
+
color: var(--text-primary);
|
| 132 |
+
font-weight: 600;
|
| 133 |
+
font-size: 1.4rem;
|
| 134 |
+
letter-spacing: -0.02em;
|
| 135 |
+
border-bottom: 1px solid var(--border-glass);
|
| 136 |
+
padding-bottom: 0.5rem;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
.stMarkdown h3 {
|
| 140 |
+
color: var(--accent-blue);
|
| 141 |
+
font-weight: 600;
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
/* === BUTTONS === */
|
| 145 |
+
.stButton > button {
|
| 146 |
+
background: linear-gradient(135deg, var(--accent-purple), var(--accent-blue));
|
| 147 |
+
color: white;
|
| 148 |
+
border: none;
|
| 149 |
+
border-radius: 10px;
|
| 150 |
+
padding: 0.6rem 1.5rem;
|
| 151 |
+
font-weight: 600;
|
| 152 |
+
letter-spacing: 0.02em;
|
| 153 |
+
transition: all 0.3s ease;
|
| 154 |
+
box-shadow: 0 4px 15px rgba(124, 58, 237, 0.3);
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
.stButton > button:hover {
|
| 158 |
+
box-shadow: 0 6px 25px rgba(124, 58, 237, 0.5);
|
| 159 |
+
transform: translateY(-2px);
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
/* === PAGE LINKS === */
|
| 163 |
+
a[data-testid="stPageLink-NavLink"] {
|
| 164 |
+
background: var(--bg-glass);
|
| 165 |
+
backdrop-filter: blur(8px);
|
| 166 |
+
border: 1px solid var(--border-glass);
|
| 167 |
+
border-radius: 12px;
|
| 168 |
+
padding: 0.8rem 1rem;
|
| 169 |
+
transition: all 0.3s ease;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
a[data-testid="stPageLink-NavLink"]:hover {
|
| 173 |
+
border-color: var(--accent-purple);
|
| 174 |
+
box-shadow: var(--glow-purple);
|
| 175 |
+
transform: translateX(4px);
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
/* === DATAFRAMES === */
|
| 179 |
+
div[data-testid="stDataFrame"] {
|
| 180 |
+
border-radius: 12px;
|
| 181 |
+
overflow: hidden;
|
| 182 |
+
border: 1px solid var(--border-glass);
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
div[data-testid="stDataFrame"] table {
|
| 186 |
+
background: var(--bg-secondary);
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
/* === SELECT / INPUT === */
|
| 190 |
+
div[data-testid="stSelectbox"],
|
| 191 |
+
div[data-testid="stMultiSelect"],
|
| 192 |
+
div[data-testid="stNumberInput"],
|
| 193 |
+
div[data-testid="stSlider"] {
|
| 194 |
+
color: var(--text-primary);
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
div[data-baseweb="select"] {
|
| 198 |
+
background: var(--bg-glass);
|
| 199 |
+
border-color: var(--border-glass);
|
| 200 |
+
border-radius: 8px;
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
/* === DIVIDER === */
|
| 204 |
+
hr {
|
| 205 |
+
border-color: var(--border-glass);
|
| 206 |
+
opacity: 0.5;
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
/* === TABS === */
|
| 210 |
+
div[data-baseweb="tab-list"] {
|
| 211 |
+
gap: 0.5rem;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
button[data-baseweb="tab"] {
|
| 215 |
+
background: var(--bg-glass);
|
| 216 |
+
border: 1px solid var(--border-glass);
|
| 217 |
+
border-radius: 8px;
|
| 218 |
+
color: var(--text-secondary);
|
| 219 |
+
transition: all 0.3s ease;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
button[data-baseweb="tab"]:hover,
|
| 223 |
+
button[data-baseweb="tab"][aria-selected="true"] {
|
| 224 |
+
background: rgba(124, 58, 237, 0.2);
|
| 225 |
+
border-color: var(--accent-purple);
|
| 226 |
+
color: var(--text-primary);
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
/* === CAPTIONS === */
|
| 230 |
+
.stCaption, .stMarkdown small, figcaption {
|
| 231 |
+
color: var(--text-secondary);
|
| 232 |
+
font-size: 0.8rem;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
/* === PLOTLY CHARTS === */
|
| 236 |
+
div[data-testid="stPlotlyChart"] {
|
| 237 |
+
border-radius: 12px;
|
| 238 |
+
overflow: hidden;
|
| 239 |
+
border: 1px solid var(--border-glass);
|
| 240 |
+
box-shadow: var(--glow-blue);
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
/* === SCROLLBAR === */
|
| 244 |
+
::-webkit-scrollbar {
|
| 245 |
+
width: 6px;
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
::-webkit-scrollbar-track {
|
| 249 |
+
background: var(--bg-primary);
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
::-webkit-scrollbar-thumb {
|
| 253 |
+
background: var(--accent-purple);
|
| 254 |
+
border-radius: 3px;
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
/* === ANIMATED GLOW BORDER FOR MAIN CONTENT === */
|
| 258 |
+
@keyframes borderGlow {
|
| 259 |
+
0%, 100% { border-color: rgba(124, 58, 237, 0.2); }
|
| 260 |
+
50% { border-color: rgba(6, 182, 212, 0.3); }
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
div[data-testid="stVerticalBlock"] > div:first-child {
|
| 264 |
+
animation: borderGlow 4s ease infinite;
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
/* === WARNING/INFO/SUCCESS === */
|
| 268 |
+
div[data-testid="stAlert"] {
|
| 269 |
+
background: var(--bg-glass);
|
| 270 |
+
backdrop-filter: blur(8px);
|
| 271 |
+
border-radius: 10px;
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
/* === SPINNER === */
|
| 275 |
+
div[data-testid="stSpinner"] {
|
| 276 |
+
color: var(--accent-cyan);
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
/* === DOWNLOAD BUTTON === */
|
| 280 |
+
.stDownloadButton > button {
|
| 281 |
+
background: transparent;
|
| 282 |
+
border: 1px solid var(--accent-cyan);
|
| 283 |
+
color: var(--accent-cyan);
|
| 284 |
+
border-radius: 8px;
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
.stDownloadButton > button:hover {
|
| 288 |
+
background: rgba(6, 182, 212, 0.1);
|
| 289 |
+
box-shadow: var(--glow-cyan);
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
/* === CODE BLOCKS === */
|
| 293 |
+
code {
|
| 294 |
+
font-family: 'JetBrains Mono', monospace;
|
| 295 |
+
background: rgba(30, 30, 60, 0.6);
|
| 296 |
+
border: 1px solid var(--border-glass);
|
| 297 |
+
border-radius: 4px;
|
| 298 |
+
color: var(--accent-cyan);
|
| 299 |
+
}
|
pages/1_Brain_Alignment.py
CHANGED
|
@@ -7,6 +7,7 @@ import plotly.graph_objects as go
|
|
| 7 |
import plotly.express as px
|
| 8 |
|
| 9 |
from session import init_session, log_analysis, carry_rois, download_csv_button, show_analysis_log
|
|
|
|
| 10 |
from utils import (
|
| 11 |
ALIGNMENT_METHODS, ROI_GROUPS, make_roi_indices,
|
| 12 |
permutation_test, bootstrap_ci, fdr_correction, noise_ceiling,
|
|
@@ -16,6 +17,7 @@ from synthetic import generate_realistic_predictions, generate_correlated_featur
|
|
| 16 |
|
| 17 |
st.set_page_config(page_title="Brain Alignment", page_icon="🎯", layout="wide")
|
| 18 |
init_session()
|
|
|
|
| 19 |
show_analysis_log()
|
| 20 |
|
| 21 |
st.title("🎯 Brain Alignment Benchmark")
|
|
|
|
| 7 |
import plotly.express as px
|
| 8 |
|
| 9 |
from session import init_session, log_analysis, carry_rois, download_csv_button, show_analysis_log
|
| 10 |
+
from theme import inject_theme, section_header
|
| 11 |
from utils import (
|
| 12 |
ALIGNMENT_METHODS, ROI_GROUPS, make_roi_indices,
|
| 13 |
permutation_test, bootstrap_ci, fdr_correction, noise_ceiling,
|
|
|
|
| 17 |
|
| 18 |
st.set_page_config(page_title="Brain Alignment", page_icon="🎯", layout="wide")
|
| 19 |
init_session()
|
| 20 |
+
inject_theme()
|
| 21 |
show_analysis_log()
|
| 22 |
|
| 23 |
st.title("🎯 Brain Alignment Benchmark")
|
pages/2_Cognitive_Load.py
CHANGED
|
@@ -7,11 +7,13 @@ import plotly.graph_objects as go
|
|
| 7 |
import plotly.express as px
|
| 8 |
|
| 9 |
from session import init_session, log_analysis, download_csv_button, show_analysis_log
|
|
|
|
| 10 |
from utils import make_roi_indices, score_cognitive_load, COGNITIVE_DIMENSIONS, ROI_GROUPS
|
| 11 |
from synthetic import generate_realistic_predictions
|
| 12 |
|
| 13 |
st.set_page_config(page_title="Cognitive Load", page_icon="📊", layout="wide")
|
| 14 |
init_session()
|
|
|
|
| 15 |
show_analysis_log()
|
| 16 |
|
| 17 |
st.title("📊 Cognitive Load Scorer")
|
|
|
|
| 7 |
import plotly.express as px
|
| 8 |
|
| 9 |
from session import init_session, log_analysis, download_csv_button, show_analysis_log
|
| 10 |
+
from theme import inject_theme, section_header
|
| 11 |
from utils import make_roi_indices, score_cognitive_load, COGNITIVE_DIMENSIONS, ROI_GROUPS
|
| 12 |
from synthetic import generate_realistic_predictions
|
| 13 |
|
| 14 |
st.set_page_config(page_title="Cognitive Load", page_icon="📊", layout="wide")
|
| 15 |
init_session()
|
| 16 |
+
inject_theme()
|
| 17 |
show_analysis_log()
|
| 18 |
|
| 19 |
st.title("📊 Cognitive Load Scorer")
|
pages/3_Temporal_Dynamics.py
CHANGED
|
@@ -7,11 +7,13 @@ import plotly.graph_objects as go
|
|
| 7 |
from plotly.subplots import make_subplots
|
| 8 |
|
| 9 |
from session import init_session, log_analysis, get_carried_rois, download_csv_button, show_analysis_log
|
|
|
|
| 10 |
from utils import make_roi_indices, peak_latency, temporal_correlation, decompose_response, ROI_GROUPS, ALL_ROIS
|
| 11 |
from synthetic import generate_realistic_predictions, generate_correlated_features
|
| 12 |
|
| 13 |
st.set_page_config(page_title="Temporal Dynamics", page_icon="⏱️", layout="wide")
|
| 14 |
init_session()
|
|
|
|
| 15 |
show_analysis_log()
|
| 16 |
|
| 17 |
st.title("⏱️ Temporal Dynamics")
|
|
|
|
| 7 |
from plotly.subplots import make_subplots
|
| 8 |
|
| 9 |
from session import init_session, log_analysis, get_carried_rois, download_csv_button, show_analysis_log
|
| 10 |
+
from theme import inject_theme, section_header
|
| 11 |
from utils import make_roi_indices, peak_latency, temporal_correlation, decompose_response, ROI_GROUPS, ALL_ROIS
|
| 12 |
from synthetic import generate_realistic_predictions, generate_correlated_features
|
| 13 |
|
| 14 |
st.set_page_config(page_title="Temporal Dynamics", page_icon="⏱️", layout="wide")
|
| 15 |
init_session()
|
| 16 |
+
inject_theme()
|
| 17 |
show_analysis_log()
|
| 18 |
|
| 19 |
st.title("⏱️ Temporal Dynamics")
|
pages/4_Connectivity.py
CHANGED
|
@@ -7,6 +7,7 @@ import plotly.graph_objects as go
|
|
| 7 |
import plotly.express as px
|
| 8 |
|
| 9 |
from session import init_session, log_analysis, get_carried_rois, download_csv_button, show_analysis_log
|
|
|
|
| 10 |
from utils import (
|
| 11 |
make_roi_indices, compute_connectivity, cluster_rois, graph_metrics,
|
| 12 |
partial_correlation, betweenness_centrality, modularity_score,
|
|
@@ -16,6 +17,7 @@ from synthetic import generate_realistic_predictions
|
|
| 16 |
|
| 17 |
st.set_page_config(page_title="ROI Connectivity", page_icon="🔗", layout="wide")
|
| 18 |
init_session()
|
|
|
|
| 19 |
show_analysis_log()
|
| 20 |
|
| 21 |
st.title("🔗 ROI Connectivity Analysis")
|
|
|
|
| 7 |
import plotly.express as px
|
| 8 |
|
| 9 |
from session import init_session, log_analysis, get_carried_rois, download_csv_button, show_analysis_log
|
| 10 |
+
from theme import inject_theme, section_header
|
| 11 |
from utils import (
|
| 12 |
make_roi_indices, compute_connectivity, cluster_rois, graph_metrics,
|
| 13 |
partial_correlation, betweenness_centrality, modularity_score,
|
|
|
|
| 17 |
|
| 18 |
st.set_page_config(page_title="ROI Connectivity", page_icon="🔗", layout="wide")
|
| 19 |
init_session()
|
| 20 |
+
inject_theme()
|
| 21 |
show_analysis_log()
|
| 22 |
|
| 23 |
st.title("🔗 ROI Connectivity Analysis")
|
pages/5_Brain_Viewer.py
CHANGED
|
@@ -5,6 +5,7 @@ import numpy as np
|
|
| 5 |
import plotly.graph_objects as go
|
| 6 |
|
| 7 |
from session import init_session, show_analysis_log, upload_npy_widget
|
|
|
|
| 8 |
from brain_mesh import (
|
| 9 |
load_fsaverage_mesh,
|
| 10 |
load_sulcal_map,
|
|
@@ -21,6 +22,7 @@ from utils import ROI_GROUPS, make_roi_indices
|
|
| 21 |
|
| 22 |
st.set_page_config(page_title="3D Brain Viewer", page_icon="🧠", layout="wide")
|
| 23 |
init_session()
|
|
|
|
| 24 |
show_analysis_log()
|
| 25 |
|
| 26 |
st.title("🧠 Interactive 3D Brain Viewer")
|
|
|
|
| 5 |
import plotly.graph_objects as go
|
| 6 |
|
| 7 |
from session import init_session, show_analysis_log, upload_npy_widget
|
| 8 |
+
from theme import inject_theme, section_header
|
| 9 |
from brain_mesh import (
|
| 10 |
load_fsaverage_mesh,
|
| 11 |
load_sulcal_map,
|
|
|
|
| 22 |
|
| 23 |
st.set_page_config(page_title="3D Brain Viewer", page_icon="🧠", layout="wide")
|
| 24 |
init_session()
|
| 25 |
+
inject_theme()
|
| 26 |
show_analysis_log()
|
| 27 |
|
| 28 |
st.title("🧠 Interactive 3D Brain Viewer")
|
requirements.txt
CHANGED
|
@@ -7,3 +7,5 @@ networkx>=3.2
|
|
| 7 |
matplotlib>=3.8
|
| 8 |
seaborn>=0.13
|
| 9 |
nilearn>=0.11.0
|
|
|
|
|
|
|
|
|
| 7 |
matplotlib>=3.8
|
| 8 |
seaborn>=0.13
|
| 9 |
nilearn>=0.11.0
|
| 10 |
+
pyvista>=0.47.0
|
| 11 |
+
stpyvista>=0.2.1
|
theme.py
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Futuristic theme injection for Streamlit."""
|
| 2 |
+
|
| 3 |
+
import streamlit as st
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def inject_theme():
|
| 8 |
+
"""Inject custom CSS and hide default Streamlit chrome."""
|
| 9 |
+
css_path = Path(__file__).parent / "assets" / "theme.css"
|
| 10 |
+
if css_path.exists():
|
| 11 |
+
css = css_path.read_text()
|
| 12 |
+
else:
|
| 13 |
+
css = ""
|
| 14 |
+
|
| 15 |
+
st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def hero_header(title, subtitle="", github_url="https://github.com/siddhant-rajhans/cortexlab"):
|
| 19 |
+
"""Render a futuristic hero header with gradient title."""
|
| 20 |
+
st.markdown(f"""
|
| 21 |
+
<div style="text-align: center; padding: 1.5rem 0 0.5rem 0;">
|
| 22 |
+
<h1 style="
|
| 23 |
+
font-size: 3rem;
|
| 24 |
+
font-weight: 800;
|
| 25 |
+
background: linear-gradient(135deg, #7C3AED 0%, #3B82F6 40%, #06B6D4 100%);
|
| 26 |
+
-webkit-background-clip: text;
|
| 27 |
+
-webkit-text-fill-color: transparent;
|
| 28 |
+
background-clip: text;
|
| 29 |
+
margin-bottom: 0.3rem;
|
| 30 |
+
letter-spacing: -0.04em;
|
| 31 |
+
">{title}</h1>
|
| 32 |
+
<p style="color: #94A3B8; font-size: 1.1rem; margin-bottom: 0.8rem;">{subtitle}</p>
|
| 33 |
+
<div style="display: flex; justify-content: center; gap: 1rem; flex-wrap: wrap;">
|
| 34 |
+
<a href="{github_url}" target="_blank" style="
|
| 35 |
+
display: inline-flex; align-items: center; gap: 0.4rem;
|
| 36 |
+
padding: 0.5rem 1.2rem;
|
| 37 |
+
background: rgba(124, 58, 237, 0.15);
|
| 38 |
+
border: 1px solid rgba(124, 58, 237, 0.3);
|
| 39 |
+
border-radius: 8px;
|
| 40 |
+
color: #C4B5FD;
|
| 41 |
+
text-decoration: none;
|
| 42 |
+
font-size: 0.85rem;
|
| 43 |
+
font-weight: 500;
|
| 44 |
+
transition: all 0.3s ease;
|
| 45 |
+
">
|
| 46 |
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
|
| 47 |
+
GitHub
|
| 48 |
+
</a>
|
| 49 |
+
<a href="https://huggingface.co/SID2000/cortexlab" target="_blank" style="
|
| 50 |
+
display: inline-flex; align-items: center; gap: 0.4rem;
|
| 51 |
+
padding: 0.5rem 1.2rem;
|
| 52 |
+
background: rgba(59, 130, 246, 0.15);
|
| 53 |
+
border: 1px solid rgba(59, 130, 246, 0.3);
|
| 54 |
+
border-radius: 8px;
|
| 55 |
+
color: #93C5FD;
|
| 56 |
+
text-decoration: none;
|
| 57 |
+
font-size: 0.85rem;
|
| 58 |
+
font-weight: 500;
|
| 59 |
+
">HuggingFace</a>
|
| 60 |
+
<a href="https://huggingface.co/spaces/SID2000/cortexlab-dashboard" target="_blank" style="
|
| 61 |
+
display: inline-flex; align-items: center; gap: 0.4rem;
|
| 62 |
+
padding: 0.5rem 1.2rem;
|
| 63 |
+
background: rgba(6, 182, 212, 0.15);
|
| 64 |
+
border: 1px solid rgba(6, 182, 212, 0.3);
|
| 65 |
+
border-radius: 8px;
|
| 66 |
+
color: #67E8F9;
|
| 67 |
+
text-decoration: none;
|
| 68 |
+
font-size: 0.85rem;
|
| 69 |
+
font-weight: 500;
|
| 70 |
+
">Live Demo</a>
|
| 71 |
+
</div>
|
| 72 |
+
</div>
|
| 73 |
+
""", unsafe_allow_html=True)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def glow_card(title, value, subtitle="", color="#06B6D4"):
|
| 77 |
+
"""Render a glowing metric card."""
|
| 78 |
+
st.markdown(f"""
|
| 79 |
+
<div style="
|
| 80 |
+
background: rgba(15, 15, 40, 0.5);
|
| 81 |
+
backdrop-filter: blur(10px);
|
| 82 |
+
border: 1px solid {color}33;
|
| 83 |
+
border-radius: 14px;
|
| 84 |
+
padding: 1.2rem;
|
| 85 |
+
text-align: center;
|
| 86 |
+
box-shadow: 0 0 20px {color}15;
|
| 87 |
+
transition: all 0.3s ease;
|
| 88 |
+
">
|
| 89 |
+
<div style="color: #94A3B8; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 0.3rem;">{title}</div>
|
| 90 |
+
<div style="color: {color}; font-size: 2rem; font-weight: 700; letter-spacing: -0.02em;">{value}</div>
|
| 91 |
+
<div style="color: #64748B; font-size: 0.75rem; margin-top: 0.2rem;">{subtitle}</div>
|
| 92 |
+
</div>
|
| 93 |
+
""", unsafe_allow_html=True)
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def section_header(title, description=""):
|
| 97 |
+
"""Render a styled section header with optional description."""
|
| 98 |
+
st.markdown(f"""
|
| 99 |
+
<div style="margin: 1.5rem 0 0.8rem 0;">
|
| 100 |
+
<h2 style="
|
| 101 |
+
color: #F1F5F9;
|
| 102 |
+
font-size: 1.3rem;
|
| 103 |
+
font-weight: 600;
|
| 104 |
+
letter-spacing: -0.02em;
|
| 105 |
+
margin-bottom: 0.3rem;
|
| 106 |
+
padding-bottom: 0.4rem;
|
| 107 |
+
border-bottom: 1px solid rgba(100, 100, 255, 0.15);
|
| 108 |
+
">{title}</h2>
|
| 109 |
+
{"<p style='color: #94A3B8; font-size: 0.85rem; margin-top: 0;'>" + description + "</p>" if description else ""}
|
| 110 |
+
</div>
|
| 111 |
+
""", unsafe_allow_html=True)
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def feature_card(icon, title, description, color="#7C3AED"):
|
| 115 |
+
"""Render a feature card for the home page."""
|
| 116 |
+
return f"""
|
| 117 |
+
<div style="
|
| 118 |
+
background: rgba(15, 15, 40, 0.4);
|
| 119 |
+
backdrop-filter: blur(8px);
|
| 120 |
+
border: 1px solid {color}25;
|
| 121 |
+
border-radius: 14px;
|
| 122 |
+
padding: 1.3rem;
|
| 123 |
+
height: 100%;
|
| 124 |
+
transition: all 0.3s ease;
|
| 125 |
+
cursor: pointer;
|
| 126 |
+
">
|
| 127 |
+
<div style="font-size: 1.5rem; margin-bottom: 0.5rem;">{icon}</div>
|
| 128 |
+
<div style="color: {color}; font-size: 1rem; font-weight: 600; margin-bottom: 0.4rem;">{title}</div>
|
| 129 |
+
<div style="color: #94A3B8; font-size: 0.8rem; line-height: 1.5;">{description}</div>
|
| 130 |
+
</div>
|
| 131 |
+
"""
|