def update_labels(self):
        """
        Trigger an updaet of labels

        The method calls `get_labels` which in turn calls the widget's
        `get_label_data`. The obtained labels are shown if the corresponding
        points are selected or if `label_only_selected` is `false`.
        """
        for label in self.labels:
            self.plot_widget.removeItem(label)
        self.labels = []
        if self.scatterplot_item is None \
                or self.label_only_selected and self.selection is None:
            return
        labels = self.get_labels()
        if labels is None:
            return
        black = pg.mkColor(0, 0, 0)
        x, y = self.scatterplot_item.getData()
        if self.label_only_selected:
            selected = np.nonzero(self._filter_visible(self.selection))
            labels = labels[selected]
            x = x[selected]
            y = y[selected]
        for label, xp, yp in zip(labels, x, y):
            ti = TextItem(label, black)
            ti.setPos(xp, yp)
            self.plot_widget.addItem(ti)
            self.labels.append(ti)
 def createGraphWidget(self):
     plotWidget = pg.PlotWidget()
     self.graphLayout.addWidget(plotWidget)
     self.plotItem = plotWidget.getPlotItem()
     self.plotItem.showGrid(x=True, y=True)
     self.plotItem.setLabel("left", "Średnia temperatura [°C]")
     self.plotItem.setLabel("bottom", "Czas [s]")
     self.plot = self.plotItem.plot()
     self.plotCurrent = self.plotItem.plot(
         symbol="o", symbolPen=(0, 122, 217), symbolBrush=(0, 122, 217)
     )
     self.currentLabel = TextItem("cell", (255, 255, 255), anchor=(0, 0))
    def add_param_tree(self):
        self.ptree = ptree.ParameterTree(showHeader=False)
        self.filter = DataFilterParameter()
        params = ptree.Parameter.create(name='params',
                                        type='group',
                                        children=[self.filter])
        self.ptree.setParameters(params, showTop=False)

        self.filter_layout.addWidget(self.ptree)

        self.filterText = TextItem(border=getConfigOption('foreground'))
        self.filterText.setPos(60, 20)
        self.filterText.setParentItem(self.plot.plotItem)
        self.filter.sigFilterChanged.connect(self.filterChanged)
        self.filter.setFields([('butterFilter', {'units': 'Hz'})])
Example #4
0
    def update_labels(self):
        """
        Trigger an update of labels

        The method calls `get_labels` which in turn calls the widget's
        `get_label_data`. The obtained labels are shown if the corresponding
        points are selected or if `label_only_selected` is `false`.
        """
        for label in self.labels:
            self.plot_widget.removeItem(label)
        self.labels = []
        if self.scatterplot_item is None \
                or self.label_only_selected and self.selection is None:
            self._signal_too_many_labels(False)
            return
        labels = self.get_labels()
        if labels is None:
            self._signal_too_many_labels(False)
            return
        (x0, x1), (y0, y1) = self.view_box.viewRange()
        x, y = self.scatterplot_item.getData()
        mask = np.logical_and(np.logical_and(x >= x0, x <= x1),
                              np.logical_and(y >= y0, y <= y1))
        if self.label_only_selected:
            mask = np.logical_and(mask,
                                  self._filter_visible(self.selection) != 0)
        if mask.sum() > self.MAX_VISIBLE_LABELS:
            self._signal_too_many_labels(True)
            return
        black = pg.mkColor(0, 0, 0)
        labels = labels[mask]
        x = x[mask]
        y = y[mask]
        for label, xp, yp in zip(labels, x, y):
            ti = TextItem(label, black)
            ti.setPos(xp, yp)
            self.plot_widget.addItem(ti)
            self.labels.append(ti)
        self._signal_too_many_labels(False)
Example #5
0
    def update_labels(self):
        """
        Trigger an update of labels

        The method calls `get_labels` which in turn calls the widget's
        `get_label_data`. The obtained labels are shown if the corresponding
        points are selected or if `label_only_selected` is `false`.
        """
        for label in self.labels:
            self.plot_widget.removeItem(label)
        self.labels = []

        mask = None
        if self.scatterplot_item is not None:
            x, y = self.scatterplot_item.getData()
            mask = self._label_mask(x, y)

        if mask is not None:
            labels = self.get_labels()
            if labels is None:
                mask = None

        self._signal_too_many_labels(
            mask is not None and mask.sum() > self.MAX_VISIBLE_LABELS)
        if self._too_many_labels or mask is None or not np.any(mask):
            return

        black = pg.mkColor(0, 0, 0)
        labels = labels[mask]
        x = x[mask]
        y = y[mask]
        for label, xp, yp in zip(labels, x, y):
            ti = TextItem(label, black)
            ti.setPos(xp, yp)
            self.plot_widget.addItem(ti)
            self.labels.append(ti)
Example #6
0
    def update_labels(self):
        """
        Trigger an update of labels

        The method calls `get_labels` which in turn calls the widget's
        `get_label_data`. The obtained labels are shown if the corresponding
        points are selected or if `label_only_selected` is `false`.
        """
        for label in self.labels:
            self.plot_widget.removeItem(label)
        self.labels = []

        mask = None
        if self.scatterplot_item is not None:
            x, y = self.scatterplot_item.getData()
            mask = self._label_mask(x, y)

        if mask is not None:
            labels = self.get_labels()
            if labels is None:
                mask = None

        self._signal_too_many_labels(mask is not None
                                     and mask.sum() > self.MAX_VISIBLE_LABELS)
        if self._too_many_labels or mask is None or not np.any(mask):
            return

        black = pg.mkColor(0, 0, 0)
        labels = labels[mask]
        x = x[mask]
        y = y[mask]
        for label, xp, yp in zip(labels, x, y):
            ti = TextItem(label, black)
            ti.setPos(xp, yp)
            self.plot_widget.addItem(ti)
            self.labels.append(ti)
