Skip to content

Commit ecec9a1

Browse files
committed
raster viewer local server
1 parent 2c84598 commit ecec9a1

File tree

2 files changed

+77
-23
lines changed

2 files changed

+77
-23
lines changed

viewspikes/gui.py

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,40 @@
11
from pathlib import Path
22

33
import numpy as np
4+
import scipy.signal
5+
46
from PyQt5 import QtWidgets, QtCore, QtGui, uic
57
import pyqtgraph as pg
6-
import scipy.signal
78
from brainbox.processing import bincount2D
89
import qt
910
from iblutil.numerical import ismember
1011
from easyqc.gui import viewseis
1112
from ibllib.io import spikeglx
1213
from ibllib.dsp import voltage
1314

15+
T_BIN = .007 # time bin size in secs
16+
D_BIN = 10 # depth bin size in um
17+
18+
SNS_PALETTE = [(0.12156862745098039, 0.4666666666666667, 0.7058823529411765),
19+
(1.0, 0.4980392156862745, 0.054901960784313725),
20+
(0.17254901960784313, 0.6274509803921569, 0.17254901960784313),
21+
(0.8392156862745098, 0.15294117647058825, 0.1568627450980392),
22+
(0.5803921568627451, 0.403921568627451, 0.7411764705882353),
23+
(0.5490196078431373, 0.33725490196078434, 0.29411764705882354),
24+
(0.8901960784313725, 0.4666666666666667, 0.7607843137254902),
25+
(0.4980392156862745, 0.4980392156862745, 0.4980392156862745),
26+
(0.7372549019607844, 0.7411764705882353, 0.13333333333333333),
27+
(0.09019607843137255, 0.7450980392156863, 0.8117647058823529)]
28+
29+
YMAX = 4000
1430

