Пример #1
0
    def selectionChanged(self, selected, deselected):
        super(ClusterTreeView, self).selectionChanged(selected, deselected)
        can_signal_selection = getattr(self, "can_signal_selection", True)
        can_signal_selection = can_signal_selection and getattr(self.model(), "can_signal_selection", True)

        if can_signal_selection:
            # emit the ClusterSelectionToChange signal
            clusters = self.selected_clusters()
            groups = self.selected_groups()
            allclusters = []
            # groups first
            for group in groups:
                allclusters.extend([cl.clusteridx() for cl in self.model().get_clusters_in_group(group)])

            # add clusters that are not in the selected groups, and
            # remove the others
            clusters_to_add = []
            for cluster in clusters:
                if cluster not in allclusters:
                    clusters_to_add.append(cluster)
                else:
                    allclusters.remove(cluster)
            allclusters.extend(clusters_to_add)

            # remove duplicates while preserving the order
            clusters_unique = []
            for clu in allclusters:
                if clu not in clusters_unique:
                    clusters_unique.append(clu)
            clusters_unique = np.array(clusters_unique, dtype=np.int32)

            ssignals.emit(self, "ClusterSelectionToChange", clusters_unique)
Пример #2
0
 def set_highlighted_spikes(self, spikes, do_emit=True):
     """Update spike colors to mark transiently selected spikes with
     a special color."""
     if len(spikes) == 0:
         # do update only if there were previously selected spikes
         do_update = len(self.highlighted_spikes) > 0
         self.highlight_mask[:] = 0
     else:
         do_update = True
         self.highlight_mask[:] = 0
         spikes_rel = self.spikes_rel[spikes]
         # from absolue indices to relative indices
         # spikes_rel = np.digitize(spikes, self.spike_ids) - 1
         self.highlight_mask[spikes_rel] = 1
     
     if do_update:
         
         # emit the HighlightSpikes signal
         if do_emit:
             ssignals.emit(self.parent, 'HighlightSpikes', spikes)
                 # self.spike_ids[np.array(spikes, dtype=np.int32)])
         
         self.paint_manager.set_data(
             highlight=self.highlight_mask, visual='features')
     
     # self.HighlightSpikes = QtCore.pyqtSignal(np.ndarray)
     
     # self.parent.emit(SpikySignals.HighlightSpikes, spikes)
     
     self.highlighted_spikes = spikes
Пример #3
0
 def set_selected_spikes(self, spikes, do_emit=True):
     """Update spike colors to mark transiently selected spikes with
     a special color."""
     if len(spikes) == 0:
         # do update only if there were previously selected spikes
         do_update = len(self.selected_spikes) > 0
         self.selection_mask[:] = 0
     else:
         do_update = True
         self.selection_mask[:] = 0
         self.selection_mask[spikes] = 1
     
     if do_update:
         
         # emit the SelectionSpikes signal
         if do_emit:
             if len(spikes) > 0:
                 aspikes = self.data_manager.spike_ids[spikes]
             else:
                 aspikes = spikes
             ssignals.emit(self.parent, 'SelectSpikes', aspikes)
         
         self.paint_manager.set_data(
             selection=self.selection_mask, visual='features')
     
     self.selected_spikes = spikes
Пример #4
0
    def change_color(self):
        items = self.view.selected_items()
        if not items:
            return
        initial_color = items[0].color()
        if initial_color >= 0:
            initial_color = 255 * colors.COLORMAP[initial_color]
            initial_color = QtGui.QColor(*initial_color)
            color = QtGui.QColorDialog.getColor(initial_color)
        else:
            color = QtGui.QColorDialog.getColor()
        # return if the user canceled
        if not color.isValid():
            return
        # get the RGB values of the chosen color
        rgb = np.array(color.getRgbF()[:3]).reshape((1, -1))
        # test white: in this case, no color
        if rgb.sum() >= 2.999:
            nocolor = True
        else:
            nocolor = False
        # take the closest color in the palette
        i = np.argmin(np.abs(colors.COLORMAP - rgb).sum(axis=1))

        # emit signal
        groups = np.array(self.view.selected_groups())
        clusters = np.array(self.view.selected_clusters())
        if len(groups) > 0:
            ssignals.emit(self, "ChangeGroupColorRequested", groups, i)
        if len(clusters) > 0:
            ssignals.emit(self, "ChangeClusterColorRequested", clusters, i)