Example #7
0
    def __init__(self, scatter_widget, parent=None, _="None"):
        gui.OWComponent.__init__(self, scatter_widget)
        self.view_box = InteractiveViewBox(self)
        self.plot_widget = pg.PlotWidget(viewBox=self.view_box, parent=parent)
        self.plot_widget.setAntialiasing(True)
        self.replot = self.plot_widget
        ScaleScatterPlotData.__init__(self)
        self.scatterplot_item = None

        self.tooltip_data = []
        self.tooltip = TextItem(
            border=pg.mkPen(200, 200, 200), fill=pg.mkBrush(250, 250, 200, 220))
        self.tooltip.hide()

        self.labels = []

        self.master = scatter_widget
        self.shown_attribute_indices = []
        self.shown_x = ""
        self.shown_y = ""
        self.pen_colors = self.brush_colors = None

        self.valid_data = None  # np.ndarray
        self.selection = None  # np.ndarray
        self.n_points = 0

        self.gui = OWPlotGUI(self)
        self.continuous_palette = ContinuousPaletteGenerator(
            QColor(255, 255, 0), QColor(0, 0, 255), True)
        self.discrete_palette = ColorPaletteGenerator()

        self.selection_behavior = 0

        self.legend = self.color_legend = None
        self.scale = None  # DiscretizedScale

        self.tips = TooltipManager(self)
        # self.setMouseTracking(True)
        # self.grabGesture(QPinchGesture)
        # self.grabGesture(QPanGesture)

        self.update_grid()
Example #8
0
 def create_labels(self):
     for x, y in zip(*self.scatterplot_item.getData()):
         ti = TextItem()
         self.plot_widget.addItem(ti)
         ti.setPos(x, y)
         self.labels.append(ti)
Example #9
0
    def plotData(self):
        offset = 0
        lastAutoRangeState = self._graphicsView.vb.getState()['autoRange']
        self._graphicsView.disableAutoRange(ViewBox.XYAxes)
        if self.lastEnabledChannels and self.lastEnabledChannels != self.signalTableModel.enabledList:
            for curve in concatenate_iter(self.curveBundle,
                                          self.curveAuxBundle,
                                          self.curveTriggerBundle,
                                          self.curveGateBundle):
                if curve:
                    self._graphicsView.removeItem(curve)
            self.curveBundle = None
            self.curveAuxBundle = None
            self.curveTriggerBundle = None
            self.curveGateBundle = None
            if self.textItems:
                for item in self.textItems:
                    self._graphicsView.removeItem(item)
        if self.yDataBundle:
            if self.curveBundle is None:
                self.curveBundle = list()
                for i, yData in enumerate(self.yDataBundle):
                    if yData:
                        curve = PlotCurveItem(self.xData,
                                              yData,
                                              stepMode=True,
                                              fillLevel=offset,
                                              brush=penList[1][4],
                                              pen=penList[1][0])
                        self._graphicsView.addItem(curve)
                        self.curveBundle.append(curve)
                        textItem = TextItem(
                            self.signalTableModel.primaryChannelName(i),
                            anchor=(1, 1),
                            color=(0, 0, 0))
                        textItem.setPos(0, offset)
                        self._graphicsView.addItem(textItem)
                        self.textItems.append(textItem)
                        offset += 1
                    else:
                        self.curveBundle.append(None)
            else:
                for curve, yData in zip(self.curveBundle, self.yDataBundle):
                    if yData:
                        if curve:
                            curve.setData(x=self.xData, y=yData)

        nextChannel = self.settings.numChannels
        if self.yAuxDataBundle:
            if self.curveAuxBundle is None:
                self.curveAuxBundle = list()
                for i, yAuxData in enumerate(self.yAuxDataBundle):
                    if yAuxData:
                        curve = PlotCurveItem(self.xAuxData,
                                              yAuxData,
                                              stepMode=True,
                                              fillLevel=offset,
                                              brush=penList[2][4],
                                              pen=penList[2][0])
                        self._graphicsView.addItem(curve)
                        self.curveAuxBundle.append(curve)
                        textItem = TextItem(
                            self.signalTableModel.auxChannelName(i),
                            anchor=(1, 1),
                            color=(0, 0, 0))
                        textItem.setPos(0, offset)
                        self._graphicsView.addItem(textItem)
                        self.textItems.append(textItem)
                        offset += 1
                    else:
                        self.curveAuxBundle.append(None)

            else:
                for curve, yAuxData in zip(self.curveAuxBundle,
                                           self.yAuxDataBundle):
                    if yAuxData:
                        if curve:
                            curve.setData(x=self.xAuxData, y=yAuxData)
        nextChannel += self.settings.numAuxChannels
        if self.yTriggerBundle:
            if self.curveTriggerBundle is None:
                self.curveTriggerBundle = list()
                for i, yTrigger in enumerate(self.yTriggerBundle):
                    if yTrigger:
                        curve = PlotCurveItem(self.xTrigger,
                                              yTrigger,
                                              stepMode=True,
                                              fillLevel=offset,
                                              brush=penList[3][4],
                                              pen=penList[3][0])
                        self._graphicsView.addItem(curve)
                        self.curveTriggerBundle.append(curve)
                        textItem = TextItem(
                            self.signalTableModel.triggerChannelName(i),
                            anchor=(1, 1),
                            color=(0, 0, 0))
                        textItem.setPos(0, offset)
                        self._graphicsView.addItem(textItem)
                        self.textItems.append(textItem)
                        offset += 1
                    else:
                        self.curveTriggerBundle.append(None)

            else:
                for curve, yTrigger in zip(self.curveTriggerBundle,
                                           self.yTriggerBundle):
                    if yTrigger:
                        if curve:
                            curve.setData(x=self.xTrigger, y=yTrigger)
        nextChannel = self.settings.numTriggerChannels
        if self.yGateDataBundle:
            if self.curveGateBundle is None:
                self.curveGateBundle = list()
                for i, yGateData in enumerate(self.yGateDataBundle):
                    if yGateData:
                        curve = PlotCurveItem(self.xGateData,
                                              yGateData,
                                              stepMode=True,
                                              fillLevel=offset,
                                              brush=penList[2][4],
                                              pen=penList[2][0])
                        self._graphicsView.addItem(curve)
                        self.curveGateBundle.append(curve)
                        textItem = TextItem(
                            self.signalTableModel.gateChannelName(i),
                            anchor=(1, 1),
                            color=(0, 0, 0))
                        textItem.setPos(0, offset)
                        self._graphicsView.addItem(textItem)
                        self.textItems.append(textItem)
                        offset += 1
                    else:
                        self.curveGateBundle.append(None)

            else:
                for curve, yGateData in zip(self.curveGateBundle,
                                            self.yGateDataBundle):
                    if yGateData:
                        if curve:
                            curve.setData(x=self.xGateData, y=yGateData)
        self.lastEnabledChannels = list(self.signalTableModel.enabledList)
        xautorange, yautorange = lastAutoRangeState
        if xautorange:
            self._graphicsView.enableAutoRange(ViewBox.XAxis)
        if yautorange:
            self._graphicsView.enableAutoRange(ViewBox.YAxis)
        self._graphicsView.autoRange()
