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
38 changes: 38 additions & 0 deletions code/+nansen/+app/+tutorial/+enum/Tutorial.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
classdef Tutorial
enumeration
TwoPhotonQuickstart("Nansen - Two-photon Quickstart")
ABO_VisualCodingEphys("Allen Brain Observatory - Visual Coding (Neuropixels)")
%ABO_VisualCodingOphys("Allen Brain Observatory - Visual Coding (Calcium Imaging)")
%EBRAINS_Ophys_Demo("EBRAINS D&K - L2/3 + L5 Visual occlusion (Calcium Imaging)");
end

properties
Title (1,1) string
ProjectName (1,1) string
RepositoryName (1,1) string
end

methods
function obj = Tutorial(titleStr)
obj.Title = titleStr;

switch titleStr
case "Nansen - Two-photon Quickstart"
obj.RepositoryName = "Nansen_Demo";
obj.ProjectName = 'nansen_demo';

case "Allen Brain Observatory - Visual Coding (Neuropixels)"
obj.RepositoryName = "ABO-VisualCoding-Neuropixels-Test";
obj.ProjectName = 'abo_ephys';

case "Allen Brain Observatory - Visual Coding (Calcium Imaging)"
obj.RepositoryName = "ABO-VisualCoding-TwoPhoton-Test";
obj.ProjectName = 'abo_ophys';

case "EBRAINS D&K - L2/3 + L5 Visual occlusion (Calcium Imaging)"
obj.RepositoryName = "EBRAINS-VisualOcclusion-TwoPhoton";
error('Not implemented yet')
end
end
end
end
174 changes: 76 additions & 98 deletions code/+nansen/+app/+tutorial/loadProject.m
Original file line number Diff line number Diff line change
@@ -1,111 +1,89 @@
function loadProject(tutorial)

% Start a tutorial user session
warnState = warning('off', 'Nansen:NoProjectsAvailable');
warningCleanup = onCleanup(@() warning(warnState));
userSession = nansen.internal.user.NansenUserSession.instance();

% Allow user to select an existing project
S = ["Nansen - Two-photon Quickstart", ...
"Allen Brain Observatory - Visual Coding (Neuropixels)", ...
"Allen Brain Observatory - Visual Coding (Calcium Imaging)", ...
"EBRAINS D&K - L2/3 + L5 Visual occlusion (Calcium Imaging)"];

S = ["Nansen - Two-photon Quickstart", ...
"Allen Brain Observatory - Visual Coding (Calcium Imaging)"];

[selection, ok] = listdlg('ListString', S, 'ListSize', [360, 240]);

if ok
switch S(selection)
case "Nansen - Two-photon Quickstart"
repositoryName = "Nansen_Demo";
projectName = 'nansen_demo';

case "Allen Brain Observatory - Visual Coding (Neuropixels)"
repositoryName = "ABO-VisualCoding-Neuropixels-Test";

case "Allen Brain Observatory - Visual Coding (Calcium Imaging)"
repositoryName = "ABO-VisualCoding-TwoPhoton-Test";
projectName = 'abo_ophys';

case "EBRAINS D&K - L2/3 + L5 Visual occlusion (Calcium Imaging)"
repositoryName = "EBRAINS-VisualOcclusion-TwoPhoton";
arguments
tutorial nansen.app.tutorial.enum.Tutorial {mustBeScalarOrEmpty} = nansen.app.tutorial.enum.Tutorial.empty
end
else
error('User canceled.')
end

% We need the addonmanager to ensure all tutorial dependencies are installed
addonManager = nansen.AddonManager();
import nansen.app.tutorial.enum.Tutorial

if startsWith(S(selection), 'Allen Brain Observatory')
warnState = warning('off', 'Nansen:NoProjectsAvailable');
warningCleanup = onCleanup(@() warning(warnState));
userSession = nansen.internal.user.NansenUserSession.instance();


addonManager.refreshManagedAddons( ...
"SelectedModules", "nansen.module.ophys.twophoton")
names = {addonManager.AddonList.Name};
addonEntry = addonManager.AddonList(strcmp(names, "Brain Observatory Toolbox"));
if isempty(addonEntry)
error('NANSEN:Tutorial:MissingAddonDefinition', ...
'Could not find the Brain Observatory Toolbox dependency definition.')
end
if ~addonEntry.IsInstalled
fprintf('Downloading %s...', addonEntry.Name)
addonManager.downloadAddon(addonEntry.Name)
fprintf('Finished.\n')
if isempty(tutorial)
tutorial = nansen.app.tutorial.uiSelectTutorialProject();
end

