Skip to content

Commit 47530ae

Browse files
committed
Cache SpikeViewer display settings by spike channel
1 parent be8d65f commit 47530ae

9 files changed

Lines changed: 141 additions & 78 deletions

File tree

Plugins/BasicSpikeDisplay/SpikeDetector/SpikeDetector.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,15 @@ SpikeChannel* SpikeDetector::addSpikeChannel (SpikeChannel::Type type,
536536
selectedChannels,
537537
spikeChannel->getNumChannels()));
538538

539+
//Whenever a new spike channel is created, we need to update the unique ID
540+
//TODO: This should be automatically done in the SpikeChannel constructor next time we change the API
541+
const Array<const ContinuousChannel*>& sourceChannels = spikeChannel->getSourceChannels();
542+
std::string cacheKey = std::to_string(sourceChannels[0]->getSourceNodeId());
543+
cacheKey += "|" + spikeChannel->getStreamName().toStdString();
544+
cacheKey += "|" + name.toStdString();
545+
546+
spikeChannel->setIdentifier(cacheKey);
547+
539548
return spikeChannel;
540549

541550
}

Plugins/BasicSpikeDisplay/SpikeDisplayNode/SpikeDisplay.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ void SpikeDisplay::clear()
5656

5757
}
5858

59-
SpikePlot* SpikeDisplay::addSpikePlot(int numChannels, int electrodeNum, String name_)
59+
SpikePlot* SpikeDisplay::addSpikePlot(int numChannels, int electrodeNum, String name_, std::string identifier_)
6060
{
6161

6262
LOGD("Adding spike plot for electrode: ", electrodeNum, " named: ", name_, " with ", numChannels, " channels");
6363

64-
SpikePlot* spikePlot = new SpikePlot(canvas, electrodeNum, 1000 + numChannels, name_);
64+
SpikePlot* spikePlot = new SpikePlot(canvas, electrodeNum, 1000 + numChannels, name_, identifier_);
6565
spikePlots.add(spikePlot);
6666
addAndMakeVisible(spikePlot);
6767
spikePlot->invertSpikes(shouldInvert);
@@ -260,13 +260,13 @@ float SpikeDisplay::getRangeForWaveAxis(int plotNum, int axisNum)
260260
void SpikeDisplay::setThresholdForWaveAxis(int plotNum, int axisNum, float range)
261261
{
262262
if (spikePlots.size() > plotNum)
263-
return spikePlots[plotNum]->setDisplayThresholdForChannel(axisNum, range);
263+
spikePlots[plotNum]->setDisplayThresholdForChannel(axisNum, range);
264264
}
265265

266266
void SpikeDisplay::setRangeForWaveAxis(int plotNum, int axisNum, float range)
267267
{
268268
if (spikePlots.size() > plotNum)
269-
return spikePlots[plotNum]->setRangeForChannel(axisNum, range);
269+
spikePlots[plotNum]->setRangeForChannel(axisNum, range);
270270
}
271271

272272
bool SpikeDisplay::getMonitorStateForPlot(int plotNum)
@@ -278,5 +278,5 @@ bool SpikeDisplay::getMonitorStateForPlot(int plotNum)
278278
void SpikeDisplay::setMonitorStateForPlot(int plotNum, bool state)
279279
{
280280
if (spikePlots.size() > plotNum)
281-
return spikePlots[plotNum]->setMonitorState(state);
281+
spikePlots[plotNum]->setMonitorState(state);
282282
}

Plugins/BasicSpikeDisplay/SpikeDisplayNode/SpikeDisplay.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class SpikeDisplay : public Component
5454
void clear();
5555

5656
/** Adds a spike plot with 1, 2, or 3 channels*/
57-
SpikePlot* addSpikePlot(int numChannels, int electrodeNum, String name);
57+
SpikePlot* addSpikePlot(int numChannels, int electrodeNum, String name, std::string identifier);
5858

5959
/** Returns a spike plot based on index*/
6060
SpikePlot* getSpikePlot(int index);

Plugins/BasicSpikeDisplay/SpikeDisplayNode/SpikeDisplayCanvas.cpp

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -108,33 +108,10 @@ SpikeDisplayCanvas::SpikeDisplayCanvas(SpikeDisplayNode* processor_) :
108108
addAndMakeVisible(viewport.get());
109109

110110
update();
111-
}
112-
113-
void SpikeDisplayCanvas::cacheDisplaySettings(int electrode, int channel, double threshold, double range, bool isMonitored)
114-
{
115-
thresholds[electrode][channel] = threshold;
116-
ranges[electrode][channel] = range;
117-
monitors[electrode] = isMonitored;
118-
}
119-
120-
void SpikeDisplayCanvas::cacheDisplayThreshold(int electrode, int channel, double threshold)
121-
{
122-
thresholds[electrode][channel] = threshold;
123-
}
124111

