Skip to content

Commit

Permalink
Merge pull request #108 from bahanonu/bahanonu/functionUpdates
Browse files Browse the repository at this point in the history
Code and GUI improvements, NoRMCorre and additional file formats support, etc.
  • Loading branch information
bahanonu authored Sep 14, 2022
2 parents 53b424b + 1655feb commit 31f31dd
Show file tree
Hide file tree
Showing 70 changed files with 4,110 additions and 1,513 deletions.
2 changes: 1 addition & 1 deletion +ciapkg/+api/getMovieFileType.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [movieType, supported, movieType2] = getMovieFileType(thisMoviePath)
function [movieType, supported, movieType2] = getMovieFileType(thisMoviePath,varargin)
% Determine how to load movie, don't assume every movie in list is of the same type
% Biafra Ahanonu
% started: 2020.09.01 [‏‎14:16:57]
Expand Down
32 changes: 32 additions & 0 deletions +ciapkg/+api/getSeriesNoFromName.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
function [bfSeriesNo] = getSeriesNoFromName(inputMoviePath,bfSeriesName,varargin)
% [bfSeriesNo] = getSeriesNoFromName(inputFilePath,bfSeriesName,varargin)
%
% Returns series number for Bio-Formats series with name given by user.
%
% Biafra Ahanonu
% started: 2022.07.15 [08:10:16]
%
% Inputs
% inputFilePath - Str: path to Bio-Formats compatible file.
% bfSeriesName - Str: name of series within the file. Can be a regular expression.
%
% Outputs
% bfSeriesNo - Int: series number (1-based indexing) matching the input series name. NaN is output if no series is found.
%
% Options (input as Name-Value with Name = options.(Name))
% % File ID connection from calling bfGetReader(inputFilePath), this is to save time on larger files by avoiding opening the connection again.
% options.fileIdOpen = '';

% Changelog
%
% TODO
%

try
bfSeriesNo = ciapkg.bf.getSeriesNoFromName(inputMoviePath,bfSeriesName,'passArgs',varargin);
catch err
disp(repmat('@',1,7))
disp(getReport(err,'extended','hyperlinks','on'));
disp(repmat('@',1,7))
end
end
27 changes: 27 additions & 0 deletions +ciapkg/+api/loadSignalExtractionSorting.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
function [valid, algorithmStr, infoStruct] = loadSignalExtractionSorting(inputFilePath,varargin)
% [valid,algorithmStr,infoStruct] = loadSignalExtractionSorting(inputFilePath,varargin)
%
% Loads manual or automated (e.g. CLEAN) sorting..
%
% Biafra Ahanonu
% started: 2022.05.31 [20:14:54] (branched from modelVarsFromFiles)
%
% Inputs
% inputFilePath - Str: path to signal extraction output.
%
% Outputs
% valid - logical vector: indicating which signals are valid and should be kept.
% algorithmStr - Str: algorithm name.
% infoStruct - Struct: contains information about the file, e.g. the 'description' property that can contain information about the algorithm.
%
% Options (input as Name-Value with Name = options.(Name))
% % DESCRIPTION
% options.exampleOption = '';

% Changelog
%
% TODO
%

[valid, algorithmStr, infoStruct] = ciapkg.io.loadSignalExtractionSorting(inputFilePath,'passArgs', varargin);
end
9 changes: 8 additions & 1 deletion +ciapkg/+api/manageParallelWorkers.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,12 @@
% Biafra Ahanonu
% started: 2015.12.01

[success] = ciapkg.io.manageParallelWorkers('passArgs', varargin);
% changelog
% 2022.02.28 [18:36:15] - Added ability to input just the number of workers to open as 1st single input argument that aliases for the "setNumCores" Name-Value input, still support other input arguments as well.