elseif startsWith(S(selection), 'Nansen - Two-photon Quickstart')
warnState = warning('off', 'MATLAB:RMDIR:RemovedFromPath');
warnCleanup = onCleanup(@() warning(warnState));
% We need the addonmanager to ensure all tutorial dependencies are installed
addonManager = nansen.AddonManager();

disp('Installing two-photon addons...')
addonManager.installMissingAddons('nansen.module.ophys.twophoton')

% Some users had problems where Yaml was not added to java path
nansen.internal.setup.addYamlJarToJavaClassPath
end

% Check if project is already in the catalog
projectManager = userSession.getProjectManager();

if ~projectManager.containsProject(projectName)

% Download target repository folder (todo: function)
repositoryUrl = sprintf('https://github.com/NansenProjects/%s', repositoryName);
installationLocation = fullfile(userpath, 'Nansen-Tutorial');
fprintf("Downloading project ""%s""...\n", S(selection))
repoTargetFolder = matbox.setup.internal.installGithubRepository(repositoryUrl, "InstallationLocation", installationLocation, "Update", true);
if startsWith(tutorial.Title, 'Allen Brain Observatory')

L = dir(fullfile(repoTargetFolder, '*', 'project.nansen.json'));
fprintf("Adding project ""%s"" to NANSEN...\n", S(selection))
projectManager.importProject(L.folder);
projectManager.changeProject(projectName);

% Todo: Choose a datapath:
%S = struct();
%S.DataDirectory = fullfile(userpath, 'Nansen-Tutorial', 'Data', projectName);
%S.DataDirectory_ = 'uigetdir';
%[S, wasAborted] = tools.editStruct(S);

dataDirectory = fullfile(userpath, 'Nansen-Tutorial', 'Data', projectName);

project = projectManager.getCurrentProject();
dlModel = project.DataLocationModel;
for i = 1:dlModel.NumDataLocations
item = dlModel.getItem(i);
if ~isempty(item.RootPath)
[~,folderName] = fileparts(item.RootPath.Value);
item.RootPath.Value = fullfile(dataDirectory, folderName);
project.DataLocationModel.replaceItem(item)
addonManager.refreshManagedAddons( ...
"SelectedModules", "nansen.module.ophys.twophoton")
names = {addonManager.AddonList.Name};
addonEntry = addonManager.AddonList(strcmp(names, "Brain Observatory Toolbox"));

if isempty(addonEntry)
error('NANSEN:Tutorial:MissingAddonDefinition', ...
'Could not find the Brain Observatory Toolbox dependency definition.')
end
if ~addonEntry.IsInstalled
fprintf('Downloading %s...', addonEntry.Name)
addonManager.downloadAddon(addonEntry.Name)
fprintf('Finished.\n')
end

elseif startsWith(tutorial.Title, 'Nansen - Two-photon Quickstart')
warnState = warning('off', 'MATLAB:RMDIR:RemovedFromPath');
warnCleanup = onCleanup(@() warning(warnState));

disp('Installing two-photon addons...')
addonManager.installMissingAddons( ...
'nansen.module.ophys.twophoton', "ShowSummary", true)

% Some users had problems where Yaml was not added to java path
nansen.internal.setup.addYamlJarToJavaClassPath()
end
else
if ~strcmp( projectManager.CurrentProject, projectName )
projectManager.changeProject(projectName)

% Check if project is already in the catalog
projectManager = userSession.getProjectManager();

if ~projectManager.containsProject(tutorial.ProjectName)

% Download target repository folder (todo: function)
repositoryUrl = sprintf('https://github.com/NansenProjects/%s', tutorial.RepositoryName);
installationLocation = fullfile(userpath, 'Nansen-Tutorial');
fprintf("Downloading project ""%s""...\n", tutorial.Title)
repoTargetFolder = matbox.setup.internal.installGithubRepository(...
repositoryUrl, "InstallationLocation", installationLocation, "Update", true);