125-
bool SpikeDisplayCanvas::hasCachedDisplaySettings(int electrode, int channel)
126-
{
127-
return thresholds[electrode].count(channel) > 0;
128-
}
129-
130-
void SpikeDisplayCanvas::invalidateDisplaySettings(int electrodeIndex)
131-
{
132-
thresholds.erase(electrodeIndex);
133-
ranges.erase(electrodeIndex);
134-
monitors.erase(electrodeIndex);
112+
cache = std::make_unique<SpikeDisplayCache>();
135113
}
136114

137-
138115
void SpikeDisplayCanvas::update()
139116
{
140117

@@ -149,27 +126,29 @@ void SpikeDisplayCanvas::update()
149126
for (int i = 0; i < nPlots; i++)
150127
{
151128
SpikePlot* sp = spikeDisplay->addSpikePlot(processor->getNumberOfChannelsForElectrode(i), i,
152-
processor->getNameForElectrode(i));
129+
processor->getNameForElectrode(i), processor->getSpikeChannel(i)->getIdentifier().toStdString());
130+
153131
processor->addSpikePlotForElectrode(sp, i);
154132

155-
if (monitors.size())
133+
std::string cacheKey = processor->getSpikeChannel(i)->getIdentifier().toStdString();
134+
135+
if (cache && cache->hasCachedDisplaySettings(cacheKey))
156136
{
157137

158-
spikeDisplay->setMonitorStateForPlot(i, monitors[i]);
138+
spikeDisplay->setMonitorStateForPlot(i, cache->isMonitored(cacheKey));
159139

160140
for (int j = 0; j < processor->getNumberOfChannelsForElectrode(i); j++)
161141
{
162-
163-
LOGD("Updating spike plot: ", i, " channel: ", j, " threshold: ", thresholds[i][j], " range: ", ranges[i][j])
164-
spikeDisplay->setThresholdForWaveAxis(i,j,thresholds[i][j]);
165-
spikeDisplay->setRangeForWaveAxis(i,j,ranges[i][j]);
166-
spikeDisplay->setMonitorStateForPlot(i,monitors[i]);
142+
spikeDisplay->setThresholdForWaveAxis(i,j,cache->getThreshold(cacheKey,j));
143+
spikeDisplay->setRangeForWaveAxis(i,j,cache->getRange(cacheKey, j));
167144
}
168145

169146
}
147+
170148
}
171149

172150
spikeDisplay->resized();
151+
spikeDisplay->refresh();
173152

174153
}
175154

@@ -240,33 +219,48 @@ void SpikeDisplayCanvas::saveCustomParametersToXml(XmlElement* xml)
240219
xmlNode->setAttribute("LockThresholds", lockThresholdsButton->getToggleState());
241220
xmlNode->setAttribute("InvertSpikes", invertSpikesButton->getToggleState());
242221