if length(varargin)==1
[success] = ciapkg.io.manageParallelWorkers(varargin{1});
else
[success] = ciapkg.io.manageParallelWorkers('passArgs', varargin);
end
end
17 changes: 17 additions & 0 deletions +ciapkg/+api/mergeStructs.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function [pullStruct] = mergeStructs(toStruct,fromStruct,varargin)
% [toStruct] = mergeStructs(fromStruct,toStruct,overwritePullFields)
%
% Copies fields in fromStruct into toStruct, if there is an overlap in field names, fromStruct overwrites toStruct unless specified otherwise.
%
% Biafra Ahanonu
% started: 2014.02.12
%
% inputs
% toStruct - Structure that is to be updated with values from fromStruct.
% fromStruct - structure to use to overwrite toStruct.
% overwritePullFields - 1 = overwrite toStruct fields with fromStruct, 0 = don't overwrite.
% outputs
% toStruct - structure with fromStructs values added.

[pullStruct] = ciapkg.io.mergeStructs(toStruct,fromStruct,'passArgs', varargin);
end
3 changes: 3 additions & 0 deletions +ciapkg/+api/normalizeSignalExtractionActivityTraces.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
function inputSignals = normalizeSignalExtractionActivityTraces(inputSignals,inputImages, varargin)
% [inputSignals] = ciapkg.signal_extraction.normalizeSignalExtractionActivityTraces(inputSignals,inputImages,'passArgs', varargin);
%
% Normalizes cell activity traces by the max value in the associated image, normally to produce dF/F equivalent activity traces
%
% started: 2019.08.25 [18:19:34]
% Biafra Ahanonu
% Branched from normalizeCELLMaxTraces (Lacey Kitch and Biafra Ahanonu)
Expand Down
76 changes: 76 additions & 0 deletions +ciapkg/+bf/dispFileSeries.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
function [seriesNameArray] = dispFileSeries(inputFilePath,varargin)
% [bfSeriesNo] = getSeriesNoFromName(inputFilePath,bfSeriesName,varargin)
%
% Returns series number for Bio-Formats series with name given by user.
%
% Biafra Ahanonu
% started: 2022.07.15 [08:10:16]
%
% Inputs
% inputFilePath - Str: path to Bio-Formats compatible file.
%
% Outputs
% bfSeriesNo - Int: series number (1-based indexing) matching the input series name. NaN is output if no series is found.
%
% Options (input as Name-Value with Name = options.(Name))
% % File ID connection from calling bfGetReader(inputFilePath), this is to save time on larger files by avoiding opening the connection again.
% options.fileIdOpen = '';

% Changelog
%
% TODO
%

% ========================
% File ID connection from calling bfGetReader(inputFilePath), this is to save time on larger files by avoiding opening the connection again.
options.fileIdOpen = [];
% get options
options = ciapkg.io.getOptions(options,varargin);
% disp(options)
% unpack options into current workspace
% fn=fieldnames(options);
% for i=1:length(fn)
% eval([fn{i} '=options.' fn{i} ';']);
% end
% ========================

try
% By default output NaN if no series found.
seriesNameArray = {};

if isempty(options.fileIdOpen)
disp(['Opening connection to Bio-Formats file:' inputFilePath])
startReadTime = tic;
fileIdOpen = bfGetReader(inputFilePath);
toc(startReadTime)
else
fileIdOpen = options.fileIdOpen;
end
omeMeta = fileIdOpen.getMetadataStore();

nSeries = fileIdOpen.getSeriesCount();
seriesNameArray = cell([1 nSeries]);
disp('===')
disp(['Series in file: ' inputFilePath])
for seriesNo = 1:nSeries
% Convert 1-based to 0-based indexing.
thisStr = char(omeMeta.getImageName(seriesNo-1));
seriesNameArray{seriesNo} = thisStr;
disp([num2str(seriesNo) ': "' thisStr '"'])
end
disp('===')
catch err
disp(repmat('@',1,7))
disp(getReport(err,'extended','hyperlinks','on'));
disp(repmat('@',1,7))
end

