Mattias Cosarinsky commited on
Commit
7d0bd10
·
1 Parent(s): 59d4532
Files changed (2) hide show
  1. app.py +82 -0
  2. utils.py +99 -0
app.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+
3
+ import gradio as gr
4
+ from utils import HF_REPO, ROIS, load_roi_image, load_images, get_hypotheses_for_selection
5
+
6
+ # -------- CONFIGURATION --------
7
+ MODELS = ["SAE", "SAE_ICA", "ICA", "PCA", "NMF", "Voxel"]
8
+
9
+ # Initial values derived from the helper functions after the structure is loaded
10
+ INITIAL_HYPOTHESES = get_hypotheses_for_selection(MODELS[0], ROIS[0])
11
+ INITIAL_ROI_IMAGE = load_roi_image(ROIS[0])
12
+
13
+ # -------- GRADIO UI AND CALLBACK LOGIC --------
14
+ def update_hypotheses(model, roi):
15
+ new_hypotheses = get_hypotheses_for_selection(model, roi)
16
+ return gr.Dropdown(choices=new_hypotheses, value=new_hypotheses[0] if new_hypotheses else None)
17
+
18
+ with gr.Blocks() as demo:
19
+ gr.Markdown("## BrainExplore: Visual Concept Explorer")
20
+
21
+ # 1. TOP ROW: Dropdowns (Menus)
22
+ with gr.Row():
23
+ model_dropdown = gr.Dropdown(label="Select Model", choices=MODELS, value=MODELS[0], scale=1)
24
+ roi_dropdown = gr.Dropdown(label="Select ROI", choices=ROIS, value=ROIS[0], scale=1)
25
+
26
+ hyp_dropdown = gr.Dropdown(
27
+ label="Select Hypothesis",
28
+ choices=INITIAL_HYPOTHESES,
29
+ value=INITIAL_HYPOTHESES[0] if INITIAL_HYPOTHESES else None,
30
+ scale=1
31
+ )
32
+
33
+ # 2. SECOND ROW: Visualizations (ROI Image and Gallery)
34
+ with gr.Row(equal_height=True):
35
+
36
+ roi_image = gr.Image(
37
+ label="Selected Brain Region (ROI)",
38
+ value=INITIAL_ROI_IMAGE,
39
+ interactive=False,
40
+ height=400,
41
+ scale=1
42
+ )
43
+
44
+ image_gallery = gr.Gallery(
45
+ label="Top Activating Images",
46
+ columns=None, rows=1, scale=3,
47
+ object_fit="contain", preview=True, height=400
48
+ )
49
+
50
+ # -------- CALLBACKS --------
51
+ model_dropdown.change(
52
+ fn=update_hypotheses,
53
+ inputs=[model_dropdown, roi_dropdown],
54
+ outputs=[hyp_dropdown],
55
+ queue=False
56
+ ).then(
57
+ fn=load_images,
58
+ inputs=[model_dropdown, roi_dropdown, hyp_dropdown],
59
+ outputs=[image_gallery]
60
+ )
61
+
62
+ # ROI Change: Update Hypotheses, THEN update ROI Image, THEN update Activating Images
63
+ roi_dropdown.change(
64
+ fn=update_hypotheses,
65
+ inputs=[model_dropdown, roi_dropdown],
66
+ outputs=[hyp_dropdown],
67
+ queue=False
68
+ ).then(
69
+ fn=load_roi_image,
70
+ inputs=[roi_dropdown],
71
+ outputs=[roi_image]
72
+ ).then(
73
+ fn=load_images,
74
+ inputs=[model_dropdown, roi_dropdown, hyp_dropdown],
75
+ outputs=[image_gallery]
76
+ )
77
+
78
+ # Hypothesis Change: Update Activating Images only
79
+ hyp_dropdown.change(fn=load_images, inputs=[model_dropdown, roi_dropdown, hyp_dropdown], outputs=[image_gallery])
80
+
81
+ if __name__ == "__main__":
82
+ demo.launch()
utils.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from datasets import load_dataset
3
+ from PIL import Image
4
+ from huggingface_hub import hf_hub_download
5
+ import os
6
+
7
+ # -------- CONFIG & STATE --------
8
+ HF_REPO = "mcosarinsky/BrainExplore-Images"
9
+ STRUCTURE_DATA = None
10
+ ROIS = ["EBA","FBA-1","FBA-2","FFA-1","FFA-2","OFA","OPA","OWFA","PPA","RSC","VWFA-1","VWFA-2","hV4"]
11
+
12
+ # -------- 1. JSON STRUCTURE HELPERS --------
13
+ def load_structure(repo_id, filename="structure.json"):
14
+ """
15
+ Downloads the structure.json file from the Hugging Face Hub and loads it into memory.
16
+ """
17
+ global STRUCTURE_DATA
18
+ if STRUCTURE_DATA is not None:
19
+ return STRUCTURE_DATA
20
+
21
+ try:
22
+ local_path = hf_hub_download(
23
+ repo_id=repo_id,
24
+ filename=filename,
25
+ repo_type="dataset"
26
+ )
27
+ with open(local_path, 'r') as f:
28
+ STRUCTURE_DATA = json.load(f)
29
+
30
+ print(f"Successfully loaded {filename}.")
31
+ return STRUCTURE_DATA
32
+
33
+ except Exception as e:
34
+ print(f"CRITICAL ERROR: Could not load {filename} via hf_hub_download: {e}")
35
+ return {}
36
+
37
+ def get_hypotheses_for_selection(model, roi):
38
+ """
39
+ Retrieves the list of hypotheses based on the selected model and ROI
40
+ from the pre-loaded STRUCTURE_DATA.
41
+ """
42
+ if not STRUCTURE_DATA:
43
+ return []
44
+
45
+ try:
46
+ hypotheses = STRUCTURE_DATA.get(model, {}).get(roi, [])
47
+ return hypotheses
48
+ except Exception as e:
49
+ print(f"Error accessing structure data for {model}/{roi}: {e}")
50
+ return []
51
+
52
+ # -------- 2. IMAGE PROCESSING HELPERS --------
53
+ def pad_image(pil_img, padding_x=10, padding_y=0, color=(255, 255, 255)):
54
+ """
55
+ Adds padding to the sides of a PIL image.
56
+ """
57
+ old_width, old_height = pil_img.size
58
+ new_width = old_width + 2 * padding_x
59
+ new_height = old_height + 2 * padding_y
60
+ new_img = Image.new(pil_img.mode, (new_width, new_height), color)
61
+ new_img.paste(pil_img, (padding_x, padding_y))
62
+ return new_img
63
+
64
+
65
+ # -------- 3. DATA LOADING HELPERS --------
66
+ def load_images(model, roi, hyp):
67
+ """
68
+ Loads top activating images for the given parameters and applies padding.
69
+ """
70
+ folder_path = f"{model}/{roi}/{hyp}"
71
+ ds = load_dataset(HF_REPO, data_dir=folder_path, split="train", streaming=True)
72
+ image_paths = [img["image"] for img in ds.take(2)]
73
+ padded_images = [pad_image(img, padding_x=10, padding_y=0) for img in image_paths]
74
+ return padded_images
75
+
76
+ def load_roi_image(roi_name):
77
+ """
78
+ Downloads the ROI PNG from the Hugging Face Hub, looking inside the 'ROI/' folder,
79
+ and loads it as a PIL Image.
80
+ """
81
+ if not roi_name:
82
+ return None
83
+
84
+ file_name = f"ROI/{roi_name}.png"
85
+
86
+ try:
87
+ local_path = hf_hub_download(
88
+ repo_id=HF_REPO,
89
+ filename=file_name,
90
+ repo_type="dataset"
91
+ )
92
+ return Image.open(local_path)
93
+ except Exception as e:
94
+ # A 404 error here likely means the file doesn't exist under that path
95
+ print(f"Error loading ROI image {roi_name} via hf_hub_download. Path used: {file_name}. Details: {e}")
96
+ return None
97
+
98
+ # Perform initial structure load for dynamic dependency resolution in app.py
99
+ load_structure(HF_REPO)