Пример #5
0
 def rename_group(self):
     groups = self.view.selected_groups()
     if groups:
         groupidx = groups[0]
         group = self.model.get_group(groupidx)
         name = group.name()
         text, ok = QtGui.QInputDialog.getText(self, "Group name", "Rename group:", QtGui.QLineEdit.Normal, name)
         if ok:
             ssignals.emit(self, "RenameGroupRequested", groupidx, text)
Пример #6
0
 def load(self, filename, fileindex, probefile):
     
     # if hasattr(self, 'du'):
         # self.du.stop()
     self.provider = KlustersDataProvider()
     self.dh = self.provider.load(filename, fileindex=fileindex,
         probefile=probefile)#, progressbar=self.progressbar)
     # self.sdh = sdataio.SelectDataHolder(self.dh)
     # self.du = DataUpdater(self.sdh)
     # self.am = spiky.ActionManager(self.dh, self.sdh)
     ssignals.emit(self, 'FileLoaded')
Пример #7
0
 def select_pair(self, parameter):
     
     self.cursor = 'ArrowCursor'
     
     # cx_rel, cy_rel = self.get_closest_cluster(parameter)
     cx, cy = self.get_closest_cluster(parameter)
     
     # cx = self.data_manager.clusters_unique[cx_rel]
     # cy = self.data_manager.clusters_unique[cy_rel]
     pair = np.unique(np.array([cx, cy]))
     
     ssignals.emit(self, 'ClusterSelectionToChange', pair)
Пример #8
0
 def select_neighbor_feature(self, parameter):
     # print self.data_manager.projection
     coord, feature_dir = parameter
     # current channel and feature in the given coordinate
     proj = self.data_manager.projection[coord]
     if proj is None:
         proj = (0, coord)
     channel, feature = proj
     # next or previous feature
     feature = np.mod(feature + feature_dir, self.data_manager.fetdim)
     # select projection
     # self.select_projection((coord, channel, feature))
     ssignals.emit(self.parent, 'ProjectionToChange', coord, channel, feature)
Пример #9
0
 def select_channel(self, channel, coord=0):
     """Raise the ProjectionToChange signal when the channel is changed."""
     # print type(channel)
     # return
     # if isinstance(channel, basestring):
     if channel.startswith('Extra'):
         channel = channel[6:]
         extra = True
     else:
         extra = False
     # try:
     channel = int(channel)
     if extra:
         channel += self.dh.nchannels #* self.dh.fetdim
     ssignals.emit(self, "ProjectionToChange", coord, channel,
              self.projection[coord][1])
Пример #10
0
    def drag(self, target, sources):
        # get source ClusterItem nodes
        source_items = []
        nodes = self.all_nodes()
        for node in nodes:
            if str(node) in sources and type(node) == ClusterItem and node not in source_items:
                source_items.append(node)

        # get the groupidx if the target is a group
        if type(target) == GroupItem:
            groupidx = target.groupidx()
        # else, if it is a cluster, take the corresponding group
        elif type(target) == ClusterItem:
            groupidx = self.get_groupidx(target.clusteridx())
        else:
            # empty target
            return

        # clusters to move
        clusters = np.array([source.clusteridx() for source in source_items])
        clusters = np.array([source.clusteridx() for source in source_items])
        # emit signals
        ssignals.emit(self, "MoveClustersRequested", clusters, groupidx)
Пример #11
0
 def slotProjectionToChange(self, sender, coord, channel, feature):
     ssignals.emit(sender, 'ProjectionChanged', coord, channel, feature)
