Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 23 additions & 23 deletions spikeinterface_gui/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,32 @@ class Launcher:
analyzers_folder : str, list or None
Path to the folder containing analyzer folders or a list/dict of analyzer paths.
If None, the user will be prompted to select an analyzer folder.
root_folder: str|Path| None
A folder that is explore to construct the list of analyzers.
When not None analyzer_folders must be None.
backend : str
The backend to use for the GUI. Options are "qt" or "panel".
verbose : bool
If True, enables verbose logging in the GUI.
"""

def __init__(self, analyzer_folders=None, backend="qt", verbose=False):
def __init__(self, analyzer_folders=None, root_folder=None, backend="qt", verbose=False):
from spikeinterface_gui.main import check_folder_is_analyzer

if analyzer_folders is not None:
if isinstance(analyzer_folders, (str, Path)):
# self.analyzer_folders = [
# p for p in Path(analyzer_folders).iterdir() if p.is_dir() and check_folder_is_analyzer(p)
# ]
# @alessio I prefer this which explore also sub folders
self.analyzer_folders = [
f.parent for f in Path(analyzer_folders).glob('**/spikeinterface_info.json') if f.parent.is_dir() and check_folder_is_analyzer(f.parent)
]
elif isinstance(analyzer_folders, (list, tuple)):
self.analyzer_folders = [
p for p in analyzer_folders if isinstance(p, (str, Path)) and check_folder_is_analyzer(p)
]
self.analyzer_folders = None
if root_folder is not None:
assert analyzer_folders is None, "When using root_folder, analyzer_folders must be None"
root_folder = Path(root_folder)
self.analyzer_folders = [
f.parent for f in root_folder.glob('**/spikeinterface_info.json') if check_folder_is_analyzer(f.parent)
] + [
f.parent for f in root_folder.glob('**/.zmetadata') if check_folder_is_analyzer(f.parent)
]
elif analyzer_folders is not None:
if isinstance(analyzer_folders, (list, tuple)):
self.analyzer_folders = [ p for p in analyzer_folders if check_folder_is_analyzer(p) ]
elif isinstance(analyzer_folders, dict):
self.analyzer_folders = {
k: p for k, p in analyzer_folders.items() if isinstance(p, (str, Path)) and check_folder_is_analyzer(p)
}
else:
self.analyzer_folders = None
else:
self.analyzer_folders = None
self.analyzer_folders = { k: p for k, p in analyzer_folders.items() if check_folder_is_analyzer(p)}


self.verbose = verbose
Expand Down Expand Up @@ -231,8 +227,12 @@ def _qt_on_launch_clicked(self):
analyzer_path = self.analyzer_path_input.text()
else:
ind = self.analyzer_path_input.currentIndex()
k = list(self.analyzer_folders.keys())[ind]
analyzer_path = str(self.analyzer_folders[k])
if isinstance(self.analyzer_folders, dict):
k = list(self.analyzer_folders.keys())[ind]
analyzer_path = str(self.analyzer_folders[k])
else:
analyzer_path = self.analyzer_folders[ind]


if self.select_recording_checkbox.isChecked():
recording_path = self.recording_path_input.text()
Expand Down
32 changes: 20 additions & 12 deletions spikeinterface_gui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,16 +138,20 @@ def run_mainwindow(
return win


def run_launcher(mode="desktop", analyzer_folders=None, address="localhost", port=0, verbose=False):

def run_launcher(mode="desktop", analyzer_folders=None, root_folder=None, address="localhost", port=0, verbose=False):
"""
Run the launcher for the SpikeInterface GUI.

