Skip to content

Commit bf87cdf

Browse files
committed
Huge speed update: major overhaul of replotting the main panel
1 parent a50342f commit bf87cdf

File tree

8 files changed

+120
-76
lines changed

8 files changed

+120
-76
lines changed

@SplitMerge/SplitMerge.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
% groups of UI items:
5151
SplitChaps
52-
SpikePanels
52+
SpikePanels cell
5353
OutlierPanels
5454
DeetPanels
5555
PCAPanels

@SplitMerge/colorCheckChg.m

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@ function colorCheckChg(app,~)
33
if val ~= app.Settings.Colorful
44
app.Settings.Colorful = val;
55
%plot_units(app);
6+
unq = unique(app.Data.spikes.assigns);
67
if app.Settings.Colorful
7-
for u = 1:length(app.SpikePanels)
8-
app.SpikePanels{u}.Children(1).Color = app.Data.colors(u,:);
8+
for u = 1:length(unq)
9+
if ~isempty(app.SpikePanels{unq(u)}) && ~isempty(app.SpikePanels{unq(u)}.Children)
10+
app.SpikePanels{unq(u)}.Children(1).Color = app.Data.colors(u,:);
11+
end
912
end
1013
else
11-
for u = 1:length(app.SpikePanels)
12-
app.SpikePanels{u}.Children(1).Color = [0 0.4470 0.7410];
14+
for u = 1:length(unq)
15+
if ~isempty(app.SpikePanels{unq(u)}) && ~isempty(app.SpikePanels{unq(u)}.Children)
16+
app.SpikePanels{unq(u)}.Children(1).Color = [0 0.4470 0.7410];
17+
end
1318
end
1419
end
1520
end
16-
end
21+
end

@SplitMerge/makeColors.m

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,38 @@
11
function cols = makeColors(~,n)
22
if exist('hex2col','file')
33
% hard-coded palette:
4-
col_str = '#e6194B,#3cb44b,#ffe119,#4363d8,#f58231,#911eb4,#42d4f4,#f032e6,#bfef45,#fabebe,#469990,#e6beff,#9A6324,#5f7ba8,#800000,#aaffc3,#808000,#5fa870,#000075,#a9a9a9,#000000';
5-
col_str = strsplit(col_str,',');
4+
palette = [
5+
0.9020 0.0980 0.2941
6+
0.2353 0.7059 0.2941
7+
1.0000 0.8824 0.0980
8+
0.2627 0.3882 0.8471
9+
0.9608 0.5098 0.1922
10+
0.5686 0.1176 0.7059
11+
0.2588 0.8314 0.9569
12+
0.9412 0.1961 0.9020
13+
0.7490 0.9373 0.2706
14+
0.9804 0.7451 0.7451
15+
0.2745 0.6000 0.5647
16+
0.9020 0.7451 1.0000
17+
0.6039 0.3882 0.1412
18+
0.3725 0.4824 0.6588
19+
0.5020 0 0
20+
0.6667 1.0000 0.7647
21+
0.5020 0.5020 0
22+
0.3725 0.6588 0.4392
23+
0 0 0.4588
24+
0.6627 0.6627 0.6627
25+
0 0 0
26+
];
27+
628
c = 0;
729
cols = NaN(n,3);
830
for u = 1:n
931
c = c + 1;
10-
if c > length(col_str) % wrap around if > 19 clusters
32+
if c > size(palette,1) % wrap around if > 21 clusters
1133
c = 1;
1234
end
13-
cols(u,:) = hex2col(col_str{c});
35+
cols(u,:) = palette(c,:);
1436
end
1537
else
1638
if exist('distinguishable_colors','file')
@@ -19,4 +41,4 @@
1941
cols = lines(n);
2042
end
2143
end
22-
end
44+
end

@SplitMerge/markGood.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ function markGood(app,~)
33
ids = app.Data.Selected;
44
disp([9 'Setting unit(s) ' num2str(ids) ' as "good"'])
55
end
6-
6+
77
setLabel(app,2); % bit silly, to wrap this function. But might come in handy later.
88
app.Data.modified(1) = 1;
99
app.refreshScreen();
10-
end
10+
end

@SplitMerge/plotUnits.m

Lines changed: 71 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ function plotUnits(app)
44
% app.Data.modifyList. We should only update those axes!
55
app.Data.loader = uiprogressdlg(app.UIFigure,'Title','Please Wait',...
66
'Message','Loading clusters');
7-
% Delete all previous spike panels
8-
ch = app.UnitsPanel.Children;
9-
for c = 1:length(ch)
10-
delete(ch);
11-
app.SpikePanels = [];
12-
end
137

148
app.RecalcButton.Position = [app.TabMerge.Position(3)-450 app.TabMerge.Position(4)-30 145 24];
159
app.AggCutoff.Position = app.RecalcButton.Position + [-120 0 -30 0];
@@ -49,64 +43,74 @@ function plotUnits(app)
4943