Пример #12
0
 def initialize_actions(self):
     """Initialize all global actions."""
     # automatic projection action
     self.autoproj_action = QtGui.QAction("Automatic projection", self)
     self.autoproj_action.setIcon(spiky.get_icon("magic"))
     self.autoproj_action.setShortcut("P")
     self.autoproj_action.setStatusTip("Automatically choose the best " +
         "projection in the FeatureView.")
     self.autoproj_action.triggered.connect(lambda e: ssignals.emit(self, "AutomaticProjection"), QtCore.Qt.UniqueConnection)
     
     # open action
     self.open_action = QtGui.QAction("&Open", self)
     self.open_action.setShortcut("CTRL+O")
     self.open_action.setIcon(spiky.get_icon("open"))
     self.open_action.triggered.connect(self.open_file, QtCore.Qt.UniqueConnection)
     
     # open probe file action
     self.open_probe_action = QtGui.QAction("&Open probe file", self)
     self.open_probe_action.setShortcut("CTRL+SHIFT+O")
     self.open_probe_action.setIcon(spiky.get_icon("probe"))
     self.open_probe_action.triggered.connect(self.open_probefile, QtCore.Qt.UniqueConnection)
     
     # save action
     self.save_action = QtGui.QAction("&Save", self)
     self.save_action.setShortcut("CTRL+S")
     self.save_action.setIcon(spiky.get_icon("save"))
     self.save_action.triggered.connect(self.save_file, QtCore.Qt.UniqueConnection)
     
     # save action
     self.saveas_action = QtGui.QAction("Save &as", self)
     self.saveas_action.setShortcut("CTRL+SHIFT+S")
     self.saveas_action.setIcon(spiky.get_icon("saveas"))
     self.saveas_action.triggered.connect(self.saveas_file, QtCore.Qt.UniqueConnection)
     
     # exit action
     self.quit_action = QtGui.QAction("E&xit", self)
     self.quit_action.setShortcut("CTRL+Q")
     self.quit_action.triggered.connect(self.close, QtCore.Qt.UniqueConnection)
     
     # merge action
     self.merge_action = QtGui.QAction("Mer&ge", self)
     self.merge_action.setIcon(spiky.get_icon("merge"))
     self.merge_action.setShortcut("CTRL+G")
     self.merge_action.setEnabled(False)
     self.merge_action.triggered.connect(self.merge, QtCore.Qt.UniqueConnection)
     
     # split action
     self.split_action = QtGui.QAction("&Split", self)
     self.split_action.setIcon(spiky.get_icon("split"))
     self.split_action.setShortcut("CTRL+K")
     self.split_action.setEnabled(False)
     self.split_action.triggered.connect(self.split, QtCore.Qt.UniqueConnection)
     
     # DEL
     self.move_to_mua_action = QtGui.QAction("Move to &Multi-Unit", self)
     self.move_to_mua_action.setShortcut("Del")
     self.move_to_mua_action.setIcon(spiky.get_icon("multiunit"))
     self.move_to_mua_action.triggered.connect(self.move_to_mua, QtCore.Qt.UniqueConnection)
     self.move_to_mua_action.setEnabled(False)
     
     # SHIFT+DEL
     self.move_to_noise_action = QtGui.QAction("Move to &Noise", self)
     self.move_to_noise_action.setShortcut("Shift+Del")
     self.move_to_noise_action.setIcon(spiky.get_icon("noise"))
     self.move_to_noise_action.triggered.connect(self.move_to_noise, QtCore.Qt.UniqueConnection)
     self.move_to_noise_action.setEnabled(False)
     
     # undo action
     self.undo_action = QtGui.QAction("&Undo", self)
     self.undo_action.setShortcut("CTRL+Z")
     self.undo_action.setIcon(spiky.get_icon("undo"))
     self.undo_action.setEnabled(False)
     self.undo_action.triggered.connect(self.undo, QtCore.Qt.UniqueConnection)
     
     # redo action
     self.redo_action = QtGui.QAction("&Redo", self)
     self.redo_action.setShortcut("CTRL+Y")
     self.redo_action.setIcon(spiky.get_icon("redo"))
     self.redo_action.setEnabled(False)
     self.redo_action.triggered.connect(self.redo, QtCore.Qt.UniqueConnection)
     
     # override color action
     self.override_color_action = QtGui.QAction("Override &color", self)
     self.override_color_action.setShortcut("C")
     self.override_color_action.setIcon(spiky.get_icon("override_color"))
     self.override_color_action.triggered.connect(self.override_color, QtCore.Qt.UniqueConnection)
Пример #13
0
 def select(self, clusters):
     self.dh.select_clusters(clusters)
     ssignals.emit(self.du, 'ClusterSelectionChanged', clusters)