Parameters
----------
mode: 'desktop' | 'app', default: 'desktop'
The backend to use for the GUI.
analyzer_folders: list of str | None, default: None
List of analyzer folders to load. If str, it is a single folder and subfolders are searched.
analyzer_folders: list of str | dict | None, default: None
List of analyzer folders to load.
root_folder: str|Path| None
A folder that is explore to construct the list of analyzers.
When not None analyzer_folders must be None.
address: str, default: "localhost"
The address to use for the web mode. Default is "localhost".
Use "auto-ip" to use the real IP address of the machine.
Expand All @@ -161,7 +165,7 @@ def run_launcher(mode="desktop", analyzer_folders=None, address="localhost", por
if mode == "desktop":
from .myqt import QT, mkQApp
app = mkQApp()
launcher = Launcher(analyzer_folders=analyzer_folders, backend="qt", verbose=verbose)
launcher = Launcher(analyzer_folders=analyzer_folders, root_folder=root_folder, backend="qt", verbose=verbose)
app.exec()

elif mode == "web":
Expand All @@ -171,7 +175,7 @@ def run_launcher(mode="desktop", analyzer_folders=None, address="localhost", por
from spikeinterface_gui.launcher import panel_gui_view
from spikeinterface_gui.backend_panel import start_server

launcher = Launcher(analyzer_folders=analyzer_folders, backend="panel", verbose=verbose)
launcher = Launcher(analyzer_folders=analyzer_folders, root_folder=root_folder, backend="panel", verbose=verbose)

server, address, port, _ = start_server(
{"/launcher": launcher.layout, "/gui": panel_gui_view},
Expand Down Expand Up @@ -202,7 +206,13 @@ def check_folder_is_analyzer(folder):
bool
True if the folder is a valid SortingAnalyzer folder, False otherwise.
"""
if not isinstance(folder, (str, Path)):
return False

folder = Path(folder)
if not folder.is_dir():
return False

if not str(folder).endswith(".zarr"):
spikeinterface_info_file = folder / 'spikeinterface_info.json'
if not spikeinterface_info_file.exists():
Expand All @@ -217,10 +227,8 @@ def check_folder_is_analyzer(folder):
else: #zarr folder
import zarr
# Check if the folder contains the necessary files for a SortingAnalyzer
if not folder.exists():
return False
zarr_root = zarr.open(folder, mode='r')
spikeinterface_info = zarr_root.get('spikeinterface_info')
spikeinterface_info = zarr_root.attrs.get('spikeinterface_info')
if spikeinterface_info is None:
return False
if spikeinterface_info.get("object") != "SortingAnalyzer":
Expand All @@ -234,7 +242,7 @@ def run_mainwindow_cli():

parser = argparse.ArgumentParser(description='spikeinterface-gui')
parser.add_argument('analyzer_folder', help='SortingAnalyzer folder path', default=None, nargs='?')
parser.add_argument('--analyzer-folders', help='Base folder for launcher mode with multiple analyzer folders', default=None)
parser.add_argument('--root-folder', help='Base folder for launcher mode with multiple analyzer folders', default=None)
parser.add_argument('--mode', help='Mode desktop or web', default='desktop')
parser.add_argument('--no-traces', help='Do not show traces', action='store_true', default=False)
parser.add_argument('--curation', help='Enable curation panel', action='store_true', default=False)
Expand All @@ -248,9 +256,9 @@ def run_mainwindow_cli():

analyzer_folder = args.analyzer_folder
if analyzer_folder is None:
print('Running launcher...')
analyzer_folders = args.analyzer_folders
run_launcher(analyzer_folders=analyzer_folders, mode=args.mode, address=args.address, port=args.port, verbose=args.verbose)
if args.verbose:
print('Running launcher...')
run_launcher(root_folder=args.root_folder, mode=args.mode, address=args.address, port=args.port, verbose=args.verbose)
else:
if args.verbose:
print('Loading analyzer...')
Expand Down
29 changes: 18 additions & 11 deletions spikeinterface_gui/tests/test_mainwindow_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,21 +83,28 @@ def test_mainwindow(start_app=False, verbose=True, curation=False, only_some_ext
def test_launcher(verbose=True):

# case 1
# analyzer_folders = None
analyzer_folders = None
root_folder = None

# case 2 : explore parent
analyzer_folders = Path(__file__).parent
analyzer_folders = None
root_folder = Path(__file__).parent

# case 3 : list
analyzer_folders = [
Path(__file__).parent / 'my_dataset_small/sorting_analyzer',
Path(__file__).parent / 'my_dataset_big/sorting_analyzer',
]
# analyzer_folders = [
# Path(__file__).parent / 'my_dataset_small/sorting_analyzer',
# Path(__file__).parent / 'my_dataset_big/sorting_analyzer',
# ]
# root_folder = None

# case 4 : dict
analyzer_folders = {
'small' : Path(__file__).parent / 'my_dataset_small/sorting_analyzer',
'big' : Path(__file__).parent / 'my_dataset_big/sorting_analyzer',
}
# analyzer_folders = {
# 'small' : Path(__file__).parent / 'my_dataset_small/sorting_analyzer',
# 'big' : Path(__file__).parent / 'my_dataset_big/sorting_analyzer',
# }
# root_folder = None

win = run_launcher(mode="desktop", analyzer_folders=analyzer_folders, verbose=verbose)
win = run_launcher(mode="desktop", analyzer_folders=analyzer_folders, root_folder=root_folder, verbose=verbose)


if __name__ == '__main__':
Expand Down