243-
for (int i = 0; i < spikeDisplay->getNumPlots(); i++)
222+
int spikePlotIdx = -1;
223+
224+
for (int i = 0; i < processor->getTotalSpikeChannels(); i++)
244225
{
226+
if (!processor->getSpikeChannel(i)->isValid())
227+
continue;
228+
229+
spikePlotIdx++;
230+
245231
XmlElement* plotNode = xmlNode->createNewChildElement("PLOT");
246232

233+
plotNode->setAttribute("name", processor->getSpikeChannel(i)->getIdentifier());
247234
plotNode->setAttribute("isMonitored", spikeDisplay->getMonitorStateForPlot(i));
248235

249236
for (int j = 0; j < spikeDisplay->getNumChannelsForPlot(i); j++)
250237
{
251238
XmlElement* axisNode = plotNode->createNewChildElement("AXIS");
252239
axisNode->setAttribute("thresh",spikeDisplay->getThresholdForWaveAxis(i,j));
253240
axisNode->setAttribute("range",spikeDisplay->getRangeForWaveAxis(i,j));
254-
255241
}
256242
}
257243

244+
xmlNode->setAttribute("NumPlots", spikePlotIdx+1);
245+
258246
}
259247

260248
void SpikeDisplayCanvas::loadCustomParametersFromXml(XmlElement* xml)
261249
{
262250

263-
thresholds.clear();
264-
ranges.clear();
265251

266252
for (auto* xmlNode : xml->getChildIterator())
267253
{
268254
if (xmlNode->hasTagName("SPIKEDISPLAY"))
269255
{
256+
257+
if (xmlNode->getIntAttribute("NumPlots", 0) != processor->getTotalSpikeChannels())
258+
{
259+
//SpikeDisplayNode has not loaded all spike channels from all incoming branches yet.
260+
//Wait until the processor has loaded all channels before loading the saved settings.
261+
return;
262+
}
263+
270264
spikeDisplay->invertSpikes(xmlNode->getBoolAttribute("InvertSpikes"));
271265
invertSpikesButton->setToggleState(xmlNode->getBoolAttribute("InvertSpikes"), dontSendNotification);
272266
lockThresholdsButton->setToggleState(xmlNode->getBoolAttribute("LockThresholds"), sendNotification);
@@ -277,12 +271,11 @@ void SpikeDisplayCanvas::loadCustomParametersFromXml(XmlElement* xml)
277271
{
278272
if (plotNode->hasTagName("PLOT"))
279273
{
280-
281274
plotIndex++;
282275

283-
monitors[plotIndex] = plotNode->getBoolAttribute("isMonitored");
276+
std::string cacheKey = processor->getSpikeChannel(plotIndex)->getIdentifier().toStdString();
284277

285-
//std::cout << "PLOT NUMBER " << plotIndex << std::endl;
278+
cache->setMonitor(cacheKey, plotNode->getBoolAttribute("isMonitored"));
286279

287280
int channelIndex = -1;
288281

@@ -291,8 +284,8 @@ void SpikeDisplayCanvas::loadCustomParametersFromXml(XmlElement* xml)
291284
if (channelNode->hasTagName("AXIS"))
292285
{
293286
channelIndex++;
294-
thresholds[plotIndex][channelIndex] = channelNode->getDoubleAttribute("thresh");
295-
ranges[plotIndex][channelIndex] = channelNode->getDoubleAttribute("range");
287+
cache->setThreshold(cacheKey, channelIndex, channelNode->getDoubleAttribute("thresh"));
288+
cache->setRange(cacheKey, channelIndex, channelNode->getDoubleAttribute("range"));
296289
}
297290
}
298291
}

Plugins/BasicSpikeDisplay/SpikeDisplayNode/SpikeDisplayCanvas.h

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,62 @@
3434
class SpikePlot;
3535
class SpikeDisplayNode;
3636

37+
class SpikeDisplayCache
38+
{
39+
public:
40+
SpikeDisplayCache () {}
41+
virtual ~SpikeDisplayCache() {}
42+
43+
void setMonitor(std::string key, bool isMonitored) {
44+
monitors[key] = isMonitored;
45+
};
46+
47+
bool isMonitored(std::string key) {
48+
return monitors[key];
49+
};
50+
51+
void setRange(std::string key, int channelIdx, double range) {
52+
ranges[key][channelIdx] = range;
53+
};
54+
55+
double getRange(std::string key, int channelIdx) {
56+
return ranges[key][channelIdx];
57+
};
58+
59+
void setThreshold(std::string key,int channelIdx, double thresh) {
60+
thresholds[key][channelIdx] = thresh;
61+
};
62+
63+
double getThreshold(std::string key, int channelIdx) {
64+
return thresholds[key][channelIdx];
65+
};
66+
67+
bool hasCachedDisplaySettings(std::string cacheKey)
68+
{
69+
/*
70+
LOGDD("SpikeDisplayCache keys:");
71+
std::vector<std::string> keys = extract_keys(ranges);
72+
std::vector<std::map<int,double>> vals = extract_values(ranges);
73+
for (int i = 0; i < keys.size(); i++)
74+
{
75+
std::vector<int> channels = extract_keys(vals[i]);
76+
std::vector<double> ranges = extract_values(vals[i]);
77+
for (int j = 0; j < channels.size(); j++)
78+
LOGDD("Key: ", keys[i], " Channel: ", channels[j], " Range: ", ranges[j]);
79+
}
80+
*/
81+
return thresholds.count(cacheKey) > 0;
82+
};
83+
84+
private:
85+
86+
std::map<std::string, std::map<int, double>> ranges;
87+
std::map<std::string, std::map<int, double>> thresholds;
88+
std::map<std::string, bool> monitors;
89+
90+
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SpikeDisplayCache);
91+
};
92+
3793
/**
3894
Allows spike plot thresholds to be adjusted synchronously
3995
*/
@@ -125,13 +181,18 @@ class SpikeDisplayCanvas : public Visualizer,
125181
/** Pointer to the underlying SpikeDisplayNode*/
126182
SpikeDisplayNode* processor;
127183

128-
void cacheDisplaySettings(int electrodeIndex, int channelIndex, double threshold, double range, bool isMonitored);
184+
void cacheDisplayThreshold(std::string cacheKey, int channelIndex, double threshold);
185+
186+
void cacheDisplayRange(std::string cacheKey, int channelIndex, double range);
129187

130-
void cacheDisplayThreshold(int electrodeIndex, int channelIndex, double threshold);
188+
void cacheMonitorState(std::string cacheKey, bool monitorState);
131189

132-
bool hasCachedDisplaySettings(int electrodeIndex, int channelIndex);
190+
bool hasCachedDisplaySettings(std::string cacheKey);
133191

134-
void invalidateDisplaySettings(int electrodeIndex);
192+
void invalidateDisplaySettings(std::string cacheKey);
193+
194+
/** Manages connections from SpikeChannels to SpikePlots */
195+
std::unique_ptr<SpikeDisplayCache> cache;
135196

136197
private:
137198

@@ -147,10 +208,6 @@ class SpikeDisplayCanvas : public Visualizer,
147208
std::unique_ptr<UtilityButton> lockThresholdsButton;
148209
std::unique_ptr<UtilityButton> invertSpikesButton;
149210

150-
std::map<int, std::map<int, double>> ranges;
151-
std::map<int, std::map<int, double>> thresholds;
152-
std::map<int, bool> monitors;
153-
154211
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SpikeDisplayCanvas);
155212

156213
};

Plugins/BasicSpikeDisplay/SpikeDisplayNode/SpikeDisplayNode.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
class DataViewport;
3030
class SpikePlot;
3131

32-
3332
/**
3433
Looks for incoming Spike events and draws them to the SpikeDisplayCanvas.
3534

0 commit comments

Comments
 (0)