Пример #14
0
    def load(self, filename, fileindex=1, probefile=None):#, progressbar=None):
        
        # load XML
        self.holder = DataHolder()
        
        try:
            path = get_actual_filename(filename, 'xml', None)
            params = parse_xml(path, fileindex=fileindex)
        except Exception as e:
            raise Exception(("The XML file was not found and the data cannot "
                "be loaded."))
        
        
        # klusters tests
        nchannels = params['nchannels']
        nsamples = params['nsamples']
        fetdim = params['fetdim']
        freq = params['rate']
        
        self.filename = filename
        self.fileindex = fileindex
        
        # if filename.endswith('_spiky'):
            # filename = filename.replace('_spiky', '')
            # spiky = True
        # else:
            # spiky = False
                
        
        # FEATURES
        # -------------------------------------------------
        # features = load_text_fast(filename + ".fet.%d" % fileindex, np.int32, skiprows=1)
        path = get_actual_filename(filename, 'fet', fileindex)
        features, headers = load_text_pandas(path, np.int32, skiprows=1, returnheaders=True)
        features = np.array(features, dtype=np.float32)
        
        # Find out the number of extra features.
        nfet = int(headers[0])
        # HACK: sometimes, problem with penultimate column due to double white space
        if features.shape[1] != nfet:
            features = np.hstack((features[:,:-2], features[:,-1].reshape((-1, 1))))
        nextrafet = nfet - fetdim * nchannels
        
        # HACK: there are either 1 or 5 dimensions more than fetdim*nchannels
        # we can't be sure so we first try 1, if it does not work we try 5
        # try:
        features = features.reshape((-1, nfet))
        # except:
            # raise Exception(("The FET file was not found and the data cannot "
                # "be loaded."))
            # log_debug("The number of columns is not fetdim (%d) x nchannels (%d) + 1." \
                # % (fetdim, nchannels))
            # try:
                # features = features.reshape((-1, fetdim * nchannels + 5))
                
            # except:
                # log_debug("The number of columns is not fetdim (%d) x nchannels (%d) + 5, so I'm confused and I can't continue. Sorry :(" \
                    # % (fetdim, nchannels))
                
        nspikes = features.shape[0]


        # CLUSTERS
        # -------------------------------------------------
        try:
            # if spiky:
                # path = filename + "_spiky.clu.%d" % fileindex
            # else:
                # path = filename + ".clu.%d" % fileindex
            path = get_actual_filename(filename, 'clu', fileindex)
            # clusters = load_text(path, np.int32)
            clusters = load_text_pandas(path, np.int32)
        except Exception as e:
            log_warn("CLU file '%s' not found" % filename)
            clusters = np.zeros(nspikes + 1, dtype=np.int32)
            clusters[0] = 1
        # nclusters = clusters[0]
        clusters = clusters[1:]
        # if progressbar:
            # progressbar.setValue(1)
        ssignals.emit(self, 'FileLoading', .2)
            
        
        # get the spiketimes
        spiketimes = features[:,-1].copy()
        # remove the last column in features, containing the spiketimes
        # features = features[:,:nchannels * fetdim]
        nextrafet = features.shape[1] - nchannels * fetdim
        
        # normalize normal features
        m = features[:,:-nextrafet].min()
        M = features[:,:-nextrafet].max()
        # force symmetry
        vx = max(np.abs(m), np.abs(M))
        m, M = -vx, vx
        features[:,:-nextrafet] = -1+2*(features[:,:-nextrafet]-m)/(M-m)
        
        
        # normalize extra features
        m = features[:,-nextrafet:].min()
        M = features[:,-nextrafet:].max()
        # # force symmetry
        # vx = max(np.abs(m), np.abs(M))
        # m, M = -vx, vx
        features[:,-nextrafet:] = -1+2*(features[:,-nextrafet:]-m)/(M-m)
        
        # if progressbar:
            # progressbar.setValue(2)
        ssignals.emit(self, 'FileLoading', .4)
            
            
        
        # MASKS
        # -------------------------------------------------
        # first: try fmask
        try:
            # masks = load_text(filename + ".fmask.%d" % fileindex, np.float32, skiprows=1)
            path = get_actual_filename(filename, 'fmask', fileindex)
            masks = load_text_pandas(path, np.float32, skiprows=1)
            self.holder.masks_complete = masks
            masks = masks[:,:-1:fetdim]
            # masks = masks[::fetdim]
        except Exception as e:
            try:
                # otherwise, try mask
                # masks = load_text(filename + ".mask.%d" % fileindex, np.float32, skiprows=1)
                path = get_actual_filename(filename, 'mask', fileindex)
                masks = load_text_pandas(path, np.float32, skiprows=1)
                # masks = masks[:,:-1:fetdim]
                self.holder.masks_complete = masks
                masks = masks[:,:-1:fetdim]
                # masks = masks[::fetdim]
            except:
                # finally, warning and default masks (everything to 1)
                log_warn("MASK file '%s' not found" % filename)
                masks = np.ones((nspikes, nchannels))
                self.holder.masks_complete = np.ones(features.shape)
        
        # if progressbar:
            # progressbar.setValue(3)
        ssignals.emit(self, 'FileLoading', .6)
        
        
        
        # WAVEFORMS
        # -------------------------------------------------
        try:
            path = get_actual_filename(filename, 'spk', fileindex)
            waveforms = load_binary(path)
            # print waveforms.shape
            # print (nspikes, nsamples, nchannels)
            # DEBUG
            # nchannels = 32
            
            # print waveforms.shape
            # print nspikes * nsamples * nchannels
            
            waveforms = waveforms.reshape((nspikes, nsamples, nchannels))
        except IOError as e:
            log_warn("SPK file '%s' not found" % filename)
            waveforms = np.zeros((nspikes, nsamples, nchannels))
        
        # if progressbar:
            # progressbar.setValue(4)
        ssignals.emit(self, 'FileLoading', .8)
            
            
            
        
        self.holder.freq = freq
        
        
        self.holder.nspikes = nspikes
        self.holder.nchannels = nchannels
        self.holder.nextrafet = nextrafet
        
        # construct spike times from random interspike interval
        self.holder.spiketimes = spiketimes
        
        self.holder.duration = spiketimes[-1] / float(self.holder.freq)
    
        # normalize waveforms at once
        waveforms = (waveforms - waveforms.mean())
        waveforms = waveforms / np.abs(waveforms).max()
        
        self.holder.waveforms = waveforms
        self.holder.waveforms_info = dict(nsamples=nsamples)
        
        self.holder.fetdim = fetdim
        self.holder.features = features
        
        self.holder.masks = masks
        
        self.holder.clusters = clusters
        
        # create the groups info object
        # Default groups
        
        # GROUPS
        # --------------------------------------
        try:
            path = get_actual_filename(filename, 'groups', fileindex)
        
            info = load_pickle(path)
            clusters_info = info['clusters_info']
            groups_info = info['groups_info']
            
        except:
        
            groups_info = {
                0: dict(groupidx=0, name='Noise', color=0, spkcount=0),
                1: dict(groupidx=1, name='Multi-unit', color=1, spkcount=0),
                2: dict(groupidx=2, name='Good', color=2, spkcount=nspikes),
            }
            clusters_info = get_clusters_info(clusters, groupidx=2)
            
            
        nclusters = len(clusters_info)
        self.holder.nclusters = nclusters
        
        self.holder.clusters_info = dict(
            clusters_info=clusters_info,
            groups_info=groups_info,
            )

            
            
            
        # c = Counter(clusters)
        # self.holder.clusters_counter = c
        
            
        probe = None
        try:
            if probefile:
                probe = np.loadtxt(probefile)
        except Exception as e:
            print(str(e))
        self.holder.probe = dict(positions=probe)
        
        # cross correlograms
        nsamples_correlograms = 20
        self.holder.correlograms_info = dict(nsamples=nsamples_correlograms)
        
        # self.holder.correlation_matrix = rdn.rand(nclusters, nclusters)
        # self.holder.correlation_matrix = np.array([[]])
        # features = 
        # self.holder.correlation_matrix = correlation_matrix(features, clusters)
        # self.holder.correlation_matrix_queue = CorrelationMatrixQueue(self.holder)
        # self.holder.correlation_matrix_queue.process()
        
        
        # TASKS.add('correlation_matrix_queue', CorrelationMatrixQueue, self.holder)
        tasks.TASKS.correlation_matrix_queue = inprocess(tasks.CorrelationMatrixQueue)(self.holder)
        tasks.TASKS.correlation_matrix_queue.process()
        
        return self.holder
Пример #15
0
 def select_feature(self, coord, fet=0):
     """Select channel coord, feature fet."""
     # raise the ProjectionToChange signal, and keep the previously
     # selected channel
     ssignals.emit(self, "ProjectionToChange", coord, self.projection[coord][0], fet)
Пример #16
0
 def process_done(dh=None, doupdate=None, _result=None):
     ssignals.emit(None, 'CorrelationMatrixUpdated', _result)
     
     
     
Пример #17
0
 def update_signal(self):
     """Raise the update signal, specifying that the correlogram view
     needs to be updated."""
     ssignals.emit(self, 'CorrelogramsUpdated')
Пример #18
0
 def add_group(self):
     ssignals.emit(self, "AddGroupRequested")
Пример #19
0
 def remove_groups(self):
     ssignals.emit(self, "RemoveGroupsRequested", np.array(self.view.selected_groups()))