1531
class RasterView(QtWidgets.QMainWindow):
1632
def __init__(self, bin_file, spikes, clusters, channels=None, trials=None, *args, **kwargs):
1733
self.sr = spikeglx.Reader(bin_file)
1834
self.spikes = spikes
1935
self.clusters = clusters
2036
self.channels = channels
37+
self.trials = trials
2138
self.eqcs = []
2239
super(RasterView, self).__init__(*args, **kwargs)
2340
# wave by Diana Militano from the Noun Projectp
@@ -31,31 +48,54 @@ def __init__(self, bin_file, spikes, clusters, channels=None, trials=None, *args
3148
s = self.viewBox_raster.scene()
3249
# vb.scene().sigMouseMoved.connect(self.mouseMoveEvent)
3350
s.sigMouseClicked.connect(self.mouseClick)
34-
35-
# set image
36-
t_bin = .007
37-
d_bin = 10
38-
self.raster, self.rtimes, self.depths = bincount2D(spikes.times, spikes.depths, t_bin, d_bin)
51+
################################################### set image
52+
iok = ~np.isnan(spikes.depths)
53+
self.raster, self.rtimes, self.depths = bincount2D(
54+
spikes.times[iok], spikes.depths[iok], T_BIN, D_BIN)
3955
self.imageItem_raster.setImage(np.flip(self.raster.T))
40-
transform = [t_bin, 0., 0., 0., d_bin, 0., - .5, - .5, 1.]
56+
transform = [T_BIN, 0., 0., 0., D_BIN, 0., - .5, - .5, 1.]
4157
self.transform = np.array(transform).reshape((3, 3)).T
4258
self.imageItem_raster.setTransform(QtGui.QTransform(*transform))
4359
self.plotItem_raster.setLimits(xMin=0, xMax=self.rtimes[-1], yMin=0, yMax=self.depths[-1])
44-
4560
# set colormap
4661
cm = pg.colormap.get('Greys', source='matplotlib') # prepare a linear color map
4762
bar = pg.ColorBarItem(values=(0, .5), colorMap=cm) # prepare interactive color bar
4863
# Have ColorBarItem control colors of img and appear in 'plot':
4964
bar.setImageItem(self.imageItem_raster)
50-
self.show()
51-
65+
################################################## plot location
66+
# self.view.layers[label] = {'layer': new_scatter, 'type': 'scatter'}
67+
self.line_eqc = pg.PlotCurveItem()
68+
self.plotItem_raster.addItem(self.line_eqc)
69+
# self.plotItem_raster.removeItem(new_curve)
70+
################################################## plot trials
71+
if self.trials is not None:
72+
trial_times = dict(
73+
goCue_times=trials['goCue_times'],
74+
error_times=trials['feedback_times'][trials['feedbackType'] == -1],
75+
reward_times=trials['feedback_times'][trials['feedbackType'] == 1])
76+
self.trial_lines = {}
77+
for i, k in enumerate(trial_times):
78+
self.trial_lines[k] = pg.PlotCurveItem()
79+
self.plotItem_raster.addItem(self.trial_lines[k])
80+
x = np.tile(trial_times[k][:, np.newaxis], (1, 2)).flatten()
81+
y = np.tile(np.array([0, 1, 1, 0]), int(trial_times[k].shape[0] / 2 + 1))[
82+
:trial_times[k].shape[0] * 2] * YMAX
83+
self.trial_lines[k].setData(x=x.flatten(), y=y.flatten(), pen=pg.mkPen(np.array(SNS_PALETTE[i]) * 256))
5284

85+
self.show()
5386

5487
def mouseClick(self, event):
88+
"""Draws a line on the raster and display in EasyQC"""
5589
if not event.double():
5690
return
5791
qxy = self.imageItem_raster.mapFromScene(event.scenePos())
58-
self.show_ephys(t0=self.rtimes[int(qxy.x())])
92+
x = qxy.x()
93+
self.show_ephys(t0=self.rtimes[int(x - .5)])
94+
ymax = np.max(self.depths) + 50
95+
self.line_eqc.setData(x=x + np.array([-.5, -.5, .5, .5]),
96+
y=np.array([0, ymax, ymax, 0]),
97+
pen=pg.mkPen((0, 255, 0)))
98+
5999

60100
def keyPressEvent(self, e):
61101
"""
@@ -73,10 +113,10 @@ def keyPressEvent(self, e):
73113
m == QtCore.Qt.ControlModifier and k == QtCore.Qt.Key_Z):
74114
self.imageItem_raster.setLevels([0, self.imageItem_raster.levels[1] * 1.4])
75115

76-
def show_ephys(self, t0, len=1):
116+
def show_ephys(self, t0, tlen=1):
77117

78118
first = int(t0 * self.sr.fs)
79-
last = first + int(self.sr.fs * len)
119+
last = first + int(self.sr.fs * tlen)
80120

81121
raw = self.sr[first:last, : - self.sr.nsync].T
82122

@@ -85,19 +125,21 @@ def show_ephys(self, t0, len=1):
85125
butt = scipy.signal.sosfiltfilt(sos, raw)
86126
destripe = voltage.destripe(raw, fs=self.sr.fs)
87127

128+
self.eqc_raw = viewephys(butt, self.sr.fs, channels=None, br=None, title='butt', t0=t0, t_scalar=1)
129+
self.eqc_des = viewephys(destripe, self.sr.fs, channels=None, br=None, title='destripe', t0=t0, t_scalar=1)
130+
131+
eqc_xrange = [t0 + tlen / 2 - 0.01, t0 + tlen / 2 + 0.01]
132+
self.eqc_des.viewBox_seismic.setXRange(*eqc_xrange)
133+
self.eqc_raw.viewBox_seismic.setXRange(*eqc_xrange)
134+
135+
# eqc2 = viewephys(butt - destripe, self.sr.fs, channels=None, br=None, title='diff')
88136
# overlay spikes
89137
tprobe = self.spikes.samples / self.sr.fs
90-
slice_spikes = slice(np.searchsorted(tprobe, t0), np.searchsorted(tprobe, t0 + len))
138+
slice_spikes = slice(np.searchsorted(tprobe, t0), np.searchsorted(tprobe, t0 + tlen))
91139
t = tprobe[slice_spikes]
92140
c = self.clusters.channels[self.spikes.clusters[slice_spikes]]
93-
94-
self.eqc_raw = viewephys(butt, self.sr.fs, channels=None, br=None, title='butt', t0=t0, t_scalar=1)
95-
self.eqc_des = viewephys(destripe, self.sr.fs, channels=None, br=None, title='destripe', t0=t0, t_scalar=1)
96-
# eqc2 = viewephys(butt - destripe, self.sr.fs, channels=None, br=None, title='diff')
97-
98141
self.eqc_raw.ctrl.add_scatter(t, c)
99142
self.eqc_des.ctrl.add_scatter(t, c)
100-
# eqc2.ctrl.add_scatter(t, c)
101143

102144

103145

viewspikes/raster.ui

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>810</width>
10-
<height>606</height>
9+
<width>999</width>
10+
<height>656</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
@@ -36,12 +36,24 @@
3636
<rect>
3737
<x>0</x>
3838
<y>0</y>
39-
<width>810</width>
39+
<width>999</width>
4040
<height>22</height>
4141
</rect>
4242
</property>
43+
<widget class="QMenu" name="menuFile">
44+
<property name="title">
45+
<string>File</string>
46+
</property>
47+
<addaction name="actionopen"/>
48+
</widget>
49+
<addaction name="menuFile"/>
4350
</widget>
4451
<widget class="QStatusBar" name="statusbar"/>
52+
<action name="actionopen">
53+
<property name="text">
54+
<string>open...</string>
55+
</property>
56+
</action>
4557
</widget>
4658
<customwidgets>
4759
<customwidget>

0 commit comments

Comments
 (0)