Example #10
0
 def create_labels(self):
     for x, y in zip(*self.scatterplot_item.getData()):
         ti = TextItem()
         self.plot_widget.addItem(ti)
         ti.setPos(x, y)
         self.labels.append(ti)
class FftGraph:
    """
    """
    def __init__(self, gv, layout):
        self.gv = gv
        self.curve_freq = []
        self.layout = layout

        self.dock_area = DockArea()
        layout.addWidget(self.dock_area, 1, 0, 1, 8)
        # Plot
        self.plot_d = self.init_plot_dock()
        self.plot = self.init_plot()
        self.add_regions_filter_to_plot()
        self.connect_classif_region()
        # Settings
        self.create_settings_dock()
        # Filter settings
        self.filter_d = self.create_filter_settings_dock()
        self.init_filters()

        self.timer = self.init_timer()

    def init_plot_dock(self):
        plot_d = InnerDock(self.layout, 'plot')
        self.dock_area.addDock(plot_d.dock)
        return plot_d

    def init_timer(self):
        timer = QtCore.QTimer()
        timer.timeout.connect(self.update_plotting)
        return timer

    def init_plot(self):
        """Create the plot widget and its characteristics"""
        plot = pg.PlotWidget(background=dark_grey)
        plot.plotItem.showGrid(x=True, y=True, alpha=0.3)
        plot.plotItem.setLabel(axis='bottom', text='Frequency',
                               units='Hz')  # TODO: ALEXM : verifier l'uniter
        plot.plotItem.setLabel(axis='left', text='Amplitude', units='None')
        plot.setXRange(0, 130)
        plot.setYRange(0, 1000000)
        # Add to tab layout
        self.plot_d.layout.addWidget(plot, 2, 0, 5, 5)
        for ch in range(self.gv.N_CH):
            self.curve_freq.append(
                plot.plot(
                    deque(np.ones(self.gv.DEQUE_LEN),
                          maxlen=self.gv.DEQUE_LEN)))
            self.curve_freq[ch].setPen(pen_colors[ch])

        self.gv.curve_freq = self.curve_freq
        return plot

    def add_param_tree(self):
        self.ptree = ptree.ParameterTree(showHeader=False)
        self.filter = DataFilterParameter()
        params = ptree.Parameter.create(name='params',
                                        type='group',
                                        children=[self.filter])
        self.ptree.setParameters(params, showTop=False)

        self.filter_layout.addWidget(self.ptree)

        self.filterText = TextItem(border=getConfigOption('foreground'))
        self.filterText.setPos(60, 20)
        self.filterText.setParentItem(self.plot.plotItem)
        self.filter.sigFilterChanged.connect(self.filterChanged)
        self.filter.setFields([('butterFilter', {'units': 'Hz'})])

    def filterChanged(self):
        print('cool')

    def add_regions_filter_to_plot(self):
        """Add a region to the plot that will be use as the bondaries for
        the filter (blue for pass and red for cut)"""
        # Band pass filter
        self.pass_f_region = pg.LinearRegionItem([
            self.gv.min_pass_filter, self.gv.max_pass_filter
        ])  # TODO: ALEXM: avoid redondancy in the creation of filters
        self.pass_f_region.setBrush(blue)
        self.plot.addItem(self.pass_f_region, ignoreBounds=True)
        # Band cut filter
        self.cut_f_region = pg.LinearRegionItem(
            [self.gv.min_cut_filter, self.gv.max_cut_filter])
        self.cut_f_region.setBrush(red)
        self.plot.addItem(self.cut_f_region, ignoreBounds=True)

    def connect_classif_region(self):
        self.pass_f_region.sigRegionChanged.connect(
            partial(self.update_pass_filter_region))
        self.cut_f_region.sigRegionChanged.connect(
            partial(self.update_cut_filter_region))

    def update_pass_filter_region(self):
        self.gv.min_pass_filter, self.gv.max_pass_filter = \
                self.pass_f_region.getRegion()

    def update_cut_filter_region(self):
        self.gv.min_cut_filter, self.gv.max_cut_filter = \
                self.cut_f_region.getRegion()

    def update_plotting(self):
        self.all_frequency()

    def all_frequency(self):
        for ch in range(self.gv.N_CH):
            f_range, fft = self.gv.freq_calculator.get_fft_to_plot(
                np.array(self.gv.data_queue[ch])
                [self.gv.filter_min_bound:self.gv.filter_max_bound])
            self.curve_freq[ch].setData(f_range, fft)
            # self.curve_freq[ch].setData(
            #         self.gv.freq_calculator.freq_range,
            #         self.gv.freq_calculator.fft[ch])                         # TODO: ALEXM prendre abs ou real? avec real il y a des valeurs negatives est-ce que c'est normal?

    def init_on_off_button(self, layout):
        btn('Start',
            layout, (0, 0),
            func_conn=self.start,
            color=dark_blue_tab,
            toggle=True,
            txt_color=white,
            min_width=100)

    def create_settings_dock(self):
        settings_d = InnerDock(self.layout,
                               'Settings',
                               toggle_button=True,
                               size=(1, 1))
        self.init_on_off_button(settings_d.layout)

        create_param_combobox(settings_d.layout, 'Max Freq', (0, 1),
                              ['Auto', '60 Hz', '80 Hz', '100 Hz', '120 Hz'],
                              partial(self.scale_axis, axis_name='x'))
        create_param_combobox(settings_d.layout, 'Max Uv', (0, 2), [
            'Auto', '1000 uv', '10000 uv', '100000 uv', '1000000 uv',
            '10000000 uv'
        ], partial(self.scale_axis, axis_name='y'))
        create_param_combobox(settings_d.layout, 'Log', (0, 3),
                              ['False', 'True'], self.log_axis)
        create_param_combobox(settings_d.layout, 'Filter', (0, 4),
                              ['No filter', 'Bandpass', 'Bandstop', 'Both'],
                              self.show_filter)
        self.combo_to_filter = {
            'No filter': [],
            'Bandpass': ['bandpass'],
            'Bandstop': ['bandstop'],
            'Both': ['bandpass', 'bandstop']
        }
        create_param_combobox(
            settings_d.layout,
            'Ch On', (0, 5),
            ['ch 1', 'ch 2', 'ch 3', 'ch 4', 'ch 5', 'ch 6', 'ch 7', 'ch 8'],
            self.ch_on_off,
            editable=False)

        self.dock_area.addDock(settings_d.dock, 'top')

    def create_filter_settings_dock(self):
        filter_d = InnerDock(self.layout,
                             'Filter',
                             toggle_button=True,
                             size=(1, 1),
                             b_pos=(0, 1),
                             b_checked=False)
        self.dock_area.addDock(filter_d.dock, 'right')
        filter_d.dock.hide()
        return filter_d

    def init_filters(self):
        ## Create flowchart, define input/output terminals
        fc = Flowchart(terminals={
            'dataIn': {
                'io': 'in'
            },
            'dataOut': {
                'io': 'out'
            }
        })
        ## Add flowchart control panel to the main window
        self.filter_d.layout.addWidget(fc.widget(), 0, 0, 2, 1)
        ## Add two plot widgets
        pw1 = pg.PlotWidget()
        pw2 = pg.PlotWidget()
        self.filter_d.layout.addWidget(pw1, 0, 1)
        self.filter_d.layout.addWidget(pw2, 1, 1)
        ## generate signal data to pass through the flowchart
        data = np.random.normal(size=1000)
        data[200:300] += 1
        data += np.sin(np.linspace(0, 100, 1000))
        data = metaarray.MetaArray(data,
                                   info=[{
                                       'name':
                                       'Time',
                                       'values':
                                       np.linspace(0, 1.0, len(data))
                                   }, {}])
        ## Feed data into the input terminal of the flowchart
        fc.setInput(dataIn=data)
        ## populate the flowchart with a basic set of processing nodes.
        ## (usually we let the user do this)
        plotList = {'Top Plot': pw1, 'Bottom Plot': pw2}

        pw1Node = fc.createNode('PlotWidget', pos=(0, -150))
        pw1Node.setPlotList(plotList)
        pw1Node.setPlot(pw1)

        pw2Node = fc.createNode('PlotWidget', pos=(150, -150))
        pw2Node.setPlot(pw2)
        pw2Node.setPlotList(plotList)

        fNode = fc.createNode('GaussianFilter', pos=(0, 0))
        fNode.ctrls['sigma'].setValue(5)
        fc.connectTerminals(fc['dataIn'], fNode['In'])
        fc.connectTerminals(fc['dataIn'], pw1Node['In'])
        fc.connectTerminals(fNode['Out'], pw2Node['In'])
        fc.connectTerminals(fNode['Out'], fc['dataOut'])

    def scale_axis(self, txt, axis_name):
        try:
            if txt == 'Auto':
                self.plot.enableAutoRange()
            else:
                r = int(re.search(r'\d+', txt).group())
                if axis_name == 'x':
                    self.plot.setXRange(0, r)
                elif axis_name == 'y':
                    self.plot.setYRange(0, r)
        except AttributeError:
            print("Come on bro, this  value doesn't make sens")

    def log_axis(self, txt):
        self.plot.setLogMode(y=eval(txt))

    def ch_on_off(self):
        pass

    def show_filter(self, txt):
        self.gv.filter_to_use = self.combo_to_filter[txt]

    @QtCore.pyqtSlot(bool)
    def start(self, checked):
        if checked:
            if not self.gv.freq_calculator.activated:
                self.gv.freq_calculator.timer.start(100)
                self.gv.freq_calculator.activated = True
            self.timer.start(100)
        else:
            self.timer.stop()
            self.gv.freq_calculator.timer.stop()
            self.gv.freq_calculator.activated = False
