Ejemplo n.º 1
0
 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)
Ejemplo n.º 2
0
    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")
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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")
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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")
Ejemplo n.º 9
0
    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")