L = dir(fullfile(repoTargetFolder, '*', 'project.nansen.json'));
fprintf("Adding project ""%s"" to NANSEN...\n", tutorial.Title)
projectManager.importProject(L.folder);
projectManager.changeProject(tutorial.ProjectName);

dataDirectory = fullfile(userpath, 'Nansen-Tutorial', 'Data', tutorial.ProjectName);

project = projectManager.getCurrentProject();
dlModel = project.DataLocationModel;
for i = 1:dlModel.NumDataLocations
item = dlModel.getItem(i);
if ~isempty(item.RootPath)
[~,folderName] = fileparts(item.RootPath.Value);
item.RootPath.Value = fullfile(dataDirectory, folderName);
project.DataLocationModel.replaceItem(item)
end
end
else
if ~strcmp( projectManager.CurrentProject, tutorial.ProjectName )
projectManager.changeProject(tutorial.ProjectName)
end
end

nansen()

% Todo: Clone BrainObservatoryToolbox
% Todo: Download manifests for selected dataset.
end

nansen

% Todo: Clone BrainObservatoryToolbox
% Todo: Download manifests for selected dataset.
13 changes: 13 additions & 0 deletions code/+nansen/+app/+tutorial/uiSelectTutorialProject.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function tutorialEnum = uiSelectTutorialProject()
% Allow user to select an existing project
tutorialEnums = enumeration('nansen.app.tutorial.enum.Tutorial');
tutorialTitles = [tutorialEnums.Title];

[selection, ok] = listdlg('ListString', tutorialTitles, 'ListSize', [360, 240]);

if ok
tutorialEnum = tutorialEnums(selection);
else
error('User canceled.')
end
end
9 changes: 7 additions & 2 deletions code/+nansen/+internal/+setup/verifyInstallation.m
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
function verifyInstallation()
function verifyInstallation(options)
% verifyInstallation - Verify that NANSEN has everything it needs to work

arguments
options.MathworksProductMissingAlertMode = "error"
end

nansen.internal.setup.checkWidgetsToolboxVersion();

% Check whether required Mathworks products are installed.
nansen.internal.dependencies.checkRequiredMathworksProducts('error')
nansen.internal.dependencies.checkRequiredMathworksProducts( ...
options.MathworksProductMissingAlertMode)

% Java classpath setup is a recurring pain. Verify that everything is
% set up correctly before continuing.
Expand Down
Binary file modified code/GettingStarted.mlx
Binary file not shown.
57 changes: 31 additions & 26 deletions code/examples/nansen_tutorial.m
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
% Prepare environment and run tutorial initialization
function nansen_tutorial(tutorial)

% install core nansen dependencies if missing
deps = nansen.internal.dependencies.resolveRequirements('MissingOnly', true);
if ~isempty(deps)
nansen.install()
else
nansen.internal.setup.verifyInstallation()
end

try
nansen.App.getInstance();
answer = questdlg('NANSEN is already open. Quit NANSEN and run tutorial?', 'Quit NANSEN?', 'Yes', 'No', 'Cancel', 'Yes');
switch answer
case 'Yes'
nansen.quit()
otherwise
error('User canceled')
arguments
tutorial nansen.app.tutorial.enum.Tutorial {mustBeScalarOrEmpty} = nansen.app.tutorial.enum.Tutorial.empty
end
catch exception
switch exception.identifier
case 'NANSEN:App:ApplicationNotRunning'
% Continue
otherwise
rethrow(exception)

% Install core nansen dependencies if missing
deps = nansen.internal.dependencies.resolveRequirements('MissingOnly', true);
if ~isempty(deps)
nansen.install()
else
nansen.internal.setup.verifyInstallation()
end

try
nansen.App.getInstance();
answer = questdlg('NANSEN is already open. Quit NANSEN and run tutorial?', 'Quit NANSEN?', 'Yes', 'No', 'Cancel', 'Yes');
switch answer
case 'Yes'
nansen.quit()
otherwise
error('User canceled')
end
catch exception
switch exception.identifier
case 'NANSEN:App:ApplicationNotRunning'
% Continue
otherwise
rethrow(exception)
end
end

% Run the tutorial initialization
nansen.app.tutorial.loadProject(tutorial)
end

% Run the tutorial initialization
nansen.app.tutorial.loadProject()
Loading