From e2ae8b68a9887b348d97d0a1ae41503fcc3e1080 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Fri, 29 Mar 2019 14:55:34 -0400 Subject: [PATCH] Fix #102 --- .../+curate/@CurateController/saveFiles.m | 64 +++++++++++++------ +jrclust/+interfaces/@Clustering/Clustering.m | 4 +- .../DensityPeakClustering.m | 9 ++- .../@TemplateClustering/TemplateClustering.m | 4 +- +jrclust/+sort/@TemplateClustering/refresh.m | 24 +++---- @JRC/loadFiles.m | 23 +++++++ @JRC/saveRes.m | 54 +++++++++------- CHANGELOG.TXT | 2 +- 8 files changed, 122 insertions(+), 62 deletions(-) diff --git a/+jrclust/+curate/@CurateController/saveFiles.m b/+jrclust/+curate/@CurateController/saveFiles.m index 979adee2..50a3668b 100644 --- a/+jrclust/+curate/@CurateController/saveFiles.m +++ b/+jrclust/+curate/@CurateController/saveFiles.m @@ -5,39 +5,63 @@ obj.cRes.curatedOn = now(); res_ = jrclust.utils.mergeStructs(obj.res, obj.cRes); - % don't save these large fields + res_ = rmfield(res_, 'hClust'); + + hClust = obj.hClust; + + res_.initialClustering = hClust.initialClustering; + res_.spikeClusters = hClust.spikeClusters; + + % fieldnames contained in dRes or sRes + dsFields = union(fieldnames(hClust.dRes), fieldnames(hClust.sRes)); + % fieldnames from hClust which are not in dRes or sRes + hClustOnly = setdiff(fieldnames(hClust), dsFields); + for i = 1:numel(hClustOnly) + fn = hClustOnly{i}; + % hClust fields take precedence + res_.(fn) = hClust.(fn); + end + + % don't save these fields if isfield(res_, 'spikesRaw') res_ = rmfield(res_, 'spikesRaw'); end + if isfield(res_, 'spikesRawVolt') + res_ = rmfield(res_, 'spikesRawVolt'); + end if isfield(res_, 'spikesFilt') res_ = rmfield(res_, 'spikesFilt'); end + if isfield(res_, 'spikesFiltVolt') + res_ = rmfield(res_, 'spikesFiltVolt'); + end + if isfield(res_, 'spikesFilt2') + res_ = rmfield(res_, 'spikesFilt2'); + end + if isfield(res_, 'spikesFilt3') + res_ = rmfield(res_, 'spikesFilt3'); + end if isfield(res_, 'spikeFeatures') res_ = rmfield(res_, 'spikeFeatures'); end + if isfield(res_, 'nClusters') + res_ = rmfield(res_, 'nClusters'); + end + if isfield(res_, 'nEdits') + res_ = rmfield(res_, 'nEdits'); + end + if isfield(res_, 'unitFields') + res_ = rmfield(res_, 'unitFields'); + end + if isfield(res_, 'hRecs') + res_ = rmfield(res_, 'hRecs'); + end - % don't save this stuff twice - restoreFields = struct(); % restore these fields to hClust after saving - restoreFields.dRes = res_.hClust.dRes; - res_.hClust.dRes = []; - - restoreFields.sRes = res_.hClust.sRes; - res_.hClust.sRes = []; - - hMsg = jrclust.utils.qMsgBox('Saving... (this closes automatically)', 0, 1); + hBox = jrclust.utils.qMsgBox('Saving... (this closes automatically)', 0, 1); jrclust.utils.saveStruct(res_, obj.hCfg.resFile); - % restore fields to carry on - if ~obj.isEnding - restoreFieldNames = fieldnames(restoreFields); - for i = 1:numel(restoreFieldNames) - fn = restoreFieldNames{i}; - obj.hClust.(fn) = restoreFields.(fn); - end - end - success = 1; - jrclust.utils.tryClose(hMsg); + jrclust.utils.tryClose(hBox); elseif strcmp(dlgAns, 'No') success = 1; else diff --git a/+jrclust/+interfaces/@Clustering/Clustering.m b/+jrclust/+interfaces/@Clustering/Clustering.m index fa7fd8e8..07221ee8 100644 --- a/+jrclust/+interfaces/@Clustering/Clustering.m +++ b/+jrclust/+interfaces/@Clustering/Clustering.m @@ -17,7 +17,7 @@ end %% SORTING DATA (MUTABLE) - properties (SetAccess=protected, SetObservable) + properties (SetObservable) clusterCentroids; % centroids of clusters on the probe clusterNotes; % notes on clusters clusterSites; % mode site per cluster @@ -46,7 +46,7 @@ end %% QUALITY METRICS - properties (SetAccess=protected, SetObservable) + properties (SetObservable) unitPeaks; % minimum voltage of mean filtered waveforms at peak site, per cluster unitPeaksRaw; % minimum voltage (uV) of mean raw waveforms at peak site, per cluster unitPeakSites; % sites on which unitPeaks occur diff --git a/+jrclust/+sort/@DensityPeakClustering/DensityPeakClustering.m b/+jrclust/+sort/@DensityPeakClustering/DensityPeakClustering.m index c143cc29..dd75a78f 100644 --- a/+jrclust/+sort/@DensityPeakClustering/DensityPeakClustering.m +++ b/+jrclust/+sort/@DensityPeakClustering/DensityPeakClustering.m @@ -208,13 +208,16 @@ end % rhoCuts - function rc = get.rhoCuts(obj) + function val = get.rhoCuts(obj) if isfield(obj.sRes, 'rhoCutSite') - rc = obj.sRes.rhoCutSite; + val = obj.sRes.rhoCutSite; else - rc = []; + val = []; end end + function set.rhoCuts(obj, val) + obj.sRes.rhoCutSite = val; + end % waveformSim/mrWavCor function ss = get.mrWavCor(obj) diff --git a/+jrclust/+sort/@TemplateClustering/TemplateClustering.m b/+jrclust/+sort/@TemplateClustering/TemplateClustering.m index 2a6d8f32..18c08aac 100644 --- a/+jrclust/+sort/@TemplateClustering/TemplateClustering.m +++ b/+jrclust/+sort/@TemplateClustering/TemplateClustering.m @@ -29,7 +29,9 @@ obj.dRes = dRes; obj.hCfg = hCfg; - obj.spikeClusters = sRes.spikeClusters; + if isfield(sRes, 'spikeClusters') + obj.spikeClusters = sRes.spikeClusters; + end obj.clearNotes(); obj.refresh(1, []); diff --git a/+jrclust/+sort/@TemplateClustering/refresh.m b/+jrclust/+sort/@TemplateClustering/refresh.m index 14d34c8e..76adf6e2 100644 --- a/+jrclust/+sort/@TemplateClustering/refresh.m +++ b/+jrclust/+sort/@TemplateClustering/refresh.m @@ -12,20 +12,22 @@ function refresh(obj, doRemoveEmpty, updateMe) obj.templatesByCluster = arrayfun(@(iCluster) unique(obj.spikeTemplates(obj.spikesByCluster{iCluster})), ... 1:obj.nClusters, 'UniformOutput', 0); - templateSim_ = zeros(obj.nClusters); - for iCluster = 1:obj.nClusters - iTemplates = obj.templatesByCluster{iCluster}; % unique template indices for spikes in this cluster + if ~isempty(obj.nClusters) + templateSim_ = zeros(obj.nClusters); + for iCluster = 1:obj.nClusters + iTemplates = obj.templatesByCluster{iCluster}; % unique template indices for spikes in this cluster - % compute cluster sim score, Phy style - sims = max(obj.sRes.simScore(iTemplates, :), [], 1); + % compute cluster sim score, Phy style + sims = max(obj.sRes.simScore(iTemplates, :), [], 1); - for jCluster = iCluster:obj.nClusters - jTemplates = obj.templatesByCluster{jCluster}; - templateSim_(iCluster, jCluster) = max(sims(jTemplates)); - templateSim_(jCluster, iCluster) = templateSim_(iCluster, jCluster); + for jCluster = iCluster:obj.nClusters + jTemplates = obj.templatesByCluster{jCluster}; + templateSim_(iCluster, jCluster) = max(sims(jTemplates)); + templateSim_(jCluster, iCluster) = templateSim_(iCluster, jCluster); + end end - end - obj.templateSim = templateSim_; + obj.templateSim = templateSim_; + end end diff --git a/@JRC/loadFiles.m b/@JRC/loadFiles.m index b654e29e..c8164ac2 100644 --- a/@JRC/loadFiles.m +++ b/@JRC/loadFiles.m @@ -37,6 +37,7 @@ function loadFiles(obj) spikesFilt = []; end + % load spikeFeatures if isfield(res_, 'featuresShape') obj.hCfg.updateLog('loadFeatures', sprintf('Loading %s', obj.hCfg.featuresFile), 1, 0); spikeFeatures = readBin(obj.hCfg.featuresFile, res_.featuresShape, '*single'); @@ -82,6 +83,28 @@ function loadFiles(obj) % supply hClust with our own hCfg res_.hClust.hCfg = obj.hCfg; + elseif isfield(res_, 'spikeTemplates') % create a new TemplateClustering + hClust = jrclust.sort.TemplateClustering(struct(), struct(), obj.hCfg); + fieldNames = fieldnames(res_); + for i = 1:numel(fieldNames) + fn = fieldNames{i}; + if isprop(hClust, fn) + hClust.(fn) = res_.(fn); + end + end + + res_.hClust = hClust; + elseif isfield(res_, 'spikeClusters') + hClust = jrclust.sort.DensityPeakClustering(struct(), struct(), obj.hCfg); + fieldNames = fieldnames(res_); + for i = 1:numel(fieldNames) + fn = fieldNames{i}; + if isprop(hClust, fn) + hClust.(fn) = res_.(fn); + end + end + + res_.hClust = hClust; end if isfield(res_, 'hRecs') % don't try to load recordings diff --git a/@JRC/saveRes.m b/@JRC/saveRes.m index 3ed49d00..3541d038 100644 --- a/@JRC/saveRes.m +++ b/@JRC/saveRes.m @@ -20,37 +20,39 @@ function saveRes(obj, forceOverwrite) obj.hCfg.updateLog('saveRes', sprintf('Saving results to %s', obj.hCfg.resFile), 1, 0); % save everything else (don't save spikesRaw, spikesFilt, % spikeFeatures inside hClust) - restoreFields = struct(); % restore these fields to hClust after saving + % don't save these large fields + res_ = rmfield(obj.res, 'hClust'); + if isfield(obj.res, 'hClust') - restoreFields.dRes = obj.res.hClust.dRes; - obj.res.hClust.dRes = []; + hClust = obj.res.hClust; - restoreFields.sRes = obj.res.hClust.sRes; - obj.res.hClust.sRes = []; + res_.initialClustering = hClust.initialClustering; + res_.spikeClusters = hClust.spikeClusters; - % fieldnames contained in dRes and sRes - dsFields = union(fieldnames(restoreFields.dRes), fieldnames(restoreFields.sRes)); + % fieldnames contained in dRes or sRes + dsFields = union(fieldnames(hClust.dRes), fieldnames(hClust.sRes)); % fieldnames from hClust which are not in dRes or sRes - hClustOnly = setdiff(fieldnames(obj.res.hClust), dsFields); - % any redundancies with res? - intersectFields = intersect(fieldnames(obj.res), hClustOnly); - for i = 1:numel(intersectFields) - fn = intersectFields{i}; - if jrclust.utils.isEqual(obj.res.(fn), obj.res.hClust.(fn)) - restoreFields.(fn) = obj.res.hClust.(fn); - obj.res.hClust.(fn) = []; - end + hClustOnly = setdiff(fieldnames(hClust), dsFields); + for i = 1:numel(hClustOnly) + fn = hClustOnly{i}; + % hClust fields take precedence + res_.(fn) = hClust.(fn); end end - % don't save these large fields - res_ = obj.res; + % don't save these fields if isfield(res_, 'spikesRaw') res_ = rmfield(res_, 'spikesRaw'); end + if isfield(res_, 'spikesRawVolt') + res_ = rmfield(res_, 'spikesRawVolt'); + end if isfield(res_, 'spikesFilt') res_ = rmfield(res_, 'spikesFilt'); end + if isfield(res_, 'spikesFiltVolt') + res_ = rmfield(res_, 'spikesFiltVolt'); + end if isfield(res_, 'spikesFilt2') res_ = rmfield(res_, 'spikesFilt2'); end @@ -60,17 +62,21 @@ function saveRes(obj, forceOverwrite) if isfield(res_, 'spikeFeatures') res_ = rmfield(res_, 'spikeFeatures'); end + if isfield(res_, 'nClusters') + res_ = rmfield(res_, 'nClusters'); + end + if isfield(res_, 'nEdits') + res_ = rmfield(res_, 'nEdits'); + end + if isfield(res_, 'unitFields') + res_ = rmfield(res_, 'unitFields'); + end if isfield(res_, 'hRecs') res_ = rmfield(res_, 'hRecs'); end jrclust.utils.saveStruct(res_, obj.hCfg.resFile); - - restoreFieldNames = fieldnames(restoreFields); - for i = 1:numel(restoreFieldNames) - fn = restoreFieldNames{i}; - obj.res.hClust.(fn) = restoreFields.(fn); - end + obj.res.hClust = hClust; obj.hCfg.updateLog('saveRes', sprintf('Results saved to %s', obj.hCfg.resFile), 0, 1); end \ No newline at end of file diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 07195cb1..331e619a 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -2,7 +2,7 @@ - Allow user to select exploratory clustering algorithm in main split. - Allow user to split in FigProj. - +- hClust is no longer saved to _res.mat. Now all fields are available without having a copy of JRCLUST installed. 27 Mar 2019