Example #12
0
 def plotData(self):
     offset = 0
     lastAutoRangeState = self._graphicsView.vb.getState()['autoRange']
     self._graphicsView.disableAutoRange(ViewBox.XYAxes)
     if self.lastEnabledChannels and self.lastEnabledChannels!=self.signalTableModel.enabledList:
         for curve in concatenate_iter(self.curveBundle, self.curveAuxBundle, self.curveTriggerBundle, self.curveGateBundle):
             if curve:
                 self._graphicsView.removeItem(curve)
         self.curveBundle = None
         self.curveAuxBundle = None
         self.curveTriggerBundle = None
         self.curveGateBundle = None
         if self.textItems:
             for item in self.textItems:
                 self._graphicsView.removeItem(item)
     if self.yDataBundle:
         if self.curveBundle is None:
             self.curveBundle = list()
             for i, yData in enumerate(self.yDataBundle):
                 if yData:
                     curve = PlotCurveItem(self.xData, yData, stepMode=True, fillLevel=offset, brush=penList[1][4], pen=penList[1][0]) 
                     self._graphicsView.addItem( curve )
                     self.curveBundle.append( curve )
                     textItem = TextItem( self.signalTableModel.primaryChannelName(i), anchor=(1, 1), color=(0, 0, 0) )
                     textItem.setPos( 0, offset )
                     self._graphicsView.addItem(textItem)
                     self.textItems.append(textItem)
                     offset += 1
                 else:
                     self.curveBundle.append( None )
         else:
             for curve, yData in zip(self.curveBundle, self.yDataBundle):
                 if yData:
                     if curve:
                         curve.setData(x=self.xData, y=yData)
                         
     nextChannel = self.settings.numChannels
     if self.yAuxDataBundle:
         if self.curveAuxBundle is None:
             self.curveAuxBundle = list()
             for i, yAuxData in enumerate(self.yAuxDataBundle):
                 if yAuxData:
                     curve = PlotCurveItem(self.xAuxData, yAuxData, stepMode=True, fillLevel=offset, brush=penList[2][4], pen=penList[2][0])
                     self._graphicsView.addItem( curve )
                     self.curveAuxBundle.append( curve )
                     textItem = TextItem( self.signalTableModel.auxChannelName(i), anchor=(1, 1), color=(0, 0, 0) )
                     textItem.setPos( 0, offset )
                     self._graphicsView.addItem(textItem)
                     self.textItems.append(textItem)
                     offset += 1 
                 else:
                     self.curveAuxBundle.append( None )
                     
         else:
             for curve, yAuxData in zip(self.curveAuxBundle, self.yAuxDataBundle):
                 if yAuxData:
                     if curve:
                         curve.setData(x=self.xAuxData, y=yAuxData)
     nextChannel += self.settings.numAuxChannels
     if self.yTriggerBundle:
         if self.curveTriggerBundle is None:
             self.curveTriggerBundle = list()
             for i, yTrigger in enumerate(self.yTriggerBundle):
                 if yTrigger:
                     curve = PlotCurveItem(self.xTrigger, yTrigger, stepMode=True, fillLevel=offset, brush=penList[3][4], pen=penList[3][0]) 
                     self._graphicsView.addItem( curve )
                     self.curveTriggerBundle.append( curve )
                     textItem = TextItem( self.signalTableModel.triggerChannelName(i), anchor=(1, 1), color=(0, 0, 0) )
                     textItem.setPos( 0, offset )
                     self._graphicsView.addItem(textItem)
                     self.textItems.append(textItem)
                     offset += 1 
                 else:
                     self.curveTriggerBundle.append( None )
                     
         else:
             for curve, yTrigger in zip(self.curveTriggerBundle, self.yTriggerBundle):
                 if yTrigger:
                     if curve:
                         curve.setData(x=self.xTrigger, y=yTrigger)
     nextChannel = self.settings.numTriggerChannels
     if self.yGateDataBundle:
         if self.curveGateBundle is None:
             self.curveGateBundle = list()
             for i, yGateData in enumerate(self.yGateDataBundle):
                 if yGateData:
                     curve = PlotCurveItem(self.xGateData, yGateData, stepMode=True, fillLevel=offset, brush=penList[2][4], pen=penList[2][0])
                     self._graphicsView.addItem( curve )
                     self.curveGateBundle.append( curve )
                     textItem = TextItem( self.signalTableModel.gateChannelName(i), anchor=(1, 1), color=(0, 0, 0) )
                     textItem.setPos( 0, offset )
                     self._graphicsView.addItem(textItem)
                     self.textItems.append(textItem)
                     offset += 1 
                 else:
                     self.curveGateBundle.append( None )
                     
         else:
             for curve, yGateData in zip(self.curveGateBundle, self.yGateDataBundle):
                 if yGateData:
                     if curve:
                         curve.setData(x=self.xGateData, y=yGateData)
     self.lastEnabledChannels = list( self.signalTableModel.enabledList )
     xautorange, yautorange = lastAutoRangeState
     if xautorange:
         self._graphicsView.enableAutoRange(ViewBox.XAxis)
     if yautorange:
         self._graphicsView.enableAutoRange(ViewBox.YAxis)
     self._graphicsView.autoRange()