5044
app.SelectedUnits.Items = {'Loading...'};
5145

46+
temp = cellfun(@isempty,app.SpikePanels);
47+
currentlyPlotted = find(~temp);
48+
clear temp
49+
toDrop = setdiff(currentlyPlotted,unq); % remove panels that aren't in there
50+
for t = 1:length(toDrop)
51+
delete(app.SpikePanels{toDrop(t)});
52+
app.SpikePanels{toDrop(t)} = [];
53+
end
54+
5255
yl = NaN(2,length(unq)); % for scaling if app.Settings.ToScale == true
5356
for u = 1:length(unq)
57+
% if it doesn't have an axes plotted for it:
58+
if length(app.SpikePanels) < unq(u) || isempty(app.SpikePanels{unq(u)})
59+
app.SpikePanels{unq(u)} = uiaxes(app.UnitsPanel);
60+
% a bit redundant, but may allow for compressing cell array later:
61+
% (can't at present if a new unit appears with a lower UID than an old one)
62+
app.SpikePanels{unq(u)}.UserData.UID = unq(u);
63+
app.Data.modifyList = [app.Data.modifyList unq(u)];
64+
end
65+
5466
app.Data.loader.Message = ['Loading unit ' num2str(u) ' of ' num2str(length(unq))];
5567

5668
xpos = mod(u-1,4);
5769
ypos = floor((u-1)/4);
58-
59-
app.SpikePanels{u} = uiaxes(app.UnitsPanel);
60-
app.SpikePanels{u}.Position = [margin+(xpos*w) (start_y-(ypos*w))-max_y w w];
61-
62-
t = (0:size(app.Data.spikes.waveforms,2)-1)/(app.Data.spikes.params.Fs/1e3);
63-
t = t - app.Data.spikes.params.cross_time;
64-
65-
ids = app.Data.spikes.assigns == unq(u);
66-
waveforms = app.Data.spikes.waveforms(ids,:);
67-
[tt,wvs] = compressSpikes(app,t,waveforms);
68-
69-
if app.Settings.Colorful
70-
line(app.SpikePanels{u},tt,wvs,'Color',app.Data.colors(u,:));
71-
else
72-
line(app.SpikePanels{u},tt,wvs);
73-
end
74-
75-
rpv = sum(diff(app.Data.spikes.spiketimes(ids)) <= (app.Data.spikes.params.refractory_period * 0.001));
76-
plural = '';
77-
if rpv ~= 1, plural = 's'; end
78-
if rpv/length(app.Data.spikes.spiketimes(ids)) > 0.02
79-
rpvCol = 'red';
80-
else
81-
rpvCol = 'gray';
70+
app.SpikePanels{unq(u)}.Position = [margin+(xpos*w) (start_y-(ypos*w))-max_y w w];
71+
if any(ismember(app.Data.modifyList,unq(u)))
72+
cla(app.SpikePanels{unq(u)});
73+
t = (0:size(app.Data.spikes.waveforms,2)-1)/(app.Data.spikes.params.Fs/1e3);
74+
t = t - app.Data.spikes.params.cross_time;
75+
76+
ids = app.Data.spikes.assigns == unq(u);
77+
waveforms = app.Data.spikes.waveforms(ids,:);
78+
[tt,wvs] = compressSpikes(app,t,waveforms);
79+
80+
if app.Settings.Colorful
81+
line(app.SpikePanels{unq(u)},tt,wvs,'Color',app.Data.colors(u,:));
82+
else
83+
line(app.SpikePanels{unq(u)},tt,wvs);
84+
end
85+
86+
rpv = sum(diff(app.Data.spikes.spiketimes(ids)) <= (app.Data.spikes.params.refractory_period * 0.001));
87+
plural = '';
88+
if rpv ~= 1, plural = 's'; end
89+
if rpv/length(app.Data.spikes.spiketimes(ids)) > 0.02
90+
rpvCol = 'red';
91+
else
92+
rpvCol = 'gray';
93+
end
94+
95+
label = app.Data.spikes.labels(app.Data.spikes.labels(:,1) == unq(u),2);
96+
if label == 2
97+
labelCol = '0 0.6 0.2';
98+
else
99+
labelCol = '0 0 0';
100+
end
101+
app.SpikePanels{unq(u)}.Title.String = ['{\color[rgb]{' labelCol '}Unit ' num2str(unq(u)) '}: n = ' num2str(size(waveforms,1)) ' {\color{' rpvCol '}(' num2str(rpv) ' RPV' plural ')}'];
102+
103+
disableDefaultInteractivity(app.SpikePanels{unq(u)});
104+
app.SpikePanels{unq(u)}.XGrid = 'on';
105+
app.SpikePanels{unq(u)}.YGrid = 'on';
106+
if isfield(app.SpikePanels{unq(u)},'Toolbar')
107+
app.SpikePanels{unq(u)}.Toolbar.Visible = 'off';
108+
end
109+
110+
xlim(app.SpikePanels{unq(u)},[t(1) t(end)]);
82111
end
83-
84-
label = app.Data.spikes.labels(app.Data.spikes.labels(:,1) == unq(u),2);
85-
if label == 2
86-
labelCol = '0 0.6 0.2';
87-
else
88-
labelCol = '0 0 0';
89-
end
90-
app.SpikePanels{u}.Title.String = ['{\color[rgb]{' labelCol '}Unit ' num2str(unq(u)) '}: n = ' num2str(size(waveforms,1)) ' {\color{' rpvCol '}(' num2str(rpv) ' RPV' plural ')}'];
91-
92-
disableDefaultInteractivity(app.SpikePanels{u});
93-
app.SpikePanels{u}.XGrid = 'on';
94-
app.SpikePanels{u}.YGrid = 'on';
95-
if isfield(app.SpikePanels{u},'Toolbar')
96-
app.SpikePanels{u}.Toolbar.Visible = 'off';
97-
end
98-
99-
%app.SpikePanels{u}.ButtonDownFcn = createCallbackFcn(app, @UnitClick, true);
100-
101-
%{
102-
app.SpikePanels{u}.XColor = 'none';
103-
yl = ylim(app.SpikePanels{u});
104-
text(app.SpikePanels{u},-0.6, yl(1), [num2str(yl(1)) '�V']);
105-
text(app.SpikePanels{u},-0.6, yl(2), [num2str(yl(2)) '�V']);
106-
%}
107-
xlim(app.SpikePanels{u},[t(1) t(end)]);
108-
109-
yl(:,u) = ylim(app.SpikePanels{u});
112+
% TODO: need to have a handle to the line for each panel, and update its color if needed here
113+
yl(:,u) = ylim(app.SpikePanels{unq(u)});
110114

111115
app.SelectedUnits.Items{u} = ['Unit ' num2str(unq(u))];
112116

@@ -124,10 +128,18 @@ function plotUnits(app)
124128
% link the axes, and apply the largest ylim
125129
% linkaxes(app.SpikePanels,'y'); linkaxes doesn't work with UIAxes objects in r2018b...
126130
for u = 1:length(unq)
127-
set(app.SpikePanels{u},'YLim',[min(yl(:)) max(yl(:))])
131+
set(app.SpikePanels{unq(u)},'YLim',[min(yl(:)) max(yl(:))])
128132
end
129133
end
130-
134+
%{
135+
if app.Settings.Colorful
136+
for u = 1:length(unq)
137+
app.SpikePanels{unq(u)}.Children(1).Color = app.Data.colors(u,:);
138+
else
139+
app.SpikePanels{unq(u)}.Children(1).Color = [0 0.4470 0.7410];
140+
end
141+
end
142+
%}
131143
app.Data.modified(1) = 0;
132144
app.Data.doFirstPlot(1) = 0;
133145
app.Data.modifyList = [];

@SplitMerge/scaleCheckChg.m

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@ function scaleCheckChg(app,~)
55
if app.Settings.ToScale
66
yl = NaN(2,length(app.SpikePanels));
77
for u = 1:length(app.SpikePanels)
8-
yl(:,u) = get(app.SpikePanels{u},'YLim');
8+
if ~isempty(app.SpikePanels{u})
9+
yl(:,u) = get(app.SpikePanels{u},'YLim');
10+
end
911
end
1012
for u = 1:length(app.SpikePanels)
1113
set(app.SpikePanels{u},'YLim',[min(yl(:)) max(yl(:))])
1214
end
1315
else
1416
for u = 1:length(app.SpikePanels)
15-
set(app.SpikePanels{u},'YLimMode','auto')
17+
if ~isempty(app.SpikePanels{u})
18+
set(app.SpikePanels{u},'YLimMode','auto')
19+
end
1620
end
1721
end
1822
end
19-
end
23+
end

@SplitMerge/setLabel.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ function setLabel(app,which)
1010
app.Data.spikes.labels(ids(2:end),:) = [];
1111
end
1212
end
13+
app.Data.modifyList = [app.Data.modifyList app.Data.Selected];
1314
%pushHistory(app,'l',selected,which);
1415
end

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ __Noise removal tab:__
3535
- [ ] Remove or document all necessary alterations to the base UMS toolbox
3636
- [ ] Write the help documentation!
3737
- [x] Add app.Data.modifylist array for future use (minimizing replots)
38-
- [ ] Update the replotting of the Inspect/merge panel to make use of app.Data.modifylist data and avoid full re-plot
38+
- [x] Update the replotting of the Inspect/merge panel to make use of app.Data.modifylist data and avoid full re-plot
3939
- [x] Add in confirmation of file change when alterations have been made (use app.Data.modified array?)
4040
- [x] Occasionally marking a unit as "good" results in multiple entries in the labels structure – update setLabel method to check for these

0 commit comments

Comments
 (0)