function [outputs] = nestedfxn_exampleFxn(arg)
% Always start nested functions with "nestedfxn_" prefix.
% outputs = ;
end
end
function [outputs] = localfxn_exampleFxn(arg)
% Always start local functions with "localfxn_" prefix.
% outputs = ;
end
88 changes: 88 additions & 0 deletions +ciapkg/+bf/getSeriesNoFromName.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
function [bfSeriesNo] = getSeriesNoFromName(inputFilePath,bfSeriesName,varargin)
% [bfSeriesNo] = getSeriesNoFromName(inputFilePath,bfSeriesName,varargin)
%
% Returns series number for Bio-Formats series with name given by user.
%
% Biafra Ahanonu
% started: 2022.07.15 [08:10:16]
%
% Inputs
% inputFilePath - Str: path to Bio-Formats compatible file.
% bfSeriesName - Str: name of series within the file. Can be a regular expression.
%
% Outputs
% bfSeriesNo - Int: series number (1-based indexing) matching the input series name. NaN is output if no series is found.
%
% Options (input as Name-Value with Name = options.(Name))
% % File ID connection from calling bfGetReader(inputFilePath), this is to save time on larger files by avoiding opening the connection again.
% options.fileIdOpen = '';

% Changelog
%
% TODO
%

% ========================
% File ID connection from calling bfGetReader(inputFilePath), this is to save time on larger files by avoiding opening the connection again.
options.fileIdOpen = [];
% get options
options = ciapkg.io.getOptions(options,varargin);
% disp(options)
% unpack options into current workspace
% fn=fieldnames(options);
% for i=1:length(fn)
% eval([fn{i} '=options.' fn{i} ';']);
% end
% ========================

try
% By default output NaN if no series found.
bfSeriesNo = NaN;

if isempty(options.fileIdOpen)
disp(['Opening connection to Bio-Formats file:' inputFilePath])
startReadTime = tic;
fileIdOpen = bfGetReader(inputFilePath);
toc(startReadTime)
else
fileIdOpen = options.fileIdOpen;
end
omeMeta = fileIdOpen.getMetadataStore();

if isempty(bfSeriesName)
disp('Please provide a series name for Bio-Formats')
else
disp(['Searching for series: "' bfSeriesName '"'])
nSeries = fileIdOpen.getSeriesCount();
seriesNameArray = cell([1 nSeries]);
disp('===')
disp(['Series in file: ' inputFilePath])
for seriesNo = 1:nSeries
% Convert 1-based to 0-based indexing.
thisStr = char(omeMeta.getImageName(seriesNo-1));
seriesNameArray{seriesNo} = thisStr;
disp([num2str(seriesNo) ': "' thisStr '"'])
end
disp('===')
matchIdx = ~cellfun(@isempty,regexp(seriesNameArray,bfSeriesName));
if any(matchIdx)
bfSeriesNo = find(matchIdx);
bfSeriesNo = bfSeriesNo(1);
disp(['Series found: ' num2str(bfSeriesNo) ' - "' seriesNameArray{bfSeriesNo} '"'])
end
end
catch err
disp(repmat('@',1,7))
disp(getReport(err,'extended','hyperlinks','on'));
disp(repmat('@',1,7))
end

