SID2000 commited on
Commit
c8c04e3
·
verified ·
1 Parent(s): e620fce

Upload folder using huggingface_hub

Browse files
.streamlit/config.toml CHANGED
@@ -1,9 +1,13 @@
1
  [theme]
2
- primaryColor = "#6C5CE7"
3
- backgroundColor = "#0E1117"
4
- secondaryBackgroundColor = "#1A1A2E"
5
- textColor = "#FAFAFA"
 
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 build-essential && rm -rf /var/lib/apt/lists/*
 
 
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
- - 3D Brain Viewer with rotatable fsaverage mesh and activation overlays
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
- Runs on biologically realistic synthetic data. No GPU required.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 - Home Page with Data Management."""
2
 
3
  import streamlit as st
4
  import numpy as np
5
 
6
- from session import init_session, data_summary_widget, show_analysis_log, upload_npy_widget
 
7
  from utils import make_roi_indices
 
8
 
9
- st.set_page_config(page_title="CortexLab Dashboard", page_icon="🧠", layout="wide", initial_sidebar_state="expanded")
10
  init_session()
11
-
12
- st.title("CortexLab Dashboard")
13
- st.markdown("**Research-grade analysis toolkit for multimodal fMRI brain encoding**")
14
-
15
- # --- Data Source ---
16
- st.divider()
17
- st.subheader("Data Configuration")
18
-
19
- col_src, col_params = st.columns([1, 2])
20
-
21
- with col_src:
22
- source = st.radio("Data source", ["Synthetic (realistic)", "Upload your data"], index=0)
23
- st.session_state["data_source"] = "synthetic" if "Synthetic" in source else "uploaded"
24
-
25
- with col_params:
26
- if st.session_state["data_source"] == "synthetic":
27
- c1, c2, c3, c4 = st.columns(4)
28
- st.session_state["stimulus_type"] = c1.selectbox("Stimulus type", ["visual", "auditory", "language", "multimodal"])
29
- st.session_state["n_timepoints"] = c2.slider("Duration (TRs)", 30, 200, 80)
30
- st.session_state["tr_seconds"] = c3.slider("TR (seconds)", 0.5, 2.0, 1.0, 0.1)
31
- st.session_state["seed"] = c4.number_input("Seed", value=42, min_value=0)
32
-
33
- # Generate on config change
34
- roi_indices, n_vertices = make_roi_indices()
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
- xaxis_title="Time (seconds)", yaxis_title="Mean |activation|",
80
- height=300, template="plotly_dark",
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
- # --- Navigation ---
87
- st.divider()
88
- col1, col2 = st.columns(2)
 
 
 
 
 
89
 
90
- with col1:
91
- st.subheader("Analysis Tools")
92
- st.page_link("pages/1_Brain_Alignment.py", label="Brain Alignment Benchmark", icon="🎯")
93
- st.caption("RSA, CKA, Procrustes with permutation tests, bootstrap CIs, FDR correction, noise ceiling, and RDM visualization")
94
 
95
- st.page_link("pages/2_Cognitive_Load.py", label="Cognitive Load Scorer", icon="📊")
96
- st.caption("Timeline with confidence bands, dimension correlation, per-ROI breakdown, comparison mode")
 
 
 
 
 
 
97
 
98
  with col2:
99
- st.subheader("Advanced Analysis")
100
- st.page_link("pages/3_Temporal_Dynamics.py", label="Temporal Dynamics", icon="⏱️")
101
- st.caption("Raw timecourses, peak latency hierarchy, optimal lag analysis, cross-ROI lag matrix")
102
-
103
- st.page_link("pages/4_Connectivity.py", label="ROI Connectivity", icon="🔗")
104
- st.caption("Partial correlation, modularity, betweenness centrality, dendrogram, network graph")
105
-
106
- st.divider()
107
- st.subheader("3D Visualization")
108
- st.page_link("pages/5_Brain_Viewer.py", label="Interactive 3D Brain Viewer", icon="🧠")
109
- st.caption("Rotatable brain surface with activation overlays, publication-quality multi-view panels, ROI highlighting, and modality-specific patterns")
110
-
111
- # --- Analysis Log ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  show_analysis_log()
113
-
114
- st.divider()
115
- st.caption("[GitHub](https://github.com/siddhant-rajhans/cortexlab) | [HuggingFace](https://huggingface.co/SID2000/cortexlab) | [Dashboard Repo](https://github.com/siddhant-rajhans/cortexlab-dashboard)")
 
 
 
 
 
 
 
 
 
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 &rarr;</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
+ &nbsp;&bull;&nbsp;
159
+ <a href="https://github.com/siddhant-rajhans/cortexlab" style="color: #3B82F6; text-decoration: none;">GitHub</a>
160
+ &nbsp;&bull;&nbsp;
161
+ <a href="https://huggingface.co/SID2000/cortexlab" style="color: #06B6D4; text-decoration: none;">HuggingFace</a>
162
+ &nbsp;&bull;&nbsp;
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
+ """