33import numpy as np
44from PyQt5 import QtWidgets , QtCore , QtGui , uic
55import pyqtgraph as pg
6-
7- from iblapps import qt
6+ import scipy .signal
7+ from brainbox .processing import bincount2D
8+ import qt
89from iblutil .numerical import ismember
910from easyqc .gui import viewseis
10-
11-
12- def viewephys (data , fs , channels = None , br = None , title = 'ephys' ):
11+ from ibllib .io import spikeglx
12+ from ibllib .dsp import voltage
13+
14+
15+ class RasterView (QtWidgets .QMainWindow ):
16+ def __init__ (self , bin_file , spikes , clusters , channels = None , trials = None , * args , ** kwargs ):
17+ self .sr = spikeglx .Reader (bin_file )
18+ self .spikes = spikes
19+ self .clusters = clusters
20+ self .channels = channels
21+ self .eqcs = []
22+ super (RasterView , self ).__init__ (* args , ** kwargs )
23+ # wave by Diana Militano from the Noun Projectp
24+ uic .loadUi (Path (__file__ ).parent .joinpath ('raster.ui' ), self )
25+ background_color = self .palette ().color (self .backgroundRole ())
26+ self .plotItem_raster .setAspectLocked (False )
27+ self .imageItem_raster = pg .ImageItem ()
28+ self .plotItem_raster .setBackground (background_color )
29+ self .plotItem_raster .addItem (self .imageItem_raster )
30+ self .viewBox_raster = self .plotItem_raster .getPlotItem ().getViewBox ()
31+ s = self .viewBox_raster .scene ()
32+ # vb.scene().sigMouseMoved.connect(self.mouseMoveEvent)
33+ 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 )
39+ self .imageItem_raster .setImage (np .flip (self .raster .T ))
40+ transform = [t_bin , 0. , 0. , 0. , d_bin , 0. , - .5 , - .5 , 1. ]
41+ self .transform = np .array (transform ).reshape ((3 , 3 )).T
42+ self .imageItem_raster .setTransform (QtGui .QTransform (* transform ))
43+ self .plotItem_raster .setLimits (xMin = 0 , xMax = self .rtimes [- 1 ], yMin = 0 , yMax = self .depths [- 1 ])
44+
45+ # set colormap
46+ cm = pg .colormap .get ('Greys' , source = 'matplotlib' ) # prepare a linear color map
47+ bar = pg .ColorBarItem (values = (0 , .5 ), colorMap = cm ) # prepare interactive color bar
48+ # Have ColorBarItem control colors of img and appear in 'plot':
49+ bar .setImageItem (self .imageItem_raster )
50+ self .show ()
51+
52+
53+
54+ def mouseClick (self , event ):
55+ if not event .double ():
56+ return
57+ qxy = self .imageItem_raster .mapFromScene (event .scenePos ())
58+ self .show_ephys (t0 = self .rtimes [int (qxy .x ())])
59+
60+ def keyPressEvent (self , e ):
61+ """
62+ page-up / ctrl + a : gain up
63+ page-down / ctrl + z : gain down
64+ :param e:
65+ """
66+ k , m = (e .key (), e .modifiers ())
67+ # page up / ctrl + a
68+ if k == QtCore .Qt .Key_PageUp or (
69+ m == QtCore .Qt .ControlModifier and k == QtCore .Qt .Key_A ):
70+ self .imageItem_raster .setLevels ([0 , self .imageItem_raster .levels [1 ] / 1.4 ])
71+ # page down / ctrl + z
72+ elif k == QtCore .Qt .Key_PageDown or (
73+ m == QtCore .Qt .ControlModifier and k == QtCore .Qt .Key_Z ):
74+ self .imageItem_raster .setLevels ([0 , self .imageItem_raster .levels [1 ] * 1.4 ])
75+
76+ def show_ephys (self , t0 , len = 1 ):
77+
78+ first = int (t0 * self .sr .fs )
79+ last = first + int (self .sr .fs * len )
80+
81+ raw = self .sr [first :last , : - self .sr .nsync ].T
82+
83+ butter_kwargs = {'N' : 3 , 'Wn' : 300 / self .sr .fs * 2 , 'btype' : 'highpass' }
84+ sos = scipy .signal .butter (** butter_kwargs , output = 'sos' )
85+ butt = scipy .signal .sosfiltfilt (sos , raw )
86+ destripe = voltage .destripe (raw , fs = self .sr .fs )
87+
88+ # overlay spikes
89+ tprobe = self .spikes .samples / self .sr .fs
90+ slice_spikes = slice (np .searchsorted (tprobe , t0 ), np .searchsorted (tprobe , t0 + len ))
91+ t = tprobe [slice_spikes ]
92+ 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+
98+ self .eqc_raw .ctrl .add_scatter (t , c )
99+ self .eqc_des .ctrl .add_scatter (t , c )
100+ # eqc2.ctrl.add_scatter(t, c)
101+
102+
103+
104+
105+ def viewephys (data , fs , channels = None , br = None , title = 'ephys' , t0 = 0 , t_scalar = 1e3 ):
13106 """
14107 :param data: [nc, ns]
15108 :param fs:
@@ -28,15 +121,15 @@ def viewephys(data, fs, channels=None, br=None, title='ephys'):
28121 from ibllib .ephys .neuropixel import trace_header
29122 if channels is None or br is None :
30123 channels = trace_header (version = 1 )
31- eqc = viewseis (data .T , si = 1 / fs * 1e3 , h = channels , title = title , taxis = 0 )
124+ eqc = viewseis (data .T , si = 1 / fs * t_scalar , h = channels , title = title , taxis = 0 , t0 = t0 )
32125 return eqc
33126 else :
34127 _ , ir = ismember (channels ['atlas_id' ], br .id )
35128 image = br .rgb [ir ].astype (np .uint8 )
36129 image = image [np .newaxis , :, :]
37130
38131
39- eqc = viewseis (data .T , si = 1 / fs * 1e3 , h = channels , title = title , taxis = 0 )
132+ eqc = viewseis (data .T , si = 1 / fs * t_scalar , h = channels , title = title , taxis = 0 )
40133 imitem = pg .ImageItem (image )
41134 eqc .plotItem_header_v .addItem (imitem )
42135 transform = [1 , 0 , 0 , 0 , 1 , 0 , - 0.5 , 0 , 1. ]
0 commit comments