function [outputs] = nestedfxn_exampleFxn(arg)
% Always start nested functions with "nestedfxn_" prefix.
% outputs = ;
end
end
function [outputs] = localfxn_exampleFxn(arg)
% Always start local functions with "localfxn_" prefix.
% outputs = ;
end
52 changes: 35 additions & 17 deletions +ciapkg/+classification/signalSorter.m
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
function [inputImages, inputSignals, choices] = signalSorter(inputImages,inputSignals,varargin)
% [inputImages, inputSignals, choices] = signalSorter(inputImages,inputSignals,varargin)
%
% Displays a GUI for sorting images (e.g. cells) and their associated signals (e.g. fluorescence activity traces). Also does preliminary sorting based on image/signal properties if requested by user.
% See following URL for details of GUI and tips on manual sorting: https://github.com/bahanonu/calciumImagingAnalysis/wiki/Manual-cell-sorting-of-cell-extraction-outputs.
%
% See following URL for details of GUI and tips on manual sorting: https://bahanonu.github.io/ciatah/help_manual_cell_sorting/.
%
% Biafra Ahanonu
% started: 2013.10.08
%
% Dependent code
% getOptions.m, createObjMap.m, removeSmallICs.m, identifySpikes.m, etc., see repository
% inputs
% inputImages - [x y N] matrix where N = number of images, x/y are dimensions. Use permute(inputImages,[2 3 1]) if you use [N x y] for matrix indexing.
% Alternatively, make inputImages = give path to NWB file and inputSignals = [] for signalSorter to automatically load NWB files.
% inputSignals - [N time] matrix where N = number of signals (traces) and time = frames.
% inputID - obsolete, kept for compatibility, just input empty []
% nSignals - obsolete, kept for compatibility
% outputs
% inputImages - [N x y] matrix where N = number of images, x/y are dimensions with only manual choices kept.
% inputSignals
% choices
% getOptions.m, createObjMap.m, removeSmallICs.m, identifySpikes.m, etc., see CIAtah repository.
%
% Inputs
% <strong>inputImages</strong>
% 1) [x y N] matrix where N = number of images, x/y are dimensions. Use permute(inputImages,[2 3 1]) if you use [N x y] for matrix indexing.
% 2) Path to NWB file and inputSignals = [] for signalSorter to automatically load NWB files.
% <strong>inputSignals</strong> - [N time] matrix where N = number of signals (traces) and time = frames.
% inputID - obsolete, kept for compatibility, just input empty []
% nSignals - obsolete, kept for compatibility
%
% Outputs
% <strong>inputImages</strong> - Matrix: filtered with only good outputs. [N x y] matrix where N = number of images, x/y are dimensions with only manual choices kept.
% <strong>inputSignals</strong> - Matrix: filtered with only good outputs. [N time] matrix where N = number of signals (traces) and time = frames.
% <strong>choices</strong> - [1 N] vector using the below key:
% 1 = yes
% 0 = no
% 2 = not designated by user

