def __init__(self): """Init.""" for k in [ 'UiSettings', 'UiPanels', 'UiInfo', 'UiTools', 'UiScoring', 'UiDetection', 'UiAnnotate', 'UiMenu', 'UiScreenshot' ]: eval(k + '.__init__(self)') PROFILER("%s" % k, level=1)
def __init__(self, bgcolor='black', verbose=None, **kwargs): """Init.""" # ====================== PyQt creation ====================== _PyQtModule.__init__(self, verbose=verbose, to_describe='view.wc', icon='brain_icon.svg') self._userobj = {} self._gl_scale = 100. # fix appearance for small meshes self._camera = viscam.TurntableCamera(name='MainBrainCamera') # ====================== Canvas creation ====================== UiInit.__init__(self, bgcolor) # GUI creation + canvas PROFILER("Canvas creation") # ====================== App creation ====================== PROFILER("Visual elements", as_type='title') Visuals.__init__(self, self.view.wc, **kwargs) # ====================== Ui interactions ====================== UiElements.__init__(self) # GUI interactions PROFILER("Ui interactions") self._shpopup.set_shortcuts(self.sh) # shortcuts dict # ====================== Cameras ====================== # Main camera : self.view.wc.camera = self._camera self._vbNode.parent = self.view.wc.scene self.atlas.camera = self._camera self.roi.camera = self._camera self.atlas._csize = self.view.canvas.size self.atlas.rotate('top') self.atlas.camera.set_default_state() PROFILER("Cameras creation") # ====================== Colorbar ====================== camera = viscam.PanZoomCamera(rect=(-.2, -2.5, 1, 5)) BrainCbar.__init__(self, camera) PROFILER("Colorbar and panzoom creation") self.background_color(bgcolor) # ====================== Shortcuts ====================== BrainShortcuts.__init__(self, self.cbqt.cbviz._canvas) PROFILER("Set brain shortcuts") self._fcn_on_load() PROFILER("Functions on load")
def __init__(self): """Init.""" # Bold font : self._font = QtGui.QFont() self._font.setBold(True) self._addspace = ' ' self._pan_pick.currentIndexChanged.connect(self._fcn_pan_pick) # ===================================================================== # MAIN GRID : # ===================================================================== self._chanGrid = QtWidgets.QGridLayout() self._chanGrid.setContentsMargins(-1, -1, -1, 6) self._chanGrid.setSpacing(2) self._chanGrid.setObjectName(_fromUtf8("_chanGrid")) self.gridLayout_21.addLayout(self._chanGrid, 0, 0, 1, 1) PROFILER("Channel grid", level=2) # ===================================================================== # CHANNELS # ===================================================================== # Create check buttons and panels for every channel : self._fcn_chan_check_and_create_w() self._PanChanSelectAll.clicked.connect(self._fcn_select_all_chan) self._PanChanDeselectAll.clicked.connect(self._fcn_deselect_all_chan) self._PanAmpAuto.clicked.connect(self._fcn_chan_auto_amp) self._PanAmpSym.clicked.connect(self._fcn_chan_sym_amp) self._channels_lw.valueChanged.connect(self._fcn_chan_set_lw) self._channels_alias.clicked.connect(self._fcn_chan_antialias) PROFILER("Channel canvas, widgets and buttons", level=2) # ===================================================================== # AMPLITUDES # ===================================================================== # Save all current amplitudes : self._PanAllAmpMax.setValue(100.) self._ylims = np.zeros((len(self), 2), dtype=np.float32) self._fcn_update_amp_info() self._PanAllAmpMin.valueChanged.connect(self._fcn_all_amp) self._PanAllAmpMax.valueChanged.connect(self._fcn_all_amp) PROFILER("Channel amplitudes", level=2) # ===================================================================== # SPECTROGRAM # ===================================================================== # Main canvas for the spectrogram : self._specCanvas = AxisCanvas(axis=self._ax, name='Spectrogram', fcn=[self.on_mouse_wheel]) self._SpecW, self._SpecLayout = self._create_compatible_w( "SpecW", "SpecL") self._SpecLayout.addWidget(self._specCanvas.canvas.native) self._chanGrid.addWidget(self._SpecW, len(self) + 1, 1, 1, 1) # Add label : self._specLabel = QtWidgets.QLabel(self.centralwidget) self._specLabel.setText(self._addspace + self._channels[0]) self._specLabel.setFont(self._font) self._chanGrid.addWidget(self._specLabel, len(self) + 1, 0, 1, 1) # Add list of colormaps : self._cmap_lst = mpl_cmap() self._PanSpecCmap.addItems(self._cmap_lst) self._PanSpecCmap.setCurrentIndex(self._cmap_lst.index(self._defcmap)) # Add list of channels : self._PanSpecChan.addItems(self._channels) # Disable multitaper option if not is_lspopt_installed self._PanSpecMethod.model().item(2).setEnabled(is_lspopt_installed()) # Connect spectrogam properties : self._PanSpecApply.setEnabled(False) self._PanSpecApply.clicked.connect(self._fcn_spec_set_data) self._PanSpecNfft.valueChanged.connect(self._fcn_spec_compat) self._PanSpecStep.valueChanged.connect(self._fcn_spec_compat) self._PanSpecFstart.valueChanged.connect(self._fcn_spec_compat) self._PanSpecFend.valueChanged.connect(self._fcn_spec_compat) self._PanSpecCon.valueChanged.connect(self._fcn_spec_compat) self._PanSpecCmap.currentIndexChanged.connect(self._fcn_spec_compat) self._PanSpecChan.currentIndexChanged.connect(self._fcn_spec_compat) self._PanSpecMethod.currentIndexChanged.connect(self._fcn_spec_compat) self._PanSpecCmapInv.clicked.connect(self._fcn_spec_compat) self._PanSpecNorm.currentIndexChanged.connect(self._fcn_spec_compat) self._PanSpecInterp.currentIndexChanged.connect(self._fcn_spec_interp) PROFILER("Spectrogram", level=2) # ===================================================================== # HYPNOGRAM # ===================================================================== self._hypCanvas = AxisCanvas(axis=self._ax, name='Hypnogram', fcn=[self.on_mouse_wheel], use_pad=True) self._HypW, self._HypLayout = self._create_compatible_w("HypW", "HypL") self._HypLayout.addWidget(self._hypCanvas.canvas.native) self._chanGrid.addWidget(self._HypW, len(self) + 2, 1, 1, 1) # Add label : self._hypLabel = QtWidgets.QWidget() layout = QtWidgets.QVBoxLayout(self._hypLabel) layout.setContentsMargins(0, 0, 0, 0) self._hypYLabels = [] for k in [''] + self._href + ['']: label = QtWidgets.QLabel() label.setText(self._addspace + k) label.setFont(self._font) layout.addWidget(label) self._hypYLabels.append(label) self._chanGrid.addWidget(self._hypLabel, len(self) + 2, 0, 1, 1) PROFILER("Hypnogram", level=2) # Connect : self._PanHypnoReset.clicked.connect(self._fcn_hypno_clean) self._PanHypnoLw.valueChanged.connect(self._fcn_set_hypno_lw) self._PanHypnoColor.clicked.connect(self._fcn_set_hypno_color) # ===================================================================== # TOPOPLOT # ===================================================================== # Main canvas for the spectrogram : self._topoCanvas = AxisCanvas(axis=False, name='Topoplot') self._topoLayout.addWidget(self._topoCanvas.canvas.native) self._topoW.setVisible(False) self._PanTopoCmin.setValue(-.5) self._PanTopoCmax.setValue(.5) # Connect : self._PanTopoCmap.addItems(self._cmap_lst) self._PanTopoCmap.setCurrentIndex(self._cmap_lst.index('Spectral')) self._PanTopoCmin.setKeyboardTracking(False) self._PanTopoCmin.valueChanged.connect(self._fcn_topo_settings) self._PanTopoCmax.setKeyboardTracking(False) self._PanTopoRev.clicked.connect(self._fcn_topo_settings) self._PanTopoCmax.valueChanged.connect(self._fcn_topo_settings) self._PanTopoCmap.currentIndexChanged.connect(self._fcn_topo_settings) self._PanTopoDisp.currentIndexChanged.connect(self._fcn_topo_settings) self._PanTopoFmin.valueChanged.connect(self._fcn_topo_settings) self._PanTopoFmax.valueChanged.connect(self._fcn_topo_settings) self._PanTopoAutoClim.clicked.connect(self._fcn_topo_settings) self._PanTopoApply.clicked.connect(self._fcn_topo_apply) PROFILER("Topoplot", level=2) # ===================================================================== # TIME AXIS # ===================================================================== # Create a unique time axis : self._TimeAxis = TimeAxis(axis=self._ax, name='TimeAxis', indic_color=self._indicol, fcn=[self.on_mouse_wheel]) self._TimeAxisW, self._TimeLayout = self._create_compatible_w( "TimeW", "TimeL") self._TimeLayout.addWidget(self._TimeAxis.canvas.native) self._TimeAxisW.setMaximumHeight(400) self._TimeAxisW.setMinimumHeight(50) self._chanGrid.addWidget(self._TimeAxisW, len(self) + 3, 1, 1, 1) # Add label : self._timeLabel = QtWidgets.QLabel(self.centralwidget) self._timeLabel.setText(self._addspace + 'Time') self._timeLabel.setFont(self._font) self._chanGrid.addWidget(self._timeLabel, len(self) + 3, 0, 1, 1) PROFILER("Time axis", level=2)
def __init__(self, bgcolor='black', verbose=None, **kwargs): """Init.""" # ====================== PyQt creation ====================== _PyQtModule.__init__(self, verbose=verbose, to_describe='view.wc', icon='brain_icon.svg') self._userobj = {} self._gl_scale = 100. # fix appearance for small meshes self._camera = viscam.TurntableCamera(name='MainEngramCamera') # ====================== Canvas creation ====================== UiInit.__init__(self, bgcolor) # GUI creation + canvas PROFILER("Canvas creation") # ====================== App creation ====================== PROFILER("Visual elements", as_type='title') Visuals.__init__(self, self.view.wc, **kwargs) # ====================== Metadata Storage ====================== if 'metadata' in kwargs.keys(): self.metadata = kwargs['metadata'] else: self.metadata = {} # ====================== Rotation Kinetics ====================== if 'rotation' in kwargs.keys(): self.rotation = kwargs['rotation'] else: self.rotation = 0 # ====================== Carousel Options ====================== self.ease_xyz = False # Between carousel options self.ignore_streams = True if 'carousel_metadata' in kwargs.keys(): self.carousel_metadata = kwargs['carousel_metadata'] else: self.carousel_metadata = {} # Carousel Display Method if 'carousel_display_method' in kwargs.keys(): self._carousel_display_method = kwargs['carousel_display_method'] else: self._carousel_display_method = 'text' # Carousel Options if 'hierarchy_lookup' in self.carousel_metadata: options = np.asarray(self.carousel_metadata['hierarchy_lookup']) self._carousel_options_inds = [np.asarray([0])] for dims in (range(len(options))): _combs = itertools.combinations(range(len(options)), dims + 1) _combs = list(_combs) for ll, comb in enumerate(_combs): comb = list(comb) if len(comb) > 1: if ll == 0: combs = [np.array(list(comb)) + 1] else: combs.append(np.array(list(comb)) + 1) else: if ll == 0: combs = [np.array([comb[0] + 1])] else: combs.append(np.array([list(comb)[0] + 1])) self._carousel_options_inds.append(combs) self._carousel_options_inds[0] = [self._carousel_options_inds[0]] options = list(options) new_options = [np.asarray(['None'])] for ii in np.arange(len(options)) + 1: new_options.append(options[ii - 1]) self._carousel_options = np.asarray(new_options) else: self._carousel_options_inds = [np.asarray([])] self._carousel_options = np.asarray(['None']) # Carousel Choice if 'carousel_choice' in kwargs.keys(): self._carousel_choice = kwargs['carousel_choice'] self._prev_carousel_choice = kwargs['carousel_choice'] else: self._carousel_choice = [0, 0] self._prev_carousel_choice = [0, 0] # Display Method self.update_carousel() # Toggle Options self._userdistance = [0] self._uservelocity = 0 # ====================== Control Device ====================== if 'control_method' in kwargs.keys(): self.control_method = kwargs['control_method'] else: self.control_method = 'keyboard' if self.control_method is 'IR_Distance': self.ser = serial.Serial('/dev/cu.usbmodem144101') self.use_distance = True else: self.ser = None self.prev_rotation = 0 def arduino_control(method='none'): if self.ser is not None: # Check Arduino inputs try: b = self.ser.readline() # read a byte string string_n = b.decode() # decode byte string into Unicode message = string_n.rstrip() # remove \n and \r messages = message.split('|') distance = messages[0] command = messages[1] except: distance = 500 command = 'NONE' if method == 'IR_Distance': if self.use_distance: THRESHOLD = 20 # cm HEIGHT = 0 flt = float(distance) self._userdistance = np.append( self._userdistance, flt) # convert string to float # Distance Selections if flt < HEIGHT + THRESHOLD: self._carousel_choice[0] = 0 if flt >= HEIGHT + (THRESHOLD) and flt < HEIGHT + ( 2 * THRESHOLD): self._carousel_choice[0] = 1 if flt >= HEIGHT + (2 * THRESHOLD): self._carousel_choice[0] = 3 # Remote Option if command != 'NONE': print(command) if command == 'POWER': sys.exit() if command == 'ST/REPT' and not self.use_distance: if self._carousel_choice[0] < ( len(self._carousel_options_inds) - 1): if self._carousel_choice[0] == 1: self._carousel_choice[0] = 3 else: self._carousel_choice[0] += 1 else: self._carousel_choice[0] = 0 self._carousel_choice[1] = 0 if command == 'EQ': if self.use_distance: self.use_distance = False else: self.use_distance = True if command == 'FUNC/STOP': if self._carousel_choice[1] < ( len(self._carousel_options_inds[ self._carousel_choice[0]]) - 1): self._carousel_choice[1] += 1 else: self._carousel_choice[1] = 0 if command == 'VOL+' or command == 'VOL-': if command == 'VOL+': self.view.wc.camera.distance -= 5000 else: self.view.wc.camera.distance += 5000 if command == 'UP': self.rotation += .25 elif command == 'DOWN': self.rotation -= .25 elif command == 'FAST BACK': if np.sign(self.timescaling) == 1: self.timescaling = -0.1 else: self.timescaling -= 0.10 elif command == 'FAST FORWARD': if np.sign(self.timescaling) == -1: self.timescaling = 0.1 else: self.timescaling += 0.10 elif command == 'PAUSE': if self.timescaling == 0: print('PLAY') self.timescaling = self.default_timescaling self.rotation = self.prev_rotation self.displayed_time = self.time_cache self.time_cache = None else: print('PAUSE') self.prev_rotation = self.rotation self.time_cache = self.displayed_time self.rotation = 0 self.timescaling = 0 self.paused = True if self.paused == True: if command == 'FAST FORWARD': self.time_cache += .02 elif command == 'FAST BACK': self.time_cache -= .02 # Remote Numbers if command == '0': self.view.wc.camera.azimuth = 0 self.view.wc.camera.elevation = 90 elif command == '1': self.view.wc.camera.azimuth = 0 self.view.wc.camera.elevation = -90 elif command == '2': self.view.wc.camera.azimuth = 90 self.view.wc.camera.elevation = 0 elif command == '3': self.view.wc.camera.azimuth = -90 self.view.wc.camera.elevation = 0 elif command == '4': self.view.wc.camera.azimuth = 0 self.view.wc.camera.elevation = 0 elif command == '5': self.view.wc.camera.azimuth = 180 self.view.wc.camera.elevation = 0 elif command == '6': self.view.wc.camera.azimuth = 45 self.view.wc.camera.elevation = 30 elif command == '7': self.view.wc.camera.azimuth = 45 self.view.wc.camera.elevation = -30 elif command == '8': self.view.wc.camera.azimuth = -45 self.view.wc.camera.elevation = 30 elif command == '9': self.view.wc.camera.azimuth = -45 self.view.wc.camera.elevation = -30 # ====================== Timer Creation ====================== self.loop_shift = 0 self.start_offset = 0 self.default_timescaling = 1 / 4 self.timescaling = self.default_timescaling self.time_cache = None self.displayed_time = 0 self.paused = False def on_timer(*args, **kwargs): # Change Source Radii and Connectivity Values if self.time_cache is None: time_inc = (args[0].dt * self.timescaling) self.displayed_time = self.loop_shift + ( self.displayed_time + time_inc) % ( (np.shape(self.sources[0].data)[1] / self.metadata['fs']) - self.loop_shift) else: self.displayed_time = self.loop_shift + (self.time_cache) % ( (np.shape(self.sources[0].data)[1] / self.metadata['fs']) - self.loop_shift) timepoint = int(self.displayed_time * self.metadata['fs']) for source in self.sources: source._update_radius(timepoint=timepoint) for connect in self.connect: connect._update_time(timepoint=timepoint) arduino_control(self.control_method) self.update_target_positions() self.update_carousel() self.update_visibility() self._prev_carousel_choice = self._carousel_choice if len(self._userdistance) > 2: self._userdistance = [-1] # Update Time Display t_str = str(round(self.displayed_time, 3)) + ' s' if not hasattr(self, '_time'): self._time = Text(t_str, parent=self.view.canvas.scene, color='white') else: self._time.text = t_str self._time.anchors = ('right', 'bottom') self._time.font_size = self.view.canvas.size[1] // 200 self._time.pos = (49) * self.view.canvas.size[0] // 50, ( 19) * self.view.canvas.size[1] // 20 self._time.update() # Ease to New Positions if Triggered if self.ease_xyz: self.ease_xyz = False for source in self.sources: out = source._ease_to_target_position() if out: self.ease_xyz = True for connect in self.connect: out = connect._ease_to_target_position() if out: self.ease_xyz = True # if hasattr(self.view.wc, 'camera'): # diff_az = self.target_azimuth - self.view.wc.camera.azimuth # diff_el = self.target_elevation - self.view.wc.camera.elevation # # Ease scene rotation # if (diff_az != 0.) | (diff_el != 0.): # # Flip target and current (since I cannot find a way to update the shortcuts directly) # if self.first_ease: # temp_ = self.target_elevation # self.target_elevation = self.view.wc.camera.elevation # self.view.wc.camera.elevation = temp_ # temp_ = self.target_azimuth # self.target_azimuth = self.view.wc.camera.azimuth # self.view.wc.camera.azimuth = temp_ # self.first_ease = False # if (abs(diff_az) > 0.001) | (abs(diff_el) > 0.001): # self.view.wc.camera.azimuth += .1*(diff_az) # self.view.wc.camera.elevation += .1*(diff_el) # print('updating rotation') # if self.first_ease: # self.first_ease = False # else: # self.view.wc.camera.azimuth = self.target_azimuth # self.view.wc.camera.elevation = self.target_elevation # self.first_ease = True #Iterate scene rotation # else: self.view.wc.camera.azimuth += self.rotation self.view.wc.canvas.update() kw = dict(connect=on_timer, app=CONFIG['VISPY_APP'], interval='auto', iterations=-1) self._app_timer = app.Timer(**kw) self._app_timer.start() # ====================== Ui interactions ====================== UiElements.__init__(self) # GUI interactions PROFILER("Ui interactions") self._shpopup.set_shortcuts(self.sh) # shortcuts dict # ====================== Cameras ====================== # Main camera : self.view.wc.camera = self._camera self._vbNode.parent = self.view.wc.scene self.atlas.camera = self._camera self.roi.camera = self._camera self.atlas._csize = self.view.canvas.size self.atlas.rotate('top') self.atlas.camera.set_default_state() PROFILER("Cameras creation") # Set easing self.target_azimuth = self.view.wc.camera.azimuth self.target_elevation = self.view.wc.camera.elevation self.first_ease = True # ====================== Colorbar ====================== camera = viscam.PanZoomCamera(rect=(-.2, -2.5, 1, 5)) EngramCbar.__init__(self, camera) PROFILER("Colorbar and panzoom creation") self.background_color(bgcolor) # ====================== Shortcuts ====================== EngramShortcuts.__init__(self, self.cbqt.cbviz._canvas) PROFILER("Set engram shortcuts") self._fcn_on_load() PROFILER("Functions on load")
def __init__(self): """Init.""" # =================== VARIABLES =================== sf, data, time = self._sf, self._data, self._time channels, hypno, cameras = self._channels, self._hypno, self._allCams # =================== CHANNELS =================== self._chan = ChannelPlot(channels, time, camera=cameras[0], color=self._chancolor, width=self._lw, color_detection=self._indicol, parent=self._chanCanvas, fcn=self._fcn_slider_move) PROFILER('Channels', level=1) # =================== SPECTROGRAM =================== # Create a spectrogram object : self._spec = Spectrogram(camera=cameras[1], fcn=self._fcn_spec_set_data, parent=self._specCanvas.wc.scene) self._spec.set_data(sf, data[0, ...], time, cmap=self._defcmap) PROFILER('Spectrogram', level=1) # Create a visual indicator for spectrogram : self._specInd = Indicator(name='spectro_indic', visible=True, alpha=.3, parent=self._specCanvas.wc.scene) self._specInd.set_data(xlim=(0, 30), ylim=(0, 20)) PROFILER('Spectrogram indicator', level=1) # =================== HYPNOGRAM =================== # Create a hypnogram object : self._hyp = Hypnogram(time, camera=cameras[2], color=self._hypcolor, width=self._lwhyp, hconv=self._hconv, parent=self._hypCanvas.wc.scene) self._hyp.set_data(sf, hypno, time) PROFILER('Hypnogram', level=1) # Create a visual indicator for hypnogram : self._hypInd = Indicator(name='hypno_indic', visible=True, alpha=.3, parent=self._hypCanvas.wc.scene) self._hypInd.set_data(xlim=(0., 30.), ylim=(-6., 2.)) PROFILER('Hypnogram indicator', level=1) # =================== DETECTIONS =================== self._detect = Detection(self._channels.copy(), self._time, self._defspin, self._defrem, self._defkc, self._defsw, self._defpeaks, self._defmt, self._spinsym, self._remsym, self._kcsym, self._swsym, self._peaksym, self._mtsym, self._chan.node, self._hypCanvas.wc.scene) PROFILER('Detections', level=1) # =================== TOPOPLOT =================== self._topo = TopoSleep(channels=self._channels, margin=.2, parent=self._topoCanvas.wc.scene) # Set camera properties : cameras[3].rect = self._topo.rect cameras[3].aspect = 1. self._pan_pick.model().item(3).setEnabled(any(self._topo._keeponly)) PROFILER('Topoplot', level=1) # =================== SHORTCUTS =================== vbcanvas = self._chanCanvas + [self._specCanvas, self._hypCanvas] for k in vbcanvas: CanvasShortcuts.__init__(self, k.canvas) self._shpopup.set_shortcuts(self.sh) PROFILER('Shortcuts', level=1)
def __init__(self, canvas, **kwargs): """Init.""" # Create a root node : self._vbNode = scene.Node(name='Engram') self._vbNode.transform = vist.STTransform(scale=[self._gl_scale] * 3) logger.debug("Engram rescaled " + str([self._gl_scale] * 3)) PROFILER("Root node", level=1) # ========================= SOURCES ========================= self.sources = CombineSources(kwargs.get('source_obj', None)) if self.sources.name is None: self._obj_type_lst.model().item(4).setEnabled(False) # Disable menu : self.menuDispSources.setChecked(False) self.menuTransform.setEnabled(False) self.sources.parent = self._vbNode PROFILER("Sources object", level=1) # ========================= CONNECTIVITY ========================= self.connect = CombineConnect(kwargs.get('connect_obj', None)) if self.connect.name is None: self._obj_type_lst.model().item(5).setEnabled(False) self.menuDispConnect.setEnabled(False) self.connect.parent = self._vbNode PROFILER("Connect object", level=1) # ========================= TIME-SERIES ========================= self.tseries = CombineTimeSeries(kwargs.get('time_series_obj', None)) if self.tseries.name is None: self._obj_type_lst.model().item(6).setEnabled(False) self.tseries.parent = self._vbNode PROFILER("Time-series object", level=1) # ========================= PICTURES ========================= self.pic = CombinePictures(kwargs.get('picture_obj', None)) if self.pic.name is None: self._obj_type_lst.model().item(7).setEnabled(False) self.pic.parent = self._vbNode PROFILER("Pictures object", level=1) # ========================= VECTORS ========================= self.vectors = CombineVectors(kwargs.get('vector_obj', None)) if self.vectors.name is None: self._obj_type_lst.model().item(8).setEnabled(False) self.vectors.parent = self._vbNode PROFILER("Vectors object", level=1) # ========================= VOLUME ========================= # ----------------- Volume ----------------- if kwargs.get('vol_obj', None) is None: self.volume = VolumeObj('brodmann') self.volume.visible_obj = False else: self.volume = kwargs.get('vol_obj') if self.volume.name not in self.volume.list(): self.volume.save(tmpfile=True) self.volume.parent = self._vbNode PROFILER("Volume object", level=1) # ----------------- ROI ----------------- if kwargs.get('roi_obj', None) is None: self.roi = RoiObj('brodmann') self.roi.visible_obj = False else: self.roi = kwargs.get('roi_obj') if self.roi.name not in self.roi.list(): self.roi.save(tmpfile=True) self.roi.parent = self._vbNode PROFILER("ROI object", level=1) # ----------------- Cross-sections ----------------- if kwargs.get('cross_sec_obj', None) is None: self.cross_sec = CrossSecObj('brodmann') else: self.cross_sec = kwargs.get('cross_sec_obj') if self.cross_sec.name not in self.cross_sec.list(): self.cross_sec.save(tmpfile=True) self.cross_sec.visible_obj = False self.cross_sec.text_size = 2. self.cross_sec.parent = self._csView.wc.scene self._csView.camera = self.cross_sec._get_camera() self.cross_sec.set_shortcuts_to_canvas(self._csView) PROFILER("Cross-sections object", level=1) # ========================= ENGRAM ========================= if kwargs.get('engram_obj', None) is None: self.atlas = BrainObj('B1') else: self.atlas = kwargs['engram_obj'] if self.atlas.name not in self.atlas.list(): self.atlas.save(tmpfile=True) self.atlas.scale = self._gl_scale self.atlas.parent = self._vbNode PROFILER("Engram object", level=1)
def __init__(self, data, channels, sf, hypno, href, preload, use_mne, downsample, kwargs_mne, annotations): """Init.""" # ========================== LOAD DATA ========================== # Dialog window if data is None : if data is None: data = dialog_load( self, "Open dataset", '', "Any EEG files (*.vhdr *.edf *.gdf *.bdf *.eeg " "*.egi *.mff *.cnt *.trc *.set *.rec);;" "BrainVision (*.vhdr);;EDF (*.edf);;" "GDF (*.gdf);;BDF (*.bdf);;Elan (*.eeg);;" "EGI (*.egi);;MFF (*.mff);;CNT (*.cnt);;" "Micromed (*.trc);;EEGLab (*.set);;REC (*.rec)") upath = os.path.split(data)[0] else: upath = '' if isinstance(data, str): # file is defined # ---------- USE SLEEP or MNE ---------- # Find file extension : file, ext = get_file_ext(data) # Force to use MNE if preload is False : use_mne = True if not preload else use_mne # Get if the file has to be loaded using Sleep or MNE python : sleep_ext = ['.eeg', '.vhdr', '.edf', '.trc', '.rec'] use_mne = True if ext not in sleep_ext else use_mne if use_mne: is_mne_installed(raise_error=True) # ---------- LOAD THE FILE ---------- if use_mne: # Load using MNE functions logger.debug("Load file using MNE-python") kwargs_mne['preload'] = preload args = mne_switch(file, ext, downsample, **kwargs_mne) else: # Load using Sleep functions logger.debug("Load file using Sleep") args = sleep_switch(file, ext, downsample) # Get output arguments : (sf, downsample, dsf, data, channels, n, offset, annot) = args info = ("Data successfully loaded (%s):" "\n- Sampling-frequency : %.2fHz" "\n- Number of time points (before down-sampling): %i" "\n- Down-sampling frequency : %.2fHz" "\n- Number of time points (after down-sampling): %i" "\n- Number of channels : %i") n_channels, n_pts_after = data.shape logger.info( info % (file + ext, sf, n, downsample, n_pts_after, n_channels)) PROFILER("Data file loaded", level=1) elif isinstance(data, np.ndarray): # array of data is defined if not isinstance(sf, (int, float)): raise ValueError("When passing raw data, the sampling " "frequency parameter, sf, must either be an " "integer or a float.") file = annot = None offset = datetime.time(0, 0, 0) dsf, downsample = get_dsf(downsample, sf) n = data.shape[1] data = data[:, ::dsf] else: raise IOError("The data should either be a string which refer to " "the path of a file or an array of raw data of shape" " (n_electrodes, n_time_points).") # Keep variables : self._file = file self._annot_file = np.c_[merge_annotations(annotations, annot)] self._N = n self._dsf = dsf self._sfori = float(sf) self._toffset = offset.hour * 3600. + offset.minute * 60. + \ offset.second time = np.arange(n)[::dsf] / sf self._sf = float(downsample) if downsample is not None else float(sf) # ========================== LOAD HYPNOGRAM ========================== # Dialog window for hypnogram : if hypno is False: hypno = None elif hypno is None: hypno = dialog_load( self, "Open hypnogram", upath, "Text file (*.txt);;Elan (*.hyp);;" "CSV file (*.csv);;EDF+ file(*.edf);" ";All files (*.*)") hypno = None if hypno == '' else hypno if isinstance(hypno, np.ndarray): # array_like if len(hypno) == n: hypno = hypno[::dsf] else: raise ValueError("Then length of the hypnogram must be the " "same as raw data") if isinstance(hypno, str): # (*.hyp / *.txt / *.csv) hypno, _ = read_hypno(hypno, time=time, datafile=file) # Oversample then downsample : hypno = oversample_hypno(hypno, self._N)[::dsf] PROFILER("Hypnogram file loaded", level=1) # ========================== CHECKING ========================== # ---------- DATA ---------- # Check data shape : if data.ndim is not 2: raise ValueError("The data must be a 2D array") nchan, npts = data.shape # ---------- CHANNELS ---------- if (channels is None) or (len(channels) != nchan): warn("The number of channels must be " + str(nchan) + ". Default " "channel names will be used instead.") channels = ['chan' + str(k) for k in range(nchan)] # Clean channel names : patterns = ['eeg', 'EEG', 'ref'] chanc = [] for c in channels: # Remove informations after . : c = c.split('.')[0] c = c.split('-')[0] # Exclude patterns : for i in patterns: c = c.replace(i, '') # Remove space : c = c.replace(' ', '') c = c.strip() chanc.append(c) # ---------- STAGE ORDER ---------- # href checking : absref = ['art', 'wake', 'n1', 'n2', 'n3', 'rem'] absint = [-1, 0, 1, 2, 3, 4] if href is None: href = absref elif (href is not None) and isinstance(href, list): # Force lower case : href = [k.lower() for k in href] # Check that all stage are present : for k in absref: if k not in href: raise ValueError(k + " not found in href.") # Force capitalize : href = [k.capitalize() for k in href] href[href.index('Rem')] = 'REM' else: raise ValueError("The href parameter must be a list of string and" " must contain 'art', 'wake', 'n1', 'n2', 'n3' " "and 'rem'") # Conversion variable : absref = ['Art', 'Wake', 'N1', 'N2', 'N3', 'REM'] conv = {absint[absref.index(k)]: absint[i] for i, k in enumerate(href)} # ---------- HYPNOGRAM ---------- if hypno is None: hypno = np.zeros((npts, ), dtype=np.float32) else: n = len(hypno) # Check hypno values : if (hypno.min() < -1.) or (hypno.max() > 4) or (n != npts): warn("\nHypnogram values must be comprised between -1 and 4 " "(see Iber et al. 2007). Use:\n-1 -> Art (optional)\n 0 " "-> Wake\n 1 -> N1\n 2 -> N2\n 3 -> N4\n 4 -> REM\nEmpty " "hypnogram will be used instead") hypno = np.zeros((npts, ), dtype=np.float32) # ---------- SCALING ---------- # Assume that the inter-quartile amplitude of EEG data is ~50 uV iqr_chan = iqr(data[:, :int(data.shape[1] / 4)], axis=-1) bad_iqr = iqr_chan < 1. if np.any(bad_iqr): mult_fact = np.zeros_like(iqr_chan) iqr_chan[iqr_chan == 0.] = 1. mult_fact[bad_iqr] = np.floor(np.log10(50. / iqr_chan[bad_iqr])) data *= 10.**mult_fact[..., np.newaxis] warn("Wrong channel data amplitude. ") # ---------- CONVERSION ----------= # Convert data and hypno to be contiguous and float 32 (for vispy): self._data = vispy_array(data) self._hypno = vispy_array(hypno) self._time = vispy_array(time) self._channels = chanc self._href = href self._hconv = conv PROFILER("Check data", level=1)
def __init__(self, data=None, hypno=None, config_file=None, annotations=None, channels=None, sf=None, downsample=100., axis=True, href=['art', 'wake', 'rem', 'n1', 'n2', 'n3'], preload=True, use_mne=False, kwargs_mne={}, verbose=None): """Init.""" _PyQtModule.__init__(self, verbose=verbose, icon='sleep_icon.svg') # ====================== APP CREATION ====================== UiInit.__init__(self) # Set default GUI state : self._set_default_state() # Mouse control : MouseEventControl.__init__(self) # ====================== LOAD FILE ====================== PROFILER("Import file", as_type='title') ReadSleepData.__init__(self, data, channels, sf, hypno, href, preload, use_mne, downsample, kwargs_mne, annotations) # ====================== VARIABLES ====================== # Check all data : self._config_file = config_file self._annot_mark = np.array([]) self._hconvinv = {v: k for k, v in self._hconv.items()} self._ax = axis # ---------- Default line width ---------- self._lw = 1. self._lwhyp = 2 self._defwin = 30. self._defstd = 5. # ---------- Default colors ---------- self._chancolor = '#292824' # self._hypcolor = '#292824' # Hypnogram color : self._hypcolor = { -1: '#8bbf56', 0: '#56bf8b', 1: '#aabcce', 2: '#405c79', 3: '#0b1c2c', 4: '#bf5656' } # Convert color : if self._hconv != self._hconvinv: hypc = self._hypcolor.copy() for k in self._hconv.keys(): self._hypcolor[k] = hypc[self._hconvinv[k]] self._indicol = '#e74c3c' # Default spectrogram colormap : self._defcmap = 'viridis' # Spindles / REM / Peaks colors : self._defspin = color2vb('#d73737') self._defsw = color2vb('#56bf8b') self._defkc = color2vb('#b45a3c') self._defrem = color2vb('#6684e1') self._defmt = color2vb('#FE8625') self._defpeaks = '#b854d4' # ---------- Symbol ---------- self._spinsym = 'x' self._swsym = 'o' self._kcsym = 'diamond' self._remsym = 'triangle_down' self._mtsym = 'star' self._peaksym = 'disc' # ---------- Custom detections ---------- self._custom_detections = {} # Get some data info (min / max / std / mean) self._get_data_info() PROFILER("Data info") # ====================== USER & GUI INTERACTION ====================== # User <-> GUI : PROFILER("Initialize GUI interactions", as_type='title') UiElements.__init__(self) # ====================== CAMERAS ====================== self._cam_creation() # ====================== OBJECTS CREATION ====================== PROFILER("Initialize visual elements", as_type='title') Visuals.__init__(self) # ====================== FUNCTIONS ON LOAD ====================== self._fcns_on_creation() PROFILER("Functions on creation")
def __init__(self, bgcolor='black', verbose=None, **kwargs): """Init.""" # ====================== PyQt creation ====================== _PyQtModule.__init__(self, verbose=verbose, to_describe='view.wc', icon='brain_icon.svg') self._userobj = {} self._gl_scale = 100. # fix appearance for small meshes self._camera = viscam.TurntableCamera(name='MainEngramCamera') # ====================== Canvas creation ====================== UiInit.__init__(self, bgcolor) # GUI creation + canvas PROFILER("Canvas creation") # ====================== App creation ====================== PROFILER("Visual elements", as_type='title') Visuals.__init__(self, self.view.wc, **kwargs) # ====================== Metadata Storage ====================== if 'metadata' in kwargs.keys(): self.metadata = kwargs['metadata'] else: self.metadata = {} # ====================== Rotation Kinetics ====================== if 'rotation' in kwargs.keys(): self.rotation = kwargs['rotation'] else: self.rotation = 0 # ====================== Carousel Options ====================== if 'carousel_metadata' in kwargs.keys(): self.carousel_metadata = kwargs['carousel_metadata'] else: self.carousel_metadata = {} # Carousel Display Method if 'carousel_display_method' in kwargs.keys(): self._carousel_display_method = kwargs['carousel_display_method'] else: self._carousel_display_method = 'text' # Carousel Options if 'hierarchy_lookup' in self.carousel_metadata: options = np.asarray(self.carousel_metadata['hierarchy_lookup']) self._carousel_options_inds = [np.asarray([0])] for dims in (range(len(options))): _combs = itertools.combinations(range(len(options)), dims + 1) _combs = list(_combs) for ll, comb in enumerate(_combs): comb = list(comb) if len(comb) > 1: if ll == 0: combs = [np.array(list(comb)) + 1] else: combs.append(np.array(list(comb)) + 1) else: if ll == 0: combs = [np.array([comb[0] + 1])] else: combs.append(np.array([list(comb)[0] + 1])) self._carousel_options_inds.append(combs) self._carousel_options_inds[0] = [self._carousel_options_inds[0]] options = list(options) new_options = [np.asarray(['None'])] for ii in np.arange(len(options)) + 1: new_options.append(options[ii - 1]) self._carousel_options = np.asarray(new_options) else: self._carousel_options_inds = [np.asarray([])] self._carousel_options = np.asarray(['None']) # Carousel Choice if 'carousel_choice' in kwargs.keys(): self._carousel_choice = kwargs['carousel_choice'] self._prev_carousel_choice = kwargs['carousel_choice'] else: self._carousel_choice = [0, 0] self._prev_carousel_choice = [0, 0] # Display Method self.update_carousel() # ====================== Timer Creation ====================== def on_timer(*args, **kwargs): if hasattr(self.view.wc, 'camera'): self.view.wc.camera.azimuth += self.rotation self.view.wc.canvas.update() TIMESCALING = 1 / 1 SHIFT = 0 t = SHIFT + (SHIFT + (args[0].elapsed * TIMESCALING)) % ( (np.shape(self.sources[0].data)[1] / self.metadata['fs']) - SHIFT) timepoint = int(t * self.metadata['fs']) for source in self.sources: source._update_radius(timepoint=timepoint) for connect in self.connect: connect._update_time(timepoint=timepoint) t_str = str(round(t, 3)) + ' s' if not hasattr(self, '_time'): self._time = Text(t_str, parent=self.view.canvas.scene, color='white') else: self._time.text = t_str self._time.anchors = ('right', 'bottom') self._time.font_size = self.view.canvas.size[1] // 200 self._time.pos = (49) * self.view.canvas.size[0] // 50, ( 19) * self.view.canvas.size[1] // 20 self._time.update() kw = dict(connect=on_timer, app=CONFIG['VISPY_APP'], interval='auto', iterations=-1) self._app_timer = app.Timer(**kw) self._app_timer.start() # ====================== Ui interactions ====================== UiElements.__init__(self) # GUI interactions PROFILER("Ui interactions") self._shpopup.set_shortcuts(self.sh) # shortcuts dict # ====================== Cameras ====================== # Main camera : self.view.wc.camera = self._camera self._vbNode.parent = self.view.wc.scene self.atlas.camera = self._camera self.roi.camera = self._camera self.atlas._csize = self.view.canvas.size self.atlas.rotate('top') self.atlas.camera.set_default_state() PROFILER("Cameras creation") # ====================== Colorbar ====================== camera = viscam.PanZoomCamera(rect=(-.2, -2.5, 1, 5)) EngramCbar.__init__(self, camera) PROFILER("Colorbar and panzoom creation") self.background_color(bgcolor) # ====================== Shortcuts ====================== EngramShortcuts.__init__(self, self.cbqt.cbviz._canvas) PROFILER("Set engram shortcuts") self._fcn_on_load() PROFILER("Functions on load")