Changes to AmplitudeView
See original GitHub issueI’ve prototyped some changes to the Amplitude view that would add some functionality.
Feature # 1 Allow the user to define the ‘amplitude’ plotted in the AmplitudeView. Options for ‘Amplitude’ could be:
- Raw amplitude - max value minus min value of the mean waveform (mV) on CHANNEL.
- Projection onto principal component 0 (same as FeatureView) on CHANNEL
- Projection onto template of the first selected cluster
CHANNEL would be the primary channel of the first selected cluster (not the primary channel of each cluster) by default and could be modified by a ctrl+left click on the WaveformView (same as for FeatureView).
It would be great to have a hotkey that enabled toggling between these. Perhaps Ctrl+1,2,3…
Feature # 2 Show all ‘background’ events associated with clusters which share a channel with the primary channel of the selected cluster.
For example, suppose I have only 3 clusters.
Cluster 1: primary channel is channel 10 and in the TemplateView, Channels 7-13 are displayed
Cluster 2: primary channel is channel 12 and in the TemplateView, Channels 9-15 are displayed
Cluster 3: primary channel is channel 14 and in the TemplateView, Channels 11-17 are displayed
If I select Cluster 1, then CHANNEL would be 10 and the events associated with Cluster 1 would be displayed as well as the events from Cluster 2, since channel 10 is displayed in the TemplateView, but Cluster 3 would not be displayed because 10 is not within 11-17.
I used the implementation below to prototype these features and would be happy to re-write following your style, but it may just be easier for you to do it.
apps/template/gui.py
#MODIFIED
def get_amplitudes(self, cluster_ids, chan=None, load_all=False):
n = self.n_spikes_amplitudes if not load_all else None
m = self.model
data_bounds = [0., 0., m.duration, None]
full_l = (self.supervisor.clustering.cluster_ids)
if chan is None:
chan=self.get_best_channel(cluster_ids[0])
bunchs = []
for cid in full_l:
if chan in self.get_best_channels(cid):
spike_ids = self.selector.select_spikes([cid], n)
#raw amplitude (mV) -- very slow because doing max-min every time
#data = m.get_waveforms(spike_ids,[chan])
#y = np.subtract(np.amax(data,axis=1),np.amin(data,axis=1))
#x = m.spike_times[spike_ids]
#PC0
y = self.get_features(cid,[chan]).data[:,0,0]
x = self.get_spike_times(cid).data
# Projection onto selected Cluster template -- breaks on new cluster assignment (merge/split)
#y = m.get_template_features(spike_ids)[:,cluster_ids[0]]
#x = m.spike_times[spike_ids]
if not (cid in cluster_ids):
bunchs.append(Bunch(x=x, y=y, spike_ids=spike_ids,
data_bounds=data_bounds, br=True, col=[1,1,1,.15]))
else:
bunchs.append(Bunch(x=x, y=y, spike_ids=spike_ids,
data_bounds=data_bounds, br=False, col=cluster_ids.index(cid)))
ymax = max(b.y.max() for b in bunchs)
for bunch in bunchs:
bunch.data_bounds[-1] = ymax
return bunchs
cluster/views/scatter.py
# in imports:
import phy.apps.template.gui as pat
#to ensure that I only respond to channel click with AmplitudeView in on_channel_click
#MODIFIED
def _plot_points(self, bunchs, data_bounds):
ms = self._default_marker_size
xmin, ymin, xmax, ymax = data_bounds
self.visual.reset_batch()
for i, d in enumerate(bunchs):
x, y = d.x, d.y
assert x.ndim == y.ndim == 1
assert x.shape == y.shape
if hasattr(d,'br'):
if d.br:
color = d.col
else:
color = selected_cluster_color(d.col,0.75)
else:
color = selected_cluster_color(i,0.75)
# Create one visual per cluster.
self.visual.add_batch_data(x=x, y=y, color=color, size=ms, data_bounds=data_bounds)
self.canvas.update_visual(self.visual)
#ADDED
def on_channel_click(self, sender=None, channel_id=None, key=None, button=None):
if channel_id is not None and isinstance(self,pat.AmplitudeView):
bunchs = self.coords(self.cluster_ids,chan=channel_id)
if bunchs is None:
self.visual.hide()
self.canvas.update()
return
self.visual.show()
self.data_bounds = self._get_data_bounds(bunchs)
self._plot_points(bunchs, self.data_bounds)
self.canvas.axes.reset_data_bounds(self.data_bounds)
self.canvas.update()
#MODIFIED
def attach(self, gui):
super(ScatterView, self).attach(gui)
connect(self.on_request_split)
connect(self.on_channel_click)
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (5 by maintainers)
Thank you for the details and for the prototype, it was really helpful for implementing these features properly. Your proposal is now part of phy natively and I believe it will be useful to many users!
I ended up implementing just a single amplitude view where you can toggle betweel
template
,raw
, andfeature
amplitude types by pressinga
. You can still split in that view. Histograms are shown as well. And, for thefeature
type, you can choose the dimension from the feature view withalt+left click
for the x axis, andalt+right click
for the y axis.Please try it and let me know if you have any issues or suggestions.
@mswallac Thanks. FYI you can directly edit your comment on this issue instead of creating a new one