% changelog
% 2013.10.xx changed to ginput and altered UI to show more relevant information, now shows a objMap overlayed with the current filter, etc.
Expand Down Expand Up @@ -78,6 +89,7 @@
% 2021.12.22 [08:19:19] - Updated suptitle to ciapkg.overloaded.suptitle. Also limit number of GUI re-runs to prevent infinite looping.
% 2022.01.19 [12:35:42] - Fixed issue with `gca.XRuler.Axle.LineStyle` being an empty object when axes created, leading to failure to assign and error loops.
% 2022.02.06 [20:06:19] - Make all openFigure to ciapkg.api.openFigure.
% 2022.03.14 [01:10:52] - Comments update.
% TODO
% DONE: New GUI interface to allow users to scroll through video and see cell activity at that point
% DONE: allow option to mark rest as bad signals
Expand Down Expand Up @@ -171,8 +183,9 @@
options.randomizeOrder = 0;
% show ROI traces in addition to input traces
options.showROITrace = 0;
% pre-compute signal peaks
% Matrix: save time if already computed peaks. [nSignals frame] matrix. Binary matrix with 1 = peaks, 0 = non-peaks.
options.signalPeaks = [];
% Cell array: save time if already computed peaks. {1 nSignals} cell array. Each cell contains [1 nPeaks] vector that stores the frame locations of each peak.
options.signalPeaksArray = [];
% ROI for peak signal plotting
options.peakROI = -20:20;
Expand Down Expand Up @@ -1550,17 +1563,18 @@ function plotSignalStatistics(inputSignals,inputImageSizes,inputStr,pointColor,
set(zoomHandle,'ActionPostCallback',@sliderZoomCallback);
end

% Create progress bar
[axValid, axValidAll] = subfxn_progressBarCreate(axValid, axValidAll);

set(objMapPlotLocHandle,'tag','objMapPlotLocHandle')
set(objMapZoomPlotLocHandle,'tag','objMapZoomPlotLocHandle')
% if strcmp(get(zoom(1),'Enable'),'off')
% pan on;
% end
set(objMapPlotLocHandle,'ButtonDownFcn',@subfxnSelectCellOnCellmap)
set(objMapZoomPlotLocHandle,'ButtonDownFcn',@subfxnSelectCellOnCellmap)
set(mainFig, 'KeyPressFcn', @(source,eventdata) figure(mainFig));

% Create progress bar
[axValid, axValidAll] = subfxn_progressBarCreate(axValid, axValidAll);
set(mainFig, 'KeyPressFcn', @(source,eventdata) figure(mainFig));

while strcmp(keyIn,'3')
frameNoTotal = frameNoTotal+1;
Expand All @@ -1583,6 +1597,8 @@ function plotSignalStatistics(inputSignals,inputImageSizes,inputStr,pointColor,
end
set(objMapPlotLocHandle,'tag','objMapPlotLocHandle')
set(objMapZoomPlotLocHandle,'tag','objMapZoomPlotLocHandle')
set(objMapPlotLocHandle,'ButtonDownFcn',@subfxnSelectCellOnCellmap)
set(objMapZoomPlotLocHandle,'ButtonDownFcn',@subfxnSelectCellOnCellmap)

reply = double(keyIn);
set(gcf,'currentch','3');
Expand Down Expand Up @@ -2109,6 +2125,7 @@ function mouseWheelChange(hObject, callbackdata, handles)
set(gcf,'uicontextmenu',conMenu);
end
function subfxnSelectCellOnCellmap(source,eventdata)
disp('Click screen')
if showCrossHairs==1
[xUser,yUser,~] = ciapkg.overloaded.ginputCustom(1);
else
Expand All @@ -2118,6 +2135,7 @@ function subfxnSelectCellOnCellmap(source,eventdata)
end
mapTags = {'objMapPlotLocHandle','objMapZoomPlotLocHandle'};
thisPlotTag = find(ismember(mapTags, get(gca,'tag')));
thisPlotTag
if isempty(thisPlotTag)
% zoom;
elseif thisPlotTag<0|thisPlotTag>length(mapTags)
Expand Down Expand Up @@ -2551,7 +2569,7 @@ function subfxnLostFocusMainFig(jAxis, jEventData, hFig)
croppedPeakImages = cat(3,meanTransientImage,croppedPeakImages);

croppedPeakImages222 = compareSignalToMovie(inputMovie, inputImage, thisTrace,'getOnlyPeakImages',1,'waitbarOn',0,'extendedCrosshairs',2,'crossHairVal',maxValMovie*options.crossHairPercent,'outlines',0,'signalPeakArray',signalPeakArray,'cropSize',cropSizeLength,'crosshairs',0,'addPadding',1,'xCoords',xCoords,'yCoords',yCoords,'outlineVal',NaN,'inputDatasetName',options.inputDatasetName,'inputMovieDims',options.inputMovieDims,'hdf5Fid',options.hdf5Fid,'keepFileOpen',options.keepFileOpen);
[thresholdedImages, boundaryIndices] = thresholdImages(croppedPeakImages222(:,:,1),'binary',1,'getBoundaryIndex',1,'threshold',options.thresholdOutline,'removeUnconnectedBinary',0);
[thresholdedImages, boundaryIndices] = thresholdImages(croppedPeakImages222(:,:,1),'binary',1,'getBoundaryIndex',1,'threshold',options.thresholdOutline,'removeUnconnectedBinary',0,'waitbarOn',0);
for imageNo = 1:size(croppedPeakImages,3)
tmpImg = croppedPeakImages(:,:,imageNo);
tmpImg(boundaryIndices{1}) = NaN;
Expand Down
Loading

0 comments on commit 31f31dd

Please sign in to comment.