class Application(QObject, Ui_mainWindow):
    def __init__(self, mainWindow: QMainWindow):
        super().__init__()
        self.mainWindow = mainWindow
        self.userId: int = 0
        self.dbFile: str = ""
        self.setupUi()
        mainWindow.show()

    def setupUi(self):
        super().setupUi(self.mainWindow)
        self.createMediaPlayer()
        self.createGraphWidget()

        self.pickDirectory.clicked.connect(self.pickVideoClick)
        self.exitApplication.clicked.connect(self.mainWindow.close)
        self.showDataBase.clicked.connect(self.pickDataBaseClick)
        self.clearScene.clicked.connect(self.graphicsView.scene().clearSelection)

        self.playButton.clicked.connect(self.playButtonClicked)
        self.mediaDurationSlider.sliderMoved.connect(self.mediaPlayer.setPosition)
        self.graphicsView.scene().regionSelected.connect(self.displayGraph)

    def createMediaPlayer(self):
        self.mediaPlayer = SeqPlayer(self.mainWindow)
        self.mediaPlayer.setVideoOutput(self.graphicsView.scene().videoItem)
        self.mediaPlayer.videoAvailableChanged.connect(self.playButton.setEnabled)
        self.mediaPlayer.videoAvailableChanged.connect(
            self.mediaDurationSlider.setEnabled
        )
        self.mediaPlayer.stateChanged.connect(self.mediaPlayerStateChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)
        self.mediaPlayer.positionChanged.connect(self.mediaDurationSlider.setValue)
        self.mediaPlayer.positionChanged.connect(self.displayCurrentTemperature)
        self.mediaPlayerStateChanged(QMediaPlayer.StoppedState)

    def createGraphWidget(self):
        plotWidget = pg.PlotWidget()
        self.graphLayout.addWidget(plotWidget)
        self.plotItem = plotWidget.getPlotItem()
        self.plotItem.showGrid(x=True, y=True)
        self.plotItem.setLabel("left", "Średnia temperatura [°C]")
        self.plotItem.setLabel("bottom", "Czas [s]")
        self.plot = self.plotItem.plot()
        self.plotCurrent = self.plotItem.plot(
            symbol="o", symbolPen=(0, 122, 217), symbolBrush=(0, 122, 217)
        )
        self.currentLabel = TextItem("cell", (255, 255, 255), anchor=(0, 0))

    @Slot()
    def pickVideoClick(self):
        filePath, _ = QFileDialog.getOpenFileName(
            self.mainWindow, "Otwórz plik", "", "SEQ files (*.seq);;IMG files (*.img)"
        )
        if filePath:
            self.videoPath = pathlib.Path(filePath)
            self.userId = self.videoPath.stem[0:2]
            self.mediaPlayer.setFile(self.videoPath)
            self.graphicsView.scene().clearSelection()
            self.displayUserData()
            self.mediaPlayer.play()

    @Slot()
    def playButtonClicked(self):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()

    @Slot(int)
    def durationChanged(self, duration: int):
        self.mediaDurationSlider.setMaximum(duration - 1)

    @Slot(QMediaPlayer.State)
    def mediaPlayerStateChanged(self, state: QMediaPlayer.PlayingState):
        if state == QMediaPlayer.PlayingState:
            buttonText = "Pause"
            buttonIcon = QStyle.SP_MediaPause
        else:
            buttonText = "Play"
            buttonIcon = QStyle.SP_MediaPlay

        self.playButton.setText(buttonText)
        self.playButton.setIcon(self.playButton.style().standardIcon(buttonIcon))

    @Slot(int)
    def displayCurrentTemperature(self, position: int):
        temperature = self.values[position]
        self.plotCurrent.setData([position], [temperature])
        self.currentLabel.setPos(position, temperature)
        self.currentLabel.setText(f"{position}, {temperature:.2f}")
        if self.currentLabel not in self.plotItem.items:
            self.plotItem.addItem(self.currentLabel)

    @Slot(QRect)
    def displayGraph(self, selection: QRect):
        reader = self.mediaPlayer.reader()
        if not reader:
            logging.error("Video not available")
        self.values = []
        for frame_number in range(reader.num_frames):
            frame = reader.frame(frame_number)
            temperatures = frame.data
            if not selection.isEmpty():
                temperatures = temperatures[
                    selection.top() : selection.bottom(),
                    selection.left() : selection.right(),
                ]
            self.values.append(numpy.average(temperatures))

        self.plot.setData(self.values)
        self.displayCurrentTemperature(self.mediaPlayer.position())
        self.plotItem.getViewBox().autoRange(padding=0.11)
        self.plotItem.getViewBox().setRange(xRange=(-10, reader.num_frames * 1.12))

    def getSurveyResults(self, userId: int):
        with sqlite3.connect(self.dbFile) as connection:
            connection.row_factory = sqlite3.Row
            cursor = connection.cursor()
            return cursor.execute(
                "SELECT * FROM Ankieta WHERE Id=?", (userId,)
            ).fetchall()

    @Slot()
    def pickDataBaseClick(self):
        dbFile, _ = QFileDialog.getOpenFileName(
            self.mainWindow, "Otwórz bazę danych", "", "Database files (*.db)"
        )
        if dbFile:
            self.dbFile = dbFile
            self.displayUserData()

    def displayUserData(self):
        if not self.dbFile:
            self.userData.setText("Otwórz plik bazy danych")
        elif not self.userId:
            self.userData.setText("Załaduj plik z obrazem")
        else:
            try:
                surveyResults = self.getSurveyResults(self.userId)
                if surveyResults:
                    self.displaySurveyResults(surveyResults[0])
                else:
                    self.userData.setText(
                        dedent(
                            f"""\
                            Brak pasującego wyniku w bazie danych
                             dla użytkownika o ID "{self.userId}"
                            (dwa pierwsze znaki nazwy pliku wideo)
                            """
                        )
                    )
            except Exception as e:
                self.userData.setText(f"Nie udało się otworzyć bazy danych:\n {e}")

    def displaySurveyResults(self, userData):
        self.userData.setHtml(
            dedent(
                f"""
                <p>
                <b>Id:</b> {userData['Id']}<br />
                <b>Płeć:</b> {userData['Plec']}<br />
                <b>Wiek:</b> {userData['Wiek']}<br />
                <b>Województwo zamieszkania:</b> {userData['Wojewodztwo']}<br />
                <b>Jak często marzną dłonie/stopy:</b> {userData['Marzniecie']}<br />
                <b>Jak często bieleją lub sinieją dłonie/stopy:</b> {userData['Sinienie']}<br />
                <b>Jak często bierze zimne kąpiele:</b> {userData['ZimneKapiele']}<br />
                <b>Jak często morsuje:</b> {userData['Morsowanie']}<br />
                <b>Choroby:</b> {userData['Choroby']}<br />
                <b>Przyjmowane leki:</b> {userData['Leki']}<br />
                </p>
                <b>Temperatura badanego:</b> {userData['TempBadanego']} °C <br />
                <b>Tetno początkowe badanego:</b> {userData['TetnoPoczatkowe']}/min <br />
                <b>Ciśnienie początkowe badanego:</b> {userData['CisSkurczPoczatkowe']}/{userData['CisRozkurczPoczatkowe']} mmHg <br />
                <b>Temperatura wody przed pierwszym badaniem:</b> {userData['TempWodyDo1Badania']} °C <br />
                <b>Tętno po pierwszym badaniu:</b> {userData['TetnoPo1Badaniu']}/min <br />
                <b>Ciśnienie po pierwszym badaniu:</b> {userData['CisSkurczPo1Badaniu']}/{userData['CisRozkurczPo1Badaniu']} mmHg <br />
                <b>Temperatura wody przed drugim badaniem:</b> {userData['TempWodyDo2Badania']} °C <br />
                <b>Tętno po drugim badaniu:</b> {userData['TetnoPo2Badaniu']}/min <br />
                <b>Ciśnienie po drugim badaniu:</b> {userData['CisSkurczPo2Badaniu']}/{userData['CisRozkurczPo2Badaniu']} mmHg <br />
                """
            )
        )
Example #14
0
class OWScatterPlotGraph(gui.OWComponent, ScaleScatterPlotData):
    attr_color = ContextSetting("", ContextSetting.OPTIONAL)
    attr_label = ContextSetting("", ContextSetting.OPTIONAL)
    attr_shape = ContextSetting("", ContextSetting.OPTIONAL)
    attr_size = ContextSetting("", ContextSetting.OPTIONAL)

    point_width = Setting(10)
    alpha_value = Setting(255)
    show_grid = Setting(False)
    show_legend = Setting(True)
    tooltip_shows_all = Setting(False)
    square_granularity = Setting(3)
    space_between_cells = Setting(True)

    CurveSymbols = np.array("o x t + d s ?".split())
    MinShapeSize = 6
    DarkerValue = 120
    UnknownColor = (168, 50, 168)

    def __init__(self, scatter_widget, parent=None, _="None"):
        gui.OWComponent.__init__(self, scatter_widget)
        self.view_box = InteractiveViewBox(self)
        self.plot_widget = pg.PlotWidget(viewBox=self.view_box, parent=parent)
        self.plot_widget.setAntialiasing(True)
        self.replot = self.plot_widget
        ScaleScatterPlotData.__init__(self)
        self.scatterplot_item = None

        self.tooltip_data = []
        self.tooltip = TextItem(
            border=pg.mkPen(200, 200, 200), fill=pg.mkBrush(250, 250, 200, 220))
        self.tooltip.hide()

        self.labels = []

        self.master = scatter_widget
        self.shown_attribute_indices = []
        self.shown_x = ""
        self.shown_y = ""
        self.pen_colors = self.brush_colors = None

        self.valid_data = None  # np.ndarray
        self.selection = None  # np.ndarray
        self.n_points = 0

        self.gui = OWPlotGUI(self)
        self.continuous_palette = ContinuousPaletteGenerator(
            QColor(255, 255, 0), QColor(0, 0, 255), True)
        self.discrete_palette = ColorPaletteGenerator()

        self.selection_behavior = 0

        self.legend = self.color_legend = None
        self.scale = None  # DiscretizedScale

        self.tips = TooltipManager(self)
        # self.setMouseTracking(True)
        # self.grabGesture(QPinchGesture)
        # self.grabGesture(QPanGesture)

        self.update_grid()

    def set_data(self, data, subset_data=None, **args):
        self.plot_widget.clear()
        ScaleScatterPlotData.set_data(self, data, subset_data, **args)

    def update_data(self, attr_x, attr_y):
        self.shown_x = attr_x
        self.shown_y = attr_y

        self.remove_legend()
        if self.scatterplot_item:
            self.plot_widget.removeItem(self.scatterplot_item)
        for label in self.labels:
            self.plot_widget.removeItem(label)
        self.labels = []
        self.tooltip_data = []
        self.set_axis_title("bottom", "")
        self.set_axis_title("left", "")

        if self.scaled_data is None or not len(self.scaled_data):
            self.valid_data = None
            self.n_points = 0
            return

        index_x = self.attribute_name_index[attr_x]
        index_y = self.attribute_name_index[attr_y]
        self.valid_data = self.get_valid_list([index_x, index_y])
        x_data, y_data = self.get_xy_data_positions(
            attr_x, attr_y, self.valid_data)
        x_data = x_data[self.valid_data]
        y_data = y_data[self.valid_data]
        self.n_points = len(x_data)

        for axis, name, index in (("bottom", attr_x, index_x),
                                  ("left", attr_y, index_y)):
            self.set_axis_title(axis, name)
            var = self.data_domain[index]
            if isinstance(var, DiscreteVariable):
                self.set_labels(axis, get_variable_values_sorted(var))

        color_data, brush_data = self.compute_colors()
        size_data = self.compute_sizes()
        shape_data = self.compute_symbols()
        self.scatterplot_item = ScatterPlotItem(
            x=x_data, y=y_data, data=np.arange(self.n_points),
            symbol=shape_data, size=size_data, pen=color_data, brush=brush_data)
        self.plot_widget.addItem(self.scatterplot_item)
        self.plot_widget.addItem(self.tooltip)
        self.scatterplot_item.selected_points = []
        self.scatterplot_item.sigClicked.connect(self.select_by_click)
        self.scatterplot_item.scene().sigMouseMoved.connect(self.mouseMoved)

        self.update_labels()
        self.make_legend()
        self.plot_widget.replot()

    def set_labels(self, axis, labels):
        axis = self.plot_widget.getAxis(axis)
        if labels:
            ticks = [[(i, labels[i]) for i in range(len(labels))]]
            axis.setTicks(ticks)
        else:
            axis.setTicks(None)

    def set_axis_title(self, axis, title):
        self.plot_widget.setLabel(axis=axis, text=title)

    def get_size_index(self):
        size_index = -1
        attr_size = self.attr_size
        if attr_size != "" and attr_size != "(Same size)":
            size_index = self.attribute_name_index[attr_size]
        return size_index

    def compute_sizes(self):
        size_index = self.get_size_index()
        if size_index == -1:
            size_data = np.full((self.n_points,), self.point_width)
        else:
            size_data = \
                self.MinShapeSize + \
                self.no_jittering_scaled_data[size_index] * self.point_width
        size_data[np.isnan(size_data)] = self.MinShapeSize - 2
        return size_data

    def update_sizes(self):
        if self.scatterplot_item:
            size_data = self.compute_sizes()
            self.scatterplot_item.setSize(size_data)

    update_point_size = update_sizes

    def get_color_index(self):
        color_index = -1
        attr_color = self.attr_color
        if attr_color != "" and attr_color != "(Same color)":
            color_index = self.attribute_name_index[attr_color]
            color_var = self.data_domain[attr_color]
            if isinstance(color_var, DiscreteVariable):
                self.discrete_palette.set_number_of_colors(
                    len(color_var.values))
        return color_index

    def compute_colors(self, keep_colors=False):
        if not keep_colors:
            self.pen_colors = self.brush_colors = None
        color_index = self.get_color_index()
        if color_index == -1:
            color = self.plot_widget.palette().color(OWPalette.Data)
            pen = [QPen(QBrush(color), 1.5)] * self.n_points
            if self.selection is not None:
                brush = [(QBrush(QColor(128, 128, 128, 255)),
                          QBrush(QColor(128, 128, 128)))[s]
                         for s in self.selection]
            else:
                brush = [QBrush(QColor(128, 128, 128))] * self.n_points
            return pen, brush

        c_data = self.original_data[color_index, self.valid_data]
        if isinstance(self.data_domain[color_index], ContinuousVariable):
            if self.pen_colors is None:
                self.scale = DiscretizedScale(np.min(c_data), np.max(c_data))
                c_data -= self.scale.offset
                c_data /= self.scale.width
                c_data = np.floor(c_data) + 0.5
                c_data /= self.scale.bins
                c_data = np.clip(c_data, 0, 1)
                palette = self.continuous_palette
                self.pen_colors = palette.getRGB(c_data)
                self.brush_colors = np.hstack(
                    [self.pen_colors,
                     np.full((self.n_points, 1), self.alpha_value)])
                self.pen_colors *= 100 / self.DarkerValue
                self.pen_colors = [QPen(QBrush(QColor(*col)), 1.5)
                                   for col in self.pen_colors.tolist()]
            if self.selection is not None:
                self.brush_colors[:, 3] = 0
                self.brush_colors[self.selection, 3] = self.alpha_value
            else:
                self.brush_colors[:, 3] = self.alpha_value
            pen = self.pen_colors
            brush = np.array([QBrush(QColor(*col))
                              for col in self.brush_colors.tolist()])
        else:
            if self.pen_colors is None:
                palette = self.discrete_palette
                n_colors = palette.number_of_colors
                c_data = c_data.copy()
                c_data[np.isnan(c_data)] = n_colors
                c_data = c_data.astype(int)
                colors = palette.getRGB(np.arange(n_colors + 1))
                colors[n_colors] = (128, 128, 128)
                pens = np.array(
                    [QPen(QBrush(QColor(*col).darker(self.DarkerValue)), 1.5)
                     for col in colors])
                self.pen_colors = pens[c_data]
                self.brush_colors = np.array([
                    [QBrush(QColor(0, 0, 0, 0)),
                     QBrush(QColor(col[0], col[1], col[2], self.alpha_value))]
                    for col in colors])
                self.brush_colors = self.brush_colors[c_data]
            if self.selection is not None:
                brush = np.where(
                    self.selection,
                    self.brush_colors[:, 1], self.brush_colors[:, 0])
            else:
                brush = self.brush_colors[:, 1]
            pen = self.pen_colors
        return pen, brush

    def update_colors(self, keep_colors=False):
        if self.scatterplot_item:
            pen_data, brush_data = self.compute_colors(keep_colors)
            self.scatterplot_item.setPen(pen_data, update=False, mask=None)
            self.scatterplot_item.setBrush(brush_data, mask=None)
            if not keep_colors:
                self.make_legend()

    update_alpha_value = update_colors

    def create_labels(self):
        for x, y in zip(*self.scatterplot_item.getData()):
            ti = TextItem()
            self.plot_widget.addItem(ti)
            ti.setPos(x, y)
            self.labels.append(ti)

    def update_labels(self):
        if not self.attr_label:
            for label in self.labels:
                label.setText("")
            return
        if not self.labels:
            self.create_labels()
        label_column = self.raw_data.get_column_view(self.attr_label)[0]
        formatter = self.raw_data.domain[self.attr_label].str_val
        label_data = map(formatter, label_column)
        black = pg.mkColor(0, 0, 0)
        for label, text in zip(self.labels, label_data):
            label.setText(text, black)

    def get_shape_index(self):
        shape_index = -1
        attr_shape = self.attr_shape
        if attr_shape and attr_shape != "(Same shape)" and \
                len(self.data_domain[attr_shape].values) <= \
                len(self.CurveSymbols):
            shape_index = self.attribute_name_index[attr_shape]
        return shape_index

    def compute_symbols(self):
        shape_index = self.get_shape_index()
        if shape_index == -1:
            shape_data = self.CurveSymbols[np.zeros(self.n_points, dtype=int)]
        else:
            shape_data = self.original_data[shape_index]
            shape_data[np.isnan(shape_data)] = len(self.CurveSymbols) - 1
            shape_data = self.CurveSymbols[shape_data.astype(int)]
        return shape_data

    def update_shapes(self):
        if self.scatterplot_item:
            shape_data = self.compute_symbols()
            self.scatterplot_item.setSymbol(shape_data)
        self.make_legend()

    def update_grid(self):
        self.plot_widget.showGrid(x=self.show_grid, y=self.show_grid)

    def update_legend(self):
        if self.legend:
            self.legend.setVisible(self.show_legend)

    def create_legend(self):
        self.legend = PositionedLegendItem(self.plot_widget.plotItem, self)

    def remove_legend(self):
        if self.legend:
            self.legend.setParent(None)
            self.legend = None
        if self.color_legend:
            self.color_legend.setParent(None)
            self.color_legend = None

    def make_legend(self):
        self.remove_legend()
        self.make_color_legend()
        self.make_shape_legend()
        self.update_legend()

    def make_color_legend(self):
        color_index = self.get_color_index()
        if color_index == -1:
            return
        color_var = self.data_domain[color_index]
        use_shape = self.get_shape_index() == color_index
        if isinstance(color_var, DiscreteVariable):
            if not self.legend:
                self.create_legend()
            palette = self.discrete_palette
            for i, value in enumerate(color_var.values):
                color = QColor(*palette.getRGB(i))
                brush = color.lighter(self.DarkerValue)
                self.legend.addItem(
                    ScatterPlotItem(
                        pen=color, brush=brush, size=10,
                        symbol=self.CurveSymbols[i] if use_shape else "o"),
                    value)
        else:
            legend = self.color_legend = PositionedLegendItem(
                self.plot_widget.plotItem,
                self, legend_id="colors", at_bottom=True)
            label = PaletteItemSample(self.continuous_palette, self.scale)
            legend.addItem(label, "")
            legend.setGeometry(label.boundingRect())

    def make_shape_legend(self):
        shape_index = self.get_shape_index()
        if shape_index == -1 or shape_index == self.get_color_index():
            return
        if not self.legend:
            self.create_legend()
        shape_var = self.data_domain[shape_index]
        color = self.plot_widget.palette().color(OWPalette.Data)
        pen = QPen(color.darker(self.DarkerValue))
        color.setAlpha(self.alpha_value)
        for i, value in enumerate(shape_var.values):
            self.legend.addItem(
                ScatterPlotItem(pen=pen, brush=color, size=10,
                                symbol=self.CurveSymbols[i]), value)

    # noinspection PyPep8Naming
    def mouseMoved(self, pos):
        act_pos = self.scatterplot_item.mapFromScene(pos)
        points = self.scatterplot_item.pointsAt(act_pos)
        text = ""
        if len(points):
            for i, p in enumerate(points):
                index = p.data()
                text += "Attributes:\n"
                if self.tooltip_shows_all:
                    text += "".join(
                        '   {} = {}\n'.format(attr.name,
                                              self.raw_data[index][attr])
                        for attr in self.data_domain.attributes)
                else:
                    text += '   {} = {}\n   {} = {}\n'.format(
                        self.shown_x, self.raw_data[index][self.shown_x],
                        self.shown_y, self.raw_data[index][self.shown_y])
                if self.data_domain.class_var:
                    text += 'Class:\n   {} = {}\n'.format(
                        self.data_domain.class_var.name,
                        self.raw_data[index][self.raw_data.domain.class_var])
                if i < len(points) - 1:
                    text += '------------------\n'
            self.tooltip.setText(text, color=(0, 0, 0))
            self.tooltip.setPos(act_pos)
            self.tooltip.show()
            self.tooltip.setZValue(10)
        else:
            self.tooltip.hide()

    def zoom_button_clicked(self):
        self.scatterplot_item.getViewBox().setMouseMode(
            self.scatterplot_item.getViewBox().RectMode)

    def pan_button_clicked(self):
        self.scatterplot_item.getViewBox().setMouseMode(
            self.scatterplot_item.getViewBox().PanMode)

    def select_button_clicked(self):
        self.scatterplot_item.getViewBox().setMouseMode(
            self.scatterplot_item.getViewBox().RectMode)

    def reset_button_clicked(self):
        self.view_box.autoRange()

    def select_by_click(self, _, points):
        self.select(points)

    def select_by_rectangle(self, value_rect):
        points = [point
                  for point in self.scatterplot_item.points()
                  if value_rect.contains(QPointF(point.pos()))]
        self.select(points)

    def unselect_all(self):
        self.selection = None
        self.update_colors(keep_colors=True)

    def select(self, points):
        # noinspection PyArgumentList
        keys = QApplication.keyboardModifiers()
        if self.selection is None or not keys & (
                        Qt.ShiftModifier + Qt.ControlModifier + Qt.AltModifier):
            self.selection = np.full(self.n_points, False, dtype=np.bool)
        indices = [p.data() for p in points]
        if keys & Qt.ControlModifier:
            self.selection[indices] = False
        elif keys & Qt.AltModifier:
            self.selection[indices] = 1 - self.selection[indices]
        else:  # Handle shift and no modifiers
            self.selection[indices] = True
        self.update_colors(keep_colors=True)
        self.master.selection_changed()

    def get_selection(self):
        if self.selection is None:
            return np.array([], dtype=int)
        else:
            return np.arange(len(self.raw_data)
                )[self.valid_data][self.selection]

    def set_palette(self, p):
        self.plot_widget.setPalette(p)

    def save_to_file(self, size):
        pass