def _build_line(self): """Build the connectivity line.""" pos, edges = self._pos, self._edges # Color either edges or nodes : # logger.info(" %s coloring method for connectivity" % self._color_by) # Switch between coloring method : if self._color_by in ['strength', 'count']: # Build line position nnz_x, nnz_y = np.where(~edges.mask) indices = np.c_[nnz_x, nnz_y].flatten() line_pos = pos[indices, :] if self._color_by == 'strength': nnz_values = edges.compressed() values = np.c_[nnz_values, nnz_values].flatten() elif self._color_by == 'count': node_count = Counter(np.ravel([nnz_x, nnz_y])) values = np.array([node_count[k] for k in indices]) elif self._color_by == 'causal': idx = np.array(np.where(~edges.mask)).T # If the array is not symetric, the line needs to be drawn between # points. If it's symetric, line should stop a the middle point. # Here, we get the maske value of the symetric and use it to # ponderate middle point calculation : pond = (~np.array(edges.mask))[idx[:, 1], idx[:, 0]] pond = pond.astype(float).reshape(-1, 1) div = pond + 1. # Build line pos : line_pos = np.zeros((2 * idx.shape[0], 3), dtype=float) line_pos[0::2, :] = pos[idx[:, 0], :] line_pos[1::2, :] = (pos[idx[:, 1]] + pond * pos[idx[:, 0]]) / div # Build values : values = np.full((line_pos.shape[0], ), edges.min(), dtype=float) values[1::2] = edges.compressed() #logger.info(" %i connectivity links displayed" % line_pos.shape[0]) self._minmax = (values.min(), values.max()) if self._clim is None: self._clim = self._minmax # Get the color according to values : if isinstance(self._custom_colors, dict): # custom color if None in list(self._custom_colors.keys()): # {None : 'color'} color = color2vb(self._custom_colors[None], length=len(values)) else: # black by default color = np.zeros((len(values), 4), dtype=np.float32) for val, col in self._custom_colors.items(): color[values == val, :] = color2vb(col) else: color = array2colormap(values, **self.to_kwargs()) color[:, -1] = self._alpha # Dynamic color : if self._dynamic is not None: color[:, 3] = vector_to_opacity(values, clim=self._clim, dyn=self._dynamic, order=self._dyn_order, orientation=self._dyn_orient) # Send data to the connectivity object : self._connect.set_data(pos=line_pos, color=color)
def background_color(self, color=(.1, .1, .1)): """Set the background color of the main canvas and the colorbar. The main canvas is defined as the canvas where all objects are displayed. The colorbar has it own canvas and the background set will be the same as the one of the main canvas. Parameters ---------- color : tuple/string | (.1, .1, .1) The color to use for the background color of the main canvas. The color can either be a tuple of integers (R, G, B), a matplotlib color (string) or a hexadecimal color (string). Examples -------- >>> # Define a Engram instance : >>> vb = Engram() >>> # Set the background color (using a RGB tuple) : >>> vb.background_color(color=(1., 1., 1.)) >>> # Set the background color (using matplotlib format) : >>> vb.background_color(color='white') >>> # Set the background color (using hexadecimal format) : >>> vb.background_color(color='#ffffff') >>> # Show the GUI : >>> vb.show() """ bckcolor = color2vb(color).ravel()[0:-1] self.view.canvas.bgcolor = bckcolor self.cbqt.cbviz.bgcolor = bckcolor
def __init__(self, time, camera, color='#292824', width=2., parent=None, hconv=None): # Keep camera : self._camera = camera self._rect = (0., 0., 0., 0.) self.rect = (time.min(), -5., time.max() - time.min(), 7.) self.width = width self.n = len(time) self._hconv = hconv self._hconvinv = {v: k for k, v in self._hconv.items()} # Get color : self.color = {k: color2vb(color=i) for k, i in zip(color.keys(), color.values())} # Create a default line : pos = np.array([[0, 0], [0, 100]]) self.mesh = scene.visuals.Line(pos, name='hypnogram', method='gl', parent=parent, width=width) self.mesh._width = width self.mesh.set_gl_state('translucent') # Create a default marker (for edition): self.edit = Markers(parent=parent) # self.mesh.set_gl_state('translucent', depth_test=True) self.edit.set_gl_state('translucent') # Add grid : self.grid = scene.visuals.GridLines(color=(.7, .7, .7, 1.), scale=(30. * time[-1] / len(time), 1.), parent=parent) self.grid.set_gl_state('translucent')
def __init__(self, name='indicator', alpha=.3, visible=True, parent=None): # Create a vispy image object : image = color2vb('gray', alpha=alpha)[np.newaxis, ...] self.mesh = scene.visuals.Image(data=image, name=name, parent=parent) self.mesh.transform = vist.STTransform() self.mesh.visible = visible
def __init__(self, axis=True, x_label='', name='', bgcolor=(1., 1., 1.), indic_color='darkred', fcn=[]): """Init.""" # Create the main canvas : self.canvas = scene.SceneCanvas(keys=None, bgcolor=bgcolor, show=False) _ = [self.canvas.connect(k) for k in fcn] # noqa # Create a grid : grid = self.canvas.central_widget.add_grid(margin=0) grid.spacing = 0 # Add x-axis : self.xaxis = scene.AxisWidget(orientation='bottom', text_color='black') if axis: pad = grid.add_widget(row=0, col=0) pad.width_max = 50 _col = int(axis) grid.add_widget(self.xaxis, row=1, col=_col) # Main plot : self.wc = grid.add_view(row=0, col=_col, border_color='black') # Add a square indicator : image = color2vb(indic_color)[np.newaxis, ...] self.mesh = scene.visuals.Image(image, name='Time indicator') self.mesh.transform = vist.STTransform() self.mesh.parent = self.wc.scene # Add markers : pos = np.full((1, 3), -10, dtype=np.float32) self.markers = Markers(pos=pos, parent=self.wc.scene) self.markers.set_gl_state('translucent')
def _update_color(self): """Update marker's color.""" # Get marker's background color : if isinstance(self._color, str): # color='white' bg_color = color2vb(self._color, length=len(self)) elif isinstance(self._color, list): # color=['white', 'green'] assert len(self._color) == len(self) bg_color = np.squeeze(np.array([color2vb(k) for k in self._color])) elif isinstance(self._color, np.ndarray): # color = [[0, 0, 0], ...] csh = self._color.shape assert (csh[0] == len(self)) and (csh[1] >= 3) if self._color.shape[1] == 3: # RGB self._color = np.c_[self._color, np.full(len(self), self._alpha)] bg_color = self._color.copy() # Update masked marker's color : bg_color[self._mask, :] = self._mask_color self._sources._data['a_bg_color'] = bg_color self.update()
def _fcn_set_hypno_color(self): """Change the color of the hypnogram.""" if not(self._PanHypnoColor.isChecked()): color = {-1: '#292824', 0: '#292824', 1: '#292824', 2: '#292824', 3: '#292824', 4: '#292824'} else: color = self._hypcolor # Get color : zp = zip(color.keys(), color.values()) self._hyp.color = {k: color2vb(color=i) for k, i in zp} # Update hypnogram self._hyp.set_data(self._sf, self._hypno, self._time)
def __init__(self, name='scorwinindicator', alpha=.75, visible=True, parent=None, color='red', barwidth=.20): # width of the vertical bars self.barwidth = barwidth # Create two vispy image object for the start and end of window # "Start mesh" : first vertical bar image_start = color2vb(color, alpha=alpha)[np.newaxis, ...] self.mesh_start = scene.visuals.Image(data=image_start, name=name, parent=parent) self.mesh_start.transform = vist.STTransform() self.mesh_start.visible = visible # "End mesh" : second vertical bar image_end = color2vb(color, alpha=alpha)[np.newaxis, ...] self.mesh_end = scene.visuals.Image(data=image_end, name=name, parent=parent) self.mesh_end.transform = vist.STTransform() self.mesh_end.visible = visible
def _fcn_set_hypno_color(self): """Change the color of the hypnogram.""" if not (self._PanHypnoColor.isChecked()): color = { -1: '#292824', 0: '#292824', 1: '#292824', 2: '#292824', 3: '#292824', 4: '#292824' } else: color = self._hypcolor # Get color : zp = zip(color.keys(), color.values()) self._hyp.color = {k: color2vb(color=i) for k, i in zp} # Update hypnogram self._hyp.set_data(self._sf, self._hypno, self._time)
def _update_radius(self, timepoint=None): """Update marker's radius.""" logger.debug("Weird edge arround markers (source_obj.py)") if not hasattr(self, 'radius'): if np.unique(self._data).size == 1: self.radius = self._radius_min * np.ones((len(self, ))) else: self.radius = normalize(self._data.copy(), tomin=self._radius_min, tomax=self._radius_max) if timepoint: self._sources._data['a_size'] = self.radius[:, int( timepoint)] # fs/time if not hasattr(self, '_timer'): self._timer = visuals.Text(str(int(timepoint)), pos=[0, 100, 0], bold=True, name='Text', color=color2vb('white'), font_size=50, parent=None) #self._node) self._timer.text = str(int(timepoint)) self._timer.update() else: if len(self.radius.shape) == 2: self._sources._data['a_size'] = np.mean(self.radius, axis=1) else: self._sources._data['a_size'] = self.radius to_hide = self.hide # Marker size + egde width = 0 and text='' for hidden sources : self._sources._data['a_size'][to_hide] = 0. self._sources._data['a_edgewidth'][to_hide] = 0. if isinstance(self._mask_radius, (int, float)): self._sources._data['a_size'][self._mask] = self._mask_radius text = np.array(self._text.copy()) text[to_hide] = '' self._sources_text.text = text self.update()
def n3_color(self, value): """Set n3_color value.""" color = np.squeeze(color2vb(value)) self.shared_program.vert['u_n3_color'] = color self._n3_color = color
def set_data(self, data=None, axis=None, color=None, title=None, force_shape=None, plt_as='grid'): """Set data to the grid of signals. Parameters ---------- data : None Array of data. Could be 1-D, 2-D or 3-D. axis : int | None Time axis location. random : array_like/string/tuple | 'random' Use 'random' for random colors or a color name for uniform color. """ # ====================== CHECKING ====================== # Axis : axis = axis if isinstance(axis, int) else self._axis axis = len(self._sh) - 1 if axis == -1 else axis # Data : if isinstance(data, np.ndarray): # -------------- (n_rows, n_cols, n_time) -------------- if data.ndim == 1: # 1-D array data = data.reshape(1, 1, -1) g_size = (1, 1) elif data.ndim == 2: # 2-D array if axis == 0: # data need to be transposed data = np.swapaxes(data, 0, 1) axis = 1 g_size = (data.shape[0], 1) # (n_row, 1) data = data[np.newaxis, ...] elif data.ndim == 3: # 3-D array if axis != data.ndim - 1: # data need to be transposed data = np.swapaxes(data, axis, -1) axis = data.ndim - 1 g_size = (data.shape[0], data.shape[1]) # -------------- Signals index -------------- m = np.prod(list(data.shape)[0:-1]) sig_index = np.arange(m).reshape(*g_size) # -------------- Plot type -------------- if plt_as == 'row': force_shape = (1, g_size[0] * g_size[1]) elif plt_as == 'col': force_shape = (g_size[0] * g_size[1], 1) # -------------- Optimal 2-D -------------- self._data = data self._ori_shape = list(data.shape)[0:-1] if force_shape is None: n_rows, n_cols = ndsubplot(m) elif len(g_size) == 2: n_rows, n_cols = force_shape data = data.reshape(n_rows, n_cols, len(self)) sig_index = sig_index.reshape(n_rows, n_cols) g_size = (n_rows, n_cols) self._opt_shape = list(data.shape)[0:-1] self._sig_index = sig_index # -------------- (n_rows * n_cols, n_time) -------------- data = np.reshape(data, (m, len(self)), order='F') # -------------- Prepare -------------- # Force demean / detrend of _prep : self._prep.demean, self._prep.detrend = False, False data = self._prep._prepare_data(self._sf, data, 0) # Demean and normalize : kw = {'axis': -1, 'keepdims': True} dmax = np.abs(data).max(**kw) dmax[dmax == 0.] = 1. data -= data.mean(**kw) data /= dmax # data /= data.max() self._dbuffer.set_data(vispy_array(data)) self.g_size = g_size # ====================== INDEX ====================== n, m = len(self), np.prod(g_size) self._sig_index = self._sig_index.reshape(n_rows, n_cols) idg = np.c_[np.repeat(np.repeat(np.arange(n_cols), n_rows), n), np.repeat(np.tile(np.arange(n_rows), n_cols), n)[::-1], np.tile(np.arange(n), m)].astype(np.float32) self._ibuffer.set_data(vispy_array(idg)) # ====================== COLOR ====================== if color is not None: color_1d = color2vb(color) self.shared_program.frag['u_color'] = color_1d.ravel() # ====================== TITLES ====================== # Titles checking : if title is None or (len(title) != m): st, it = '({}, {})', product(range(n_rows), range(n_cols)) title = [st.format(i, k) for i, k in it] # Set text and font size : if not self._txt.text: self._txt.text = title # Get titles position : x_factor, y_factor = 1. / n_cols, 1. / n_rows r_x = np.linspace(-1. + x_factor, 1. - x_factor, n_cols) r_x = np.tile(r_x, n_rows) r_y = np.linspace(-1. + y_factor, 1. - y_factor, n_rows)[::-1] r_y += y_factor r_y = np.repeat(r_y, n_cols) pos = np.c_[r_x, r_y, np.full_like(r_x, -10.)] self._txt.pos = pos.astype(np.float32)
def __init__(self, channels, time, color=(.2, .2, .2), width=1.5, color_detection='red', method='gl', camera=None, parent=None, fcn=None): # Initialize PrepareData : PrepareData.__init__(self, axis=1) # Variables : self._camera = camera self._preproc_channel = -1 self.rect = [] self.width = width self.autoamp = False self._fcn = fcn self.visible = np.array([True] + [False] * (len(channels) - 1)) self.consider = np.ones((len(channels),), dtype=bool) # Get color : self.color = color2vb(color) self.color_detection = color2vb(color_detection) # Create one line per channel : pos = np.zeros((1, 3), dtype=np.float32) self.mesh, self.report, self.grid, self.peak = [], [], [], [] self.loc, self.node = [], [] for i, k in enumerate(channels): # ---------------------------------------------- # Create a node parent : node = scene.Node(name=k + 'plot') node.parent = parent[i].wc.scene self.node.append(node) # ---------------------------------------------- # Create main line (for channel plot) : mesh = scene.visuals.Line(pos, name=k + 'plot', color=self.color, method=method, parent=node) mesh.set_gl_state('translucent') self.mesh.append(mesh) # ---------------------------------------------- # Create marker peaks : mark = Markers(pos=np.zeros((1, 3), dtype=np.float32), parent=node) mark.set_gl_state('translucent') mark.visible = False self.peak.append(mark) # ---------------------------------------------- # Locations : loc = scene.visuals.Line(pos, name=k + 'location', method=method, color=(.1, .1, .1, .3), parent=node, connect='segments') loc.set_gl_state('translucent') self.loc.append(loc) # ---------------------------------------------- # Create a grid : grid = scene.visuals.GridLines(color=(.1, .1, .1, .5), scale=(1., .1), parent=parent[i].wc.scene) grid.set_gl_state('translucent') self.grid.append(grid)
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, data, axis=-1, time=None, sf=1., enable_grid=True, form='line', color='black', line_lw=1., line_smooth=False, marker_symbol='disc', marker_size=10., hist_nbins=10, tf_norm=0, tf_baseline=None, tf_interp='gaussian', tf_cmap='viridis', tf_av_window=None, tf_av_overlap=0., tf_clim=None, psd_nperseg=256, psd_noverlap=128, display_grid=True, display_signal=True, annotations=None, annot_txtsz=18., annot_marksz=16., annot_color='#2ecc71', grid_lw=1., grid_smooth=False, grid_titles=None, grid_font_size=10., grid_color='random', grid_shape=None, grid_titles_color='black', verbose=None, **kwargs): """Init.""" dscb = ['_grid_canvas.canvas.scene', '_signal_canvas.canvas.scene'] _PyQtModule.__init__(self, verbose=verbose, to_describe=dscb) self._enable_grid = enable_grid self._previous_form = form display_grid = bool(display_grid * self._enable_grid) # ==================== APP CREATION ==================== UiInit.__init__(self, **kwargs) # ==================== DATA CHECKING ==================== if isinstance(data, (list, tuple)): data = np.asarray(data) if not isinstance(data, np.ndarray) or (data.ndim > 3): raise TypeError("data must be an NumPy array with less than three " "dimensions.") if data.ndim == 1 or not self._enable_grid: # disable grid display_grid = self._enable_grid = False self.actionGrid.setEnabled(False) toggle_enable_tab(self.QuickSettings, 'Grid', False) self._data = data.astype(np.float32, copy=False) self._axis = axis # ==================== VISUALS ==================== grid_parent = self._grid_canvas.wc.scene signal_parent = self._signal_canvas.wc.scene Visuals.__init__(self, data, time, sf, axis, grid_titles, grid_color, grid_shape, grid_parent, signal_parent) # ==================== UI INIT ==================== self._fix_elements_limits() # ------------- Signal ------------- # Signal and axis color : self._sig_color.setText(str(color2tuple(color, astype=float))) ax_color = kwargs.get('axis_color', color2vb('black')) self._axis_color.setText(str(ax_color)) # Title, labels and ticks : self._sig_title.setText(kwargs.get('title', '')) self._sig_title_fz.setValue(kwargs.get('title_font_size', 15.)) self._sig_xlab.setText(kwargs.get('xlabel', '')) self._sig_ylab.setText(kwargs.get('ylabel', '')) self._sig_lab_fz.setValue(kwargs.get('axis_font_size', 12.)) self._sig_ticks_fz.setValue(kwargs.get('tick_font_size', 8.)) # Signal properties : safely_set_cbox(self._sig_form, form) self._sig_lw.setValue(line_lw) # line self._sig_smooth.setChecked(line_smooth) # line self._sig_nbins.setValue(hist_nbins) # histogram self._sig_size.setValue(marker_size) # marker safely_set_cbox(self._sig_symbol, marker_symbol) # marker self._sig_norm.setCurrentIndex(tf_norm) safely_set_cbox(self._sig_tf_interp, tf_interp) self._sig_tf_rev.setChecked(bool(tf_cmap.find('_r') + 1)) self._sig_tf_cmap.addItems(mpl_cmap()) safely_set_cbox(self._sig_tf_cmap, tf_cmap.replace('_r', '')) if (tf_baseline is not None) and (len(tf_baseline) == 2): self._sig_baseline.setChecked(True) self._sig_base_start.setValue(tf_baseline[0]) self._sig_base_end.setValue(tf_baseline[1]) if isinstance(tf_av_window, int): self._sig_averaging.setChecked(True) self._sig_av_win.setValue(tf_av_window) self._sig_av_overlap.setValue(tf_av_overlap) if (tf_clim is not None) and (len(tf_clim) == 2): self._sig_tf_clim.setChecked(True) self._sig_climin.setValue(tf_clim[0]) self._sig_climax.setValue(tf_clim[1]) self._sig_nperseg.setValue(psd_nperseg) self._sig_noverlap.setValue(psd_noverlap) # ------------- Grid ------------- if hasattr(self, '_grid'): n_rows, n_cols = self._grid.g_size self._grid_nrows.setValue(n_rows) self._grid_nrows.setMaximum(np.prod(self._grid.g_size)) self._grid_ncols.setValue(n_cols) self._grid_ncols.setMaximum(np.prod(self._grid.g_size)) gt_st = str(color2tuple(grid_titles_color, astype=float)) self._grid_titles_fz.setValue(grid_font_size) self._grid_titles_color.setText(gt_st) self._grid_lw.setValue(grid_lw) # ------------- Cbar ------------- self._signal_canvas.cbar.txtcolor = ax_color self._signal_canvas.cbar.border = False self._signal_canvas.cbar.cbtxtsz = 15. self._signal_canvas.cbar.txtsz = 12. # ------------- Settings ------------- bgcolor = kwargs.get('bgcolor', 'white') self._set_bgcolor.setText(str(color2tuple(bgcolor, astype=float))) self._grid_smooth.setChecked(grid_smooth) # ------------- Annotations ------------- self._annot_txtsz.setValue(annot_txtsz) self._annot_marksz.setValue(annot_marksz) self._annot_color.setText(str(color2tuple(annot_color, astype=float))) # ------------- Menu ------------- self.actionGrid.setChecked(display_grid) self.actionSignal.setChecked(display_signal) self._fcn_on_creation() # ==================== USER <-> GUI ==================== UiElements.__init__(self, **kwargs) # ==================== SHORTCUTS ==================== self._shpopup.set_shortcuts(self._sh_grid + self._sh_sig) # ------------- Annotations ------------- if annotations is not None: assert os.path.isfile(annotations) self._fcn_load_annotations(filename=annotations)
def __init__(self, channels, time, color=(.2, .2, .2), width=1.5, color_detection='red', method='gl', camera=None, parent=None, fcn=None): # Initialize PrepareData : PrepareData.__init__(self, axis=1) # Variables : self._camera = camera self._preproc_channel = -1 self.rect = [] self.width = width self.autoamp = False self._fcn = fcn self.visible = np.array([True] + [False] * (len(channels) - 1)) self.consider = np.ones((len(channels), ), dtype=bool) # Get color : self.color = color2vb(color) self.color_detection = color2vb(color_detection) # Create one line per channel : pos = np.zeros((1, 3), dtype=np.float32) self.mesh, self.report, self.grid, self.peak = [], [], [], [] self.loc, self.node = [], [] for i, k in enumerate(channels): # ---------------------------------------------- # Create a node parent : node = scene.Node(name=k + 'plot') node.parent = parent[i].wc.scene self.node.append(node) # ---------------------------------------------- # Create main line (for channel plot) : mesh = scene.visuals.Line(pos, name=k + 'plot', color=self.color, method=method, parent=node) mesh.set_gl_state('translucent') self.mesh.append(mesh) # ---------------------------------------------- # Create marker peaks : mark = Markers(pos=np.zeros((1, 3), dtype=np.float32), parent=node) mark.set_gl_state('translucent') mark.visible = False self.peak.append(mark) # ---------------------------------------------- # Locations : loc = scene.visuals.Line(pos, name=k + 'location', method=method, color=(.1, .1, .1, .3), parent=node, connect='segments') loc.set_gl_state('translucent') self.loc.append(loc) # ---------------------------------------------- # Create a grid : grid = scene.visuals.GridLines(color=(.1, .1, .1, .5), scale=(1., .1), parent=parent[i].wc.scene) grid.set_gl_state('translucent') self.grid.append(grid)
def edge_color(self, value): """Set edge_color value.""" color = color2vb(value, alpha=self.alpha) self._sources._data['a_fg_color'] = color self._edge_color = color self.update()
def color_sources(self, analysis=None, color_by=None, data=None, roi_to_color=None, color_others='black', hide_others=False, cmap='viridis', clim=None, vmin=None, vmax=None, under='gray', over='red'): """Custom color sources methods. This method can be used to color sources : * According to a data vector. In that case, source's colors are inferred using colormap inputs (i.e cmap, vmin, vmax, clim, under and over) * According to ROI analysis (using the `analysis` and `color_by` input parameters) Parameters ---------- data : array_like | None A vector of data with the same length as the number os sources. The color is inferred from this data vector and can be controlled using the cmap, clim, vmin, vmax, under and over parameters. analysis : pandas.DataFrames | None ROI analysis runned using the analyse_sources method. color_by : string | None A column name of the analysis DataFrames. This columns is then used to identify the color to set to each source inside ROI. roi_to_color : dict | None Define custom colors to ROI. For example use {'BA4': 'red', 'BA32': 'blue'} to define custom colors. If roi_to_color is None, random colors will be used instead. color_others : array_like/tuple/string | 'black' Specify how to color sources that are not found using the roi_to_color dictionary. hide_others : bool | False Show or hide sources that are not found using the roi_to_color dictionary. """ if isinstance(data, np.ndarray): assert len(data) == len(self) and (data.ndim == 1) logger.info(" Color %s using a data vector" % self.name) kw = self._update_cbar_args(cmap, clim, vmin, vmax, under, over) colors = array2colormap(data, **kw) elif (analysis is not None) and (color_by is not None): # Group analysis : assert color_by in list(analysis.columns) logger.info(" Color %s according to the %s" % (self.name, color_by)) gp = analysis.groupby(color_by).groups # Compute color : if roi_to_color is None: # random color # Predefined colors and define unique color for each ROI : colors = np.zeros((len(self), 3), dtype=np.float32) u_col = np.random.uniform(.1, .8, (len(gp), 3)) u_col = u_col.astype(np.float32) # Assign color to the ROI : for k, index in enumerate(gp.values()): colors[list(index), :] = u_col[k, :] elif isinstance(roi_to_color, dict): # user defined colors colors = color2vb(color_others, length=len(self)) keep_visible = np.zeros(len(self), dtype=bool) for roi_name, roi_col in roi_to_color.items(): if roi_name in list(gp.keys()): colors[list(gp[roi_name]), :] = color2vb(roi_col) keep_visible[list(gp[roi_name])] = True else: warn("%s not found in the %s column of analysis" "." % (roi_name, color_by)) if hide_others: self.visible = keep_visible else: raise TypeError("roi_to_color must either be None or a " "dictionary like {'roi_name': 'red'}.") self.color = colors
def tcolor(self, value): """Set tcolor value.""" self._txt.color = color2vb(value)
def __init__(self, name, xyz, data=None, color='red', alpha=1., symbol='disc', radius_min=5., radius_max=10., edge_width=0., edge_color='black', system='mni', mask=None, mask_color='gray', mask_radius=5., text=None, text_size=2., text_color='white', text_bold=False, text_translate=(0., 2., 0.), visible=True, transform=None, parent=None, verbose=None, _z=-10., **kw): """Init.""" VisbrainObject.__init__(self, name, parent, transform, verbose, **kw) # _______________________ CHECKING _______________________ # XYZ : sh = xyz.shape assert sh[1] in [2, 3] self._n_sources = sh[0] pos = xyz if sh[1] == 3 else np.c_[xyz, np.full((len(self), ), _z)] logger.info(' %i sources detected' % self._n_sources) # Radius min and max : assert all( [isinstance(k, (int, float)) for k in (radius_min, radius_max)]) radius_max = max(radius_min, radius_max) self._radius_min, self._radius_max = radius_min, radius_max self._mask_radius = mask_radius # Data : if data is None: data = np.ones((len(self), )) else: assert np.shape(data)[0] == len(self) self._data = vispy_array(data) # System : pos = pos if system == 'mni' else tal2mni(pos) self._xyz = vispy_array(pos) # Color : self._color = color # Edges : self._edge_color, self._edge_width = edge_color, edge_width # Mask : if mask is None: mask = [False] * len(self) self._mask = np.asarray(mask).ravel().astype(bool) assert len(self._mask) == len(self) self._mask_color = color2vb(mask_color) # Text : self._text_size = text_size self._text_color = text_color self._text_translate = text_translate # _______________________ MARKERS _______________________ self._sources = visuals.Markers(pos=self._xyz, name='Markers', edge_color=edge_color, edge_width=edge_width, symbol=symbol, parent=self._node) self._sources.set_gl_state('translucent', depth_test=True, cull_face=False) # _______________________ TEXT _______________________ tvisible = text is None self._text = [''] * len(self) if tvisible else text self._text = np.array(self._text) assert len(self._text) == len(self) self._sources_text = visuals.Text(self._text, pos=self._xyz, bold=text_bold, name='Text', color=color2vb(text_color), font_size=text_size, parent=self._node) self._sources_text.visible = not tvisible tr = vist.STTransform(translate=text_translate) self._sources_text.transform = tr # _______________________ UPDATE _______________________ # Radius / color : self.visible = visible self._update_radius() self.alpha = alpha self._update_color()
def mask_color(self, value): """Set mask_color value.""" value = color2vb(value).ravel() self._mask_color = value self._build_bgd_texture()
def mask_color(self, value): """Set mask_color value.""" self._mask_color = color2vb(value) self._update_color()
def text_color(self, value): """Set text_color value.""" color = color2vb(value) self._sources_text.color = color self._text_color = color self._sources_text.update()
def set_data(self, data, index, color='black', lw=2., nbins=10, symbol='disc', size=10., form='line', th=None, norm=None, window=None, overlap=0., baseline=None, clim=None, cmap='viridis', interpolation='gaussian', nperseg=256, noverlap=128): """Set data to the plot. Parameters ---------- data : array_like Raw data vector of shape (N,) index : int | 0 Index of the 3-d array. color : array_like/string/tuple | None Color of the plot. lw : float | None Line width (form='line'). symbol : string | None Marker symbol (form='marker'). size : float | None Marker size (form='marker'). nbins : int | None Number of bins for the histogram (form='histogram') form : {'line', 'marker', 'histogram', 'tf'} Plotting type. th : tuple | None Tuple of floats for line thresholding. norm : int | None Normalization method for (form='tf'). window : tuple | None Averaging window (form='tf'). overlap : float | 0. Overlap between successive windows (form='tf'). baseline : tuple | None Baseline period for the normalization (form='tf'). """ # Update variable : self.form = form self._index = index color = color2vb(color) # Get data index : if data.ndim == 1: idx = slice(None) elif data.ndim in [2, 3]: idx = list(self._navidx[index]) idx.insert(self._axis, slice(None)) idx = tuple(idx) # Convert data to be compatible with VisPy and prepare data : data_c = vispy_array(data[idx]).copy() _data = self._prep._prepare_data(self._sf, data_c, self._time) # Set data : if form in ['line', 'marker', 'psd', 'butterfly']: # line and marker # Get position array : pos = np.c_[self._time, _data] # Send position : if form in ['line', 'psd']: if form == 'psd': fmax = self._sf / 4. f, pxx = welch(_data, self._sf, nperseg=nperseg, noverlap=noverlap) f_sf4 = abs(f - fmax) f_1 = abs(f - 1.) fidx_sf4 = np.where(f_sf4 == f_sf4.min())[0][0] fidx_1 = np.where(f_1 == f_1.min())[0][0] pos = np.c_[f[fidx_1:-fidx_sf4], pxx[fidx_1:-fidx_sf4]] # Threshold : is_th = isinstance(th, (tuple, list, np.ndarray)) col = color2vb(color, length=pos.shape[0]) if is_th: # Build threshold segments : t_min, t_max = self._time.min(), self._time.max() pos_th = np.vstack( ([t_min, th[0]], [t_max, th[0]], [t_min, th[1]], [t_max, th[1]])) self._th.set_data(pos_th, connect='segments', color=color2vb('#ab4642')) # Build line color : col = color2vb(color, length=len(_data)) cond = np.logical_or(_data < th[0], _data > th[1]) col[cond, :] = color2vb('#ab4642') self._th.visible = is_th self._line.set_data(pos, width=lw, color=col) self._line.update() elif form == 'marker': self._mark.set_data(pos, face_color=color, symbol=symbol, size=size, edge_width=0.) self._mark.update() elif form == 'butterfly': # Get soe shape related variables : n, m = len(self._time), int(np.prod(data.shape)) n_rep = int(m / n) data = vispy_array(data) # Build position : pos = np.c_[np.tile(self._time.ravel(), n_rep), data.ravel()] # Disconnect some points : connect = np.c_[np.arange(m - 1), np.arange(1, m)] to_delete = np.linspace(n - 1, m - 1, n_rep) connect = np.delete(connect, to_delete, axis=0) # Build color : col = color2vb(color, length=m) # singcol = np.random.uniform(size=(n_rep, 3), low=.2, # high=.8).astype(np.float32) # col = np.repeat(singcol, n, 0) # Send data : self._line.set_data(pos, width=lw, color=col, connect=connect) self._line.update() # Get camera rectangle : t_min, t_max = pos[:, 0].min(), pos[:, 0].max() d_min, d_max = pos[:, 1].min(), pos[:, 1].max() off = .05 * (d_max - d_min) self.rect = (t_min, d_min - off, t_max - t_min, d_max - d_min + 2 * off) elif form == 'histogram': # histogram # Compute the mesh : mesh = scene.visuals.Histogram(_data, nbins) # Get the vertices and faces of the mesh : vert = mesh.mesh_data.get_vertices() faces = mesh.mesh_data.get_faces() # Pass vertices and faces to the histogram : self._hist.set_data(vert, faces, color=color) # Compute the histogram : raw, xvec = np.histogram(_data, nbins) # Get camera rectangle : t_min, t_max = xvec.min(), xvec.max() d_min, d_max = 0.9 * raw[np.nonzero(raw)].min(), 1.01 * raw.max() self.rect = (t_min, d_min, t_max - t_min, d_max - d_min) # Update object : self._hist.update() elif form == 'tf': # time-frequency map self._tf.set_data(_data, self._sf, cmap=cmap, contrast=.5, norm=norm, baseline=baseline, n_window=window, overlap=overlap, window='hanning', clim=clim) self._tf.interpolation = interpolation self.rect = self._tf.rect # Hide non form elements : self._visibility() # Update annotations : self.update_annotations(str(self))
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")