From 9aeb57f8f503760cc20592b76b90a981f4f9026f Mon Sep 17 00:00:00 2001 From: nsteinme Date: Sun, 27 May 2018 20:23:39 +0100 Subject: [PATCH] first gui commit --- configFiles/defaultOps.mat | Bin 0 -> 2667 bytes kilosort.m | 17 +++ ksGUI.m | 243 +++++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 configFiles/defaultOps.mat create mode 100644 kilosort.m create mode 100644 ksGUI.m diff --git a/configFiles/defaultOps.mat b/configFiles/defaultOps.mat new file mode 100644 index 0000000000000000000000000000000000000000..ecfbfcee51210b5cdcd6dfa8abf360d9aefd307b GIT binary patch literal 2667 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 Z>DQKRH0k?dtO@n`Gv6f!`!{t>QLipA81VoA literal 0 HcmV?d00001 diff --git a/kilosort.m b/kilosort.m new file mode 100644 index 00000000..4dd72bf6 --- /dev/null +++ b/kilosort.m @@ -0,0 +1,17 @@ +function k = kilosort +% Call this to open the kilosort gui. + +f = figure('Name', 'Kilosort',... + 'MenuBar', 'none',... + 'Toolbar', 'none',... + 'NumberTitle', 'off',... + 'Units', 'normalized',... + 'OuterPosition', [0.1 0.1 0.8 0.8]); +h = ksGUI(f); + +if nargout > 0 + k = h; +end + +end + diff --git a/ksGUI.m b/ksGUI.m new file mode 100644 index 00000000..31804d9e --- /dev/null +++ b/ksGUI.m @@ -0,0 +1,243 @@ + + +classdef ksGUI < handle + % GUI for kilosort + % + % Purpose is to display some basic data and diagnostics, to make it easy to + % run kilosort + % + % Kilosort by M. Pachitariu + % This GUI by N. Steinmetz + + properties + figHandle % handle to the figure + + guiHandles % struct of handles to useful parts of the gui + + ops % struct for kilosort to run + + rez % struct of results of running + + end + + methods + function obj = ksGUI(parent) + + obj.init(); + + obj.build(parent); + + end + + function init(obj) + + % check that required functions are present + if ~exist('uiextras.HBox') + error('ksGUI:init:uix', 'You must have the "uiextras" toolbox to use this GUI. Choose Environment->Get Add-ons and search for "GUI Layout Toolbox" by David Sampson.\n') + end + + % add paths + fprintf(1, '%s\n', mfilename); + if ~exist('preprocessDataSub') + addpath(genpath(fileparts(mfilename))); + end + if ~exist('readNPY') + githubDir = fileparts(fileparts(mfilename)); % taking a guess that they have a directory with all github repos + if exist(fullfile(githubDir, 'npy-matlab')) + addpath(genpath(fullfile(githubDir, 'npy-matlab'))); + end + end + if ~exist('readNPY') + warning('ksGUI:init:npy', 'In order to save data for phy, you must have the npy-matlab repository from https://github.com/kwikteam/npy-matlab in your matlab path\n'); + end + + % compile if necessary + if ~exist('mexWtW2') + + fprintf(1, 'Compiled Kilosort files not found. Attempting to compile now.\n'); + try + oldDir = pwd; + cd(fullfile(fileparts(mfilename), 'CUDA')); + mexGPUall; + fprintf(1, 'Success!\n'); + cd(oldDir); + catch ex + fprintf(1, 'Compilation failed. Check installation instructions at https://github.com/cortex-lab/Kilosort\n'); + rethrow(ex); + end + end + + obj.ops = ksGUI.defaultOps(); + + end + + + function build(obj, f) + % construct the GUI with appropriate panels + obj.figHandle = f; + + obj.guiHandles.root = uiextras.VBox('Parent', f,... + 'DeleteFcn', @(~,~)obj.cleanup(), 'Visible', 'on', ... + 'Padding', 5); + + % - Root sections + + obj.guiHandles.titleBar = uicontrol(... + 'Parent', obj.guiHandles.root,... + 'Style', 'text', 'HorizontalAlignment', 'left', ... + 'String', 'Kilosort', 'FontSize', 36,... + 'FontName', 'Myriad Pro', 'FontWeight', 'bold'); + + obj.guiHandles.mainSection = uiextras.HBox(... + 'Parent', obj.guiHandles.root); + + obj.guiHandles.logPanel = uiextras.Panel(... + 'Parent', obj.guiHandles.root, ... + 'Title', 'Message Log', 'FontSize', 18,... + 'FontName', 'Myriad Pro'); + + obj.guiHandles.root.Sizes = [-1 -8 -2]; + + % -- Main section + obj.guiHandles.settingsPanel = uiextras.Panel(... + 'Parent', obj.guiHandles.mainSection, ... + 'Title', 'Settings', 'FontSize', 18,... + 'FontName', 'Myriad Pro'); + + obj.guiHandles.probePanel = uiextras.Panel(... + 'Parent', obj.guiHandles.mainSection, ... + 'Title', 'Probe view', 'FontSize', 18,... + 'FontName', 'Myriad Pro'); + + obj.guiHandles.dataPanel = uiextras.Panel(... + 'Parent', obj.guiHandles.mainSection, ... + 'Title', 'Data view', 'FontSize', 18,... + 'FontName', 'Myriad Pro'); + + obj.guiHandles.mainSection.Sizes = [-1 -1 -2]; + + % --- Settings panel + + obj.guiHandles.settingsVBox = uiextras.VBox(... + 'Parent', obj.guiHandles.settingsPanel); + + obj.guiHandles.settingsGrid = uiextras.Grid(... + 'Parent', obj.guiHandles.settingsVBox); + + % choose file + obj.guiHandles.settings.ChooseFileTxt = uicontrol(... + 'Parent', obj.guiHandles.settingsGrid,... + 'Style', 'pushbutton', 'HorizontalAlignment', 'left', ... + 'String', 'Select data file'); + obj.guiHandles.settings.ChooseFileEdt = uicontrol(... + 'Parent', obj.guiHandles.settingsGrid,... + 'Style', 'edit', 'HorizontalAlignment', 'left', ... + 'String', '...'); + + % choose temporary directory + + % choose output path + + % set nChannels + + % set Fs + + % choose probe + + % choose max number of clusters + + set( obj.guiHandles.settingsGrid, ... + 'ColumnSizes', [-1 -1], 'RowSizes', -1 );%-1*ones(1,7) + + + % button for advanced options + + % button for run + + % button for write script + + % button for save defaults + + % -- Message log + obj.guiHandles.logBox = uicontrol(... + 'Parent', obj.guiHandles.logPanel,... + 'Style', 'listbox', 'Enable', 'inactive', 'String', {}, ... + 'Tag', 'Logging Display', 'FontSize', 14); + + obj.log('Initialization success.'); + + end + + function run(obj) + + % check that everything is set up correctly to run + + % do preprocessing + obj.ops.gui = obj; % for kilosort to access, e.g. calling "log" + try + obj.rez = preprocessDataSub(obj.ops); + catch ex + log(sprintf('Error preprocessing! %s', ex.message)); + end + + % update gui with results of preprocessing + obj.updateDataView(); + + % fit templates + try + obj.rez = learnAndSolve8(obj.rez); + catch ex + log(sprintf('Error running kilosort! %s', ex.message)); + end + + % save results + try + rezToPhy(obj.rez, obj.ops.saveDir); + catch ex + log(sprintf('Error saving data for phy! %s', ex.message)); + end + + end + + function writeScript(obj) + % write a .m file script that the user can use later to run + % directly, i.e. skipping the gui + + end + + function cleanup(obj) + fclose('all'); + end + + function log(obj, message) + % show a message to the user in the log box + timestamp = datestr(now, 'dd-mm-yyyy HH:MM:SS'); + str = sprintf('[%s] %s', timestamp, message); + current = get(obj.guiHandles.logBox, 'String'); + set(obj.guiHandles.logBox, 'String', [current; str], ... + 'Value', numel(current) + 1); + end + end + + methods(Static) + function ops = defaultOps() + % look for a default ops file and load it + if exist('defaultOps.mat') + load('defaultOps.mat', 'ops'); + else + ops = []; + end + end + + function docString = opDoc(opName) + switch opName + case 'NchanTOT'; docString = 'Total number of rows in the data file'; + case 'Th'; docString = 'Threshold on projections (like in Kilosort1)'; + end + end + + end + +end + +