Пример #1
0
class PlotWindow(DataWindow, Ui_plotWindow):
    """Window to display 2D plots"""
    def __init__(self, parent=None):
        DataWindow.__init__(self, parent)
        self.plot = pyqtgraph.PlotWidget(self.plotFrame, antialiasing=True)
        self.plot.hideAxis('bottom')
        self.legend = self.plot.addLegend()
        self.legend.hide()
        self._finish_layout()
        self.actionLegend_Box.triggered.connect(self.on_view_legend_box)
        self.actionX_axis.triggered.connect(self.on_view_x_axis)
        self.actionY_axis.triggered.connect(self.on_view_y_axis)
        self.acceptable_data_types = ['scalar', 'vector', 'tuple', 'triple', 'running_hist', 'histogram' , 'normalized_histogram']
        self.exclusive_source = False
        self.line_colors = [(252, 175, 62), (114, 159, 207), (255, 255, 255),
                            (239, 41, 41), (138, 226, 52), (173, 127, 168)]
        self.colorbar = None
        self.colormap = None
        self.current_index = -1
        self.last_vector_y = {}
        self.last_vector_x = None
        self.hline = None
        self.vline = None
        self.hline_color = (0,204,0)
        self.vline_color = (204,0,0)
        self._settings_diag = LinePlotSettings(self)
        self._histograms = {}
        self._normalized_histograms = {}
        self.updateFonts()

        self.plot.scene().sigMouseMoved.connect(self._onMouseMoved)

    def on_view_legend_box(self):
        """Show/hide legend box"""
        action = self.sender()
        if(action.isChecked()):
            self.legend.show()
        else:
            self.legend.hide()

    def on_view_x_axis(self):
        """Show/hide X axis"""
        action = self.sender()
        if(action.isChecked()):
            self.plot.showAxis('bottom')
        else:
            self.plot.hideAxis('bottom')

    def on_view_y_axis(self):
        """Show/hide Y axis"""
        action = self.sender()
        if(action.isChecked()):
            self.plot.showAxis('left')
        else:
            self.plot.hideAxis('left')

    def _on_plot_settings(self):
        """Show the plot settings dialog"""
        self._settings_diag.histAutorange.toggled.connect(self._on_histogram_autorange)
        if(self._settings_diag.exec_()):
            self._settings_diag._read_bg_file()
            # Show changes immediately
            self.replot()

    def _on_histogram_autorange(self, checked):
        if checked:
            self._settings_diag.histMin.setEnabled(False)
            self._settings_diag.histMax.setEnabled(False)
        else:
            self._settings_diag.histMin.setEnabled(True)
            self._settings_diag.histMax.setEnabled(True)

    def get_time(self, index=None):
        """Returns the time of the given index, or the time of the last data point"""
        if index is None:
            index = self.current_index
        # Check if we have last_vector
        if (self.last_vector_x is not None):
            dt = datetime.datetime.fromtimestamp(self.last_vector_x[index])
            return dt

        # Check if we have enabled_sources
        source = None
        if(self._enabled_sources):
            for ds in self._enabled_sources.keys():
                if(len(self._enabled_sources[ds])):
                    title = self._enabled_sources[ds][0]
                    source = ds
                    break

        # There might be no data yet, so no plotdata
        if(source is not None and title in source.plotdata and
           source.plotdata[title].x is not None):
            pd = source.plotdata[title]
            dt = datetime.datetime.fromtimestamp(pd.x[index])
            return dt
        else:
            return datetime.datetime.now()
            
    def _configure_axis(self, source, title, hist=False):
        """Configures the x and y axis of the plot, according to the
        source/title configuration and content type"""
        conf = source.conf[title]
        if(self.actionX_axis.isChecked()):
            if 'xlabel' in conf and self._settings_diag.x_auto.isChecked():
                self._settings_diag.x_label.setText(conf['xlabel'])
            if hist:
                self.plot.setLabel('bottom', self._settings_diag.y_label.text())
            else:
                self.plot.setLabel('bottom', self._settings_diag.x_label.text())
        if(self.actionY_axis.isChecked()):
            if 'ylabel' in conf and self._settings_diag.y_auto.isChecked():
                self._settings_diag.y_label.setText(conf['ylabel'])
            if hist:
                self.plot.setLabel('left', 'Counts')
            else:
                self.plot.setLabel('left', self._settings_diag.y_label.text())

    def _set_range(self, xmin, xmax, ymin, ymax):
        if not self._settings_diag.xlimits_auto.isChecked():
            try:
                xmin = float(str(self._settings_diag.xmin.text()))
            except ValueError:
                pass
            try:
                xmax = float(str(self._settings_diag.xmax.text()))
            except ValueError:
                pass
        if not self._settings_diag.ylimits_auto.isChecked():
            try:
                ymin = float(str(self._settings_diag.ymin.text()))
            except ValueError:
                pass
            try:
                ymax = float(str(self._settings_diag.ymax.text()))
            except ValueError:
                pass
        if (xmax - xmin) == 0.:
            xmin -= 0.1
            xmax += 0.1
        if (ymax - ymin) == 0.:
            ymin -= 0.1
            ymax += 0.1
        self.plot.setRange(xRange=(xmin, xmax), yRange=(ymin, ymax))    
            
    def replot(self):
        """Replot data"""
        self.plot.clear()

        # Init background if defined in a data source
        if self._settings_diag.bg is None:
            alert_flag = False
            for source, title in self.source_and_titles():
                conf = source.conf[title]
                if "bg_filename" in conf:
                    conf_bg = {}
                    for k,v in conf.items():
                        if k.startswith("bg_"):
                            conf_bg[k] = v
                    self._settings_diag._configure_bg(**conf_bg)
                    # Use only first if there are many
                    break

        alert_flag = False
        for source, title in self.source_and_titles():
            conf = source.conf[title]
            if "alert" in conf and self.actionToggleAlert.isChecked() and conf['alert']:
                alert_flag = True

        if alert_flag:
            os.system('afplay -v %f src/interface/ui/sounds/%s.wav &' %(self.volume,self.sound))
            if not self.alertBlinkTimer.isActive():
                self.alertBlinkTimer.start()
        else:
            if self.alertBlinkTimer.isActive():
                self.alertBlinkTimer.stop()
                self.setStyleSheet("")



        # Load background if configured
        self._update_bg()
            
        color_index = 0
        titlebar = []
        self.plot.plotItem.legend.items = []

        xmins = []
        xmaxs = []
        ymins = []
        ymaxs = []
        
        for source, title in self.source_and_titles():
            
            if(title not in source.plotdata or source.plotdata[title].y is None):
                continue
            pd = source.plotdata[title]
            titlebar.append(pd.title)

            conf = source.conf[title]

            color = self.line_colors[color_index % len(self.line_colors)]
            pen = None
            symbol = None
            symbol_pen = None
            symbol_brush = None
            symbol_size = None
            histoangle = 0

            if(self.actionLines.isChecked()):
                pen = color
            if(self.actionPoints.isChecked()):
                symbol = 'o'
                symbol_pen = color
                symbol_brush = color
                symbol_size = 3
            
            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                y = numpy.array(pd.y, copy=False)
                self.last_vector_y = {}
                self.last_vector_x = None
            elif(source.data_type[title] == 'tuple'):
                y = pd.y[:,1]
                symbol_brush = (255,255,255,120)
                symbol_pen = None
                symbol_size = 8
            elif(source.data_type[title] == 'triple'):
                if self.colormap is None:
                    vmin, vmax = (0,1)
                    if 'vmin' in conf:
                        vmin = conf['vmin']
                    if 'vmax' in conf:
                        vmax = conf['vmax']
                    stops = numpy.r_[vmin, vmax]
                    colors = numpy.array([[0, 0, 1, 0.7], [1, 0, 0, 1.0]])
                    self.colormap = pyqtgraph.ColorMap(stops, colors)
                if 'zlabel' in conf:
                    zlabel = conf['zlabel']
                else:
                    zlabel = 'z'
                if self.colorbar is not None:
                    self.plot.scene().removeItem(self.colorbar)
                self.colorbar = ColorBar(self.colormap, 10, 200, label=zlabel)
                self.plot.scene().addItem(self.colorbar)
                self.actionPoints.setChecked(1)
                self.actionLines.setChecked(0)
                self.colorbar.translate(self.geometry().width() - self.colorbar.zone[2], 20.0)
                y = pd.y[:,1]
                z = pd.y[:,2]
                symbol_brush = self.colormap.map(z, 'qcolor')
                symbol_pen   = None
                symbol_size  = 8
            elif source.data_type[title] == 'vector':
                if(self.current_index == -1):
                    y = numpy.array(pd.y[self.current_index % pd.y.shape[0]], copy=False)
                    self.last_vector_y[title] = numpy.array(pd.y)
                    self.last_vector_x = numpy.array(pd.x)
                else:
                    y = self.last_vector_y[title][self.current_index % self.last_vector_y[title].shape[0]]
            elif source.data_type[title] == 'histogram':
                if title not in self._histograms:
                    self._histograms[title] = Histogram(conf["hmin"], conf["hmax"], conf["bins"])
                x = self._histograms[title].values_x
                y = self._histograms[title].values_y
            elif source.data_type[title] == 'normalized_histogram':
                if title not in self._normalized_histograms:
                    self._normalized_histograms[title] = NormalizedHistogram(conf["hmin"], conf["hmax"],
                                                                    conf["bins"])
                x = self._normalized_histograms[title].values_x
                y = self._normalized_histograms[title].values_y
                
            x = None
            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                x = numpy.array(pd.x, copy=False)
                sorted_x = numpy.argsort(x)
                x = x[sorted_x]
                y = y[sorted_x]
                if self._settings_diag.showTrendScalar.isChecked():
                    wl = int(self._settings_diag.windowLength.text())
                    y = utils.array.runningMean(y, min(y.size-1,wl))
                    x = x[-y.size:]
            elif(source.data_type[title] == 'tuple') or (source.data_type[title] == 'triple'):
                x = pd.y[:,0]
            elif(source.data_type[title] == 'vector'):
                if len(y.shape) == 2:
                    x = y[0,:]
                    y = y[1,:]
                else:
                    if 'xmin' in conf and 'xmax' in conf:
                        xmin = conf['xmin']
                        xmax = conf['xmax']
                    else:
                        xmin = 0
                        xmax = source.plotdata[title].y.shape[-1] + xmin
                    x = numpy.linspace(xmin,xmax, y.shape[-1])
            if(self._settings_diag.histogram.isChecked()):
                bins = int(self._settings_diag.histBins.text())
                histMode = self._settings_diag.histMode.currentText()
                if (self._settings_diag.histAutorange.isChecked()):
                    hmin, hmax = y.min(), y.max()
                    self._settings_diag.histMin.setText("%.2f"%hmin)
                    self._settings_diag.histMax.setText("%.2f"%hmax)
                else:
                    hmin = float(self._settings_diag.histMin.text())
                    hmax = float(self._settings_diag.histMax.text())
                if histMode == 'count':
                    y,x = numpy.histogram(y, range=(hmin, hmax), bins=bins)
                elif histMode == 'mean':
                    num,x = numpy.histogram(y, range=(hmin, hmax), bins=bins, weights=x)
                    den,x = numpy.histogram(y, range=(hmin, hmax), bins=bins)
                    y = num/(den+1e-20)
                x = (x[:-1]+x[1:])/2.0
                histoangle = 90
                self._configure_axis(source, title, hist=True)
            elif(source.data_type[title] == "histogram"):
                ringbuffer = pd.y
                # Clear histogram if asked for
                if pd.clear_histogram:
                    self._histograms[title].reset()
                    pd.clear_histogram = False
                self._histograms[title].add_values_from_ringbuffer(ringbuffer)
                x = self._histograms[title].values_x
                y = self._histograms[title].values_y
            elif(source.data_type[title] == "normalized_histogram"):
                ringbuffer = pd.y
                # Clear histogram if asked for
                print("clear_histograms = {0}".format(pd.clear_histograms))
                if pd.clear_histograms:
                    self._histograms[title].reset()
                    pd.clear_histograms = False
                self._normalized_histograms[title].add_values_from_ringbuffer(ringbuffer)
                x = self._normalized_histograms[title].values_x
                y = self._normalized_histograms[title].values_y
            else:
                self._configure_axis(source, title)
            self.plot.setLogMode(x=self._settings_diag.logx.isChecked(),
                                 y=self._settings_diag.logy.isChecked())

            if self._settings_diag.showMainLine.isChecked():
                plt = self.plot.plot(x=x, y=y, clear=False, pen=pen, symbol=symbol,
                                 symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)
                self.legend.addItem(plt, pd.title)

            if 'hline' in conf and conf['hline'] is not None:
                self.plot.getPlotItem().removeItem(self.hline)
                self.hline = pyqtgraph.InfiniteLine(angle=0 + histoangle, movable=False, pen=self.hline_color)
                self.plot.getPlotItem().addItem(self.hline)
                self.hline.setPos(conf['hline'])

            if 'vline' in conf and conf['vline'] is not None:
                self.plot.getPlotItem().removeItem(self.vline)
                self.vline = pyqtgraph.InfiniteLine(angle=90 + histoangle, movable=False, pen=self.vline_color)
                self.plot.getPlotItem().addItem(self.vline)
                self.vline.setPos(conf['vline'])

            xmins.append(x.min())
            xmaxs.append(x.max())
            ymins.append(y.min())
            ymaxs.append(y.max())
            
            color_index += 1
            
            if (source.data_type[title] == 'vector') and (self._settings_diag.showTrendVector.isChecked()):
                for trend in ['mean', 'median', 'std', 'min', 'max']:
                    if eval('self._settings_diag.trendVector_%s.isChecked()' %trend):
                        _trend = getattr(numpy, trend)
                        if len(pd.y.shape) == 3:
                            ytrend = _trend(numpy.array(pd.y[:,1,:], copy=False), axis=0)
                        else:
                            ytrend = _trend(numpy.array(pd.y, copy=False), axis=0)
                        plt_trend = self.plot.plot(x=x, y=ytrend, clear=False, pen=self.line_colors[color_index % len(self.line_colors)], symbol=symbol,
                                                   symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)
                        self.legend.addItem(plt_trend, trend)
                        color_index += 1


        self.setWindowTitle(", ".join(titlebar))
        dt = self.get_time()
        # Round to miliseconds
        self.timeLabel.setText('%02d:%02d:%02d.%03d' % (dt.hour, dt.minute, dt.second, dt.microsecond/1000))
        self.dateLabel.setText(str(dt.date()))

        # Set ranges
        if len(xmins) > 0:
            self._set_range(min(xmins), max(xmaxs), min(ymins), max(ymaxs))
        
        # Various options
        if self._settings_diag.aspect_locked.isChecked():
            self.plot.getViewBox().setAspectLocked()
        if self._settings_diag.flip_x.isChecked():
            self.plot.getViewBox().invertX()
        if self._settings_diag.flip_y.isChecked():
            self.plot.getViewBox().invertY()

    def _change_index_by(self, amount):
        """Changes the history index when displaying a vector"""
        if self.last_vector_x is None:
            return
        self.current_index += amount
        if(self.current_index > -1):
            self.current_index = -1
        if(self.current_index < -len(self.last_vector_x)):
            self.current_index = -len(self.last_vector_x)

    def keyPressEvent(self, event):
        """Handle key presses"""
        key = event.key()
        if key == QtCore.Qt.Key_Right:
            self._change_index_by(1)
            self.replot()
        elif key == QtCore.Qt.Key_Left:
            self._change_index_by(-1)
            self.replot()

    def get_state(self, _settings = None):
        """Returns settings that can be used to restore the widget to the current state"""
        settings = _settings or {}
        settings['window_type'] = 'PlotWindow'
        settings['viewbox'] = self.plot.getViewBox().getState()
        settings['x_view'] = self.actionX_axis.isChecked()
        settings['y_view'] = self.actionY_axis.isChecked()
        settings['lines'] = self.actionLines.isChecked()
        settings['points'] = self.actionPoints.isChecked()
        settings['legend'] = self.actionLegend_Box.isChecked()
        settings = self._settings_diag.get_state(settings)
        return DataWindow.get_state(self, settings)

    def restore_from_state(self, settings, data_sources):
        self._settings_diag.restore_from_state(settings)
        self.plot.getViewBox().setState(settings['viewbox'])
        self.actionX_axis.setChecked(settings['x_view'])
        self.actionX_axis.triggered.emit(settings['x_view'])
        self.actionY_axis.setChecked(settings['y_view'])
        self.actionY_axis.triggered.emit(settings['y_view'])
        self.actionLines.setChecked(settings['lines'])
        self.actionPoints.setChecked(settings['points'])
        self.actionLegend_Box.setChecked(settings['legend'])
        self.actionLegend_Box.triggered.emit(settings['legend'])
        return DataWindow.restore_from_state(self, settings, data_sources)
    
    def _update_bg(self):
        if self._settings_diag.bg is not None:
            VB = self.plot.getViewBox()
            B = pyqtgraph.ImageItem(image=self._settings_diag.bg, autoLevels=True)
            xmin = float(self._settings_diag.bg_xmin.text())
            ymin = float(self._settings_diag.bg_xmin.text())
            width  = float(self._settings_diag.bg_xmax.text()) - xmin
            height = float(self._settings_diag.bg_ymax.text()) - ymin
            rect = QtCore.QRectF(xmin, ymin, width, height)
            B.setRect(rect)
            VB.addItem(B, ignoreBounds=True)


    def updateFonts(self):
        f = self.title.font()
        size = int(self.settings.value("plotFontSize"))
        f.setPointSize(size)
        self.title.setFont(f)

        f = QtGui.QFont()
        f.setPointSize(size)
        ax = self.plot.getAxis('left')
        ax.setTickFont(f)
        ax = self.plot.getAxis('bottom')
        ax.setTickFont(f)

    def _onMouseMoved(self, pos):
        view = self.plot
        xy = view.mapToView(pos)
        x = xy.x()
        y = xy.y()
        self.xLabel.setText("%f" % (x))
        self.yLabel.setText("%f" % (y))
Пример #2
0
    def replot(self):
        """Replot data"""
        self.plot.clear()

        # Init background if defined in a data source
        if self._settings_diag.bg is None:
            alert_flag = False
            for source, title in self.source_and_titles():
                conf = source.conf[title]
                if "bg_filename" in conf:
                    conf_bg = {}
                    for k,v in conf.items():
                        if k.startswith("bg_"):
                            conf_bg[k] = v
                    self._settings_diag._configure_bg(**conf_bg)
                    # Use only first if there are many
                    break

        alert_flag = False
        for source, title in self.source_and_titles():
            conf = source.conf[title]
            if "alert" in conf and self.actionToggleAlert.isChecked() and conf['alert']:
                alert_flag = True

        if alert_flag:
            os.system('afplay -v %f src/interface/ui/sounds/%s.wav &' %(self.volume,self.sound))
            if not self.alertBlinkTimer.isActive():
                self.alertBlinkTimer.start()
        else:
            if self.alertBlinkTimer.isActive():
                self.alertBlinkTimer.stop()
                self.setStyleSheet("")



        # Load background if configured
        self._update_bg()
            
        color_index = 0
        titlebar = []
        self.plot.plotItem.legend.items = []

        xmins = []
        xmaxs = []
        ymins = []
        ymaxs = []
        
        for source, title in self.source_and_titles():
            
            if(title not in source.plotdata or source.plotdata[title].y is None):
                continue
            pd = source.plotdata[title]
            titlebar.append(pd.title)

            conf = source.conf[title]

            color = self.line_colors[color_index % len(self.line_colors)]
            pen = None
            symbol = None
            symbol_pen = None
            symbol_brush = None
            symbol_size = None
            histoangle = 0

            if(self.actionLines.isChecked()):
                pen = color
            if(self.actionPoints.isChecked()):
                symbol = 'o'
                symbol_pen = color
                symbol_brush = color
                symbol_size = 3
            
            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                y = numpy.array(pd.y, copy=False)
                self.last_vector_y = {}
                self.last_vector_x = None
            elif(source.data_type[title] == 'tuple'):
                y = pd.y[:,1]
                symbol_brush = (255,255,255,120)
                symbol_pen = None
                symbol_size = 8
            elif(source.data_type[title] == 'triple'):
                if self.colormap is None:
                    vmin, vmax = (0,1)
                    if 'vmin' in conf:
                        vmin = conf['vmin']
                    if 'vmax' in conf:
                        vmax = conf['vmax']
                    stops = numpy.r_[vmin, vmax]
                    colors = numpy.array([[0, 0, 1, 0.7], [1, 0, 0, 1.0]])
                    self.colormap = pyqtgraph.ColorMap(stops, colors)
                if 'zlabel' in conf:
                    zlabel = conf['zlabel']
                else:
                    zlabel = 'z'
                if self.colorbar is not None:
                    self.plot.scene().removeItem(self.colorbar)
                self.colorbar = ColorBar(self.colormap, 10, 200, label=zlabel)
                self.plot.scene().addItem(self.colorbar)
                self.actionPoints.setChecked(1)
                self.actionLines.setChecked(0)
                self.colorbar.translate(self.geometry().width() - self.colorbar.zone[2], 20.0)
                y = pd.y[:,1]
                z = pd.y[:,2]
                symbol_brush = self.colormap.map(z, 'qcolor')
                symbol_pen   = None
                symbol_size  = 8
            elif source.data_type[title] == 'vector':
                if(self.current_index == -1):
                    y = numpy.array(pd.y[self.current_index % pd.y.shape[0]], copy=False)
                    self.last_vector_y[title] = numpy.array(pd.y)
                    self.last_vector_x = numpy.array(pd.x)
                else:
                    y = self.last_vector_y[title][self.current_index % self.last_vector_y[title].shape[0]]
            elif source.data_type[title] == 'histogram':
                if title not in self._histograms:
                    self._histograms[title] = Histogram(conf["hmin"], conf["hmax"], conf["bins"])
                x = self._histograms[title].values_x
                y = self._histograms[title].values_y
            elif source.data_type[title] == 'normalized_histogram':
                if title not in self._normalized_histograms:
                    self._normalized_histograms[title] = NormalizedHistogram(conf["hmin"], conf["hmax"],
                                                                    conf["bins"])
                x = self._normalized_histograms[title].values_x
                y = self._normalized_histograms[title].values_y
                
            x = None
            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                x = numpy.array(pd.x, copy=False)
                sorted_x = numpy.argsort(x)
                x = x[sorted_x]
                y = y[sorted_x]
                if self._settings_diag.showTrendScalar.isChecked():
                    wl = int(self._settings_diag.windowLength.text())
                    y = utils.array.runningMean(y, min(y.size-1,wl))
                    x = x[-y.size:]
            elif(source.data_type[title] == 'tuple') or (source.data_type[title] == 'triple'):
                x = pd.y[:,0]
            elif(source.data_type[title] == 'vector'):
                if len(y.shape) == 2:
                    x = y[0,:]
                    y = y[1,:]
                else:
                    if 'xmin' in conf and 'xmax' in conf:
                        xmin = conf['xmin']
                        xmax = conf['xmax']
                    else:
                        xmin = 0
                        xmax = source.plotdata[title].y.shape[-1] + xmin
                    x = numpy.linspace(xmin,xmax, y.shape[-1])
            if(self._settings_diag.histogram.isChecked()):
                bins = int(self._settings_diag.histBins.text())
                histMode = self._settings_diag.histMode.currentText()
                if (self._settings_diag.histAutorange.isChecked()):
                    hmin, hmax = y.min(), y.max()
                    self._settings_diag.histMin.setText("%.2f"%hmin)
                    self._settings_diag.histMax.setText("%.2f"%hmax)
                else:
                    hmin = float(self._settings_diag.histMin.text())
                    hmax = float(self._settings_diag.histMax.text())
                if histMode == 'count':
                    y,x = numpy.histogram(y, range=(hmin, hmax), bins=bins)
                elif histMode == 'mean':
                    num,x = numpy.histogram(y, range=(hmin, hmax), bins=bins, weights=x)
                    den,x = numpy.histogram(y, range=(hmin, hmax), bins=bins)
                    y = num/(den+1e-20)
                x = (x[:-1]+x[1:])/2.0
                histoangle = 90
                self._configure_axis(source, title, hist=True)
            elif(source.data_type[title] == "histogram"):
                ringbuffer = pd.y
                # Clear histogram if asked for
                if pd.clear_histogram:
                    self._histograms[title].reset()
                    pd.clear_histogram = False
                self._histograms[title].add_values_from_ringbuffer(ringbuffer)
                x = self._histograms[title].values_x
                y = self._histograms[title].values_y
            elif(source.data_type[title] == "normalized_histogram"):
                ringbuffer = pd.y
                # Clear histogram if asked for
                print("clear_histograms = {0}".format(pd.clear_histograms))
                if pd.clear_histograms:
                    self._histograms[title].reset()
                    pd.clear_histograms = False
                self._normalized_histograms[title].add_values_from_ringbuffer(ringbuffer)
                x = self._normalized_histograms[title].values_x
                y = self._normalized_histograms[title].values_y
            else:
                self._configure_axis(source, title)
            self.plot.setLogMode(x=self._settings_diag.logx.isChecked(),
                                 y=self._settings_diag.logy.isChecked())

            if self._settings_diag.showMainLine.isChecked():
                plt = self.plot.plot(x=x, y=y, clear=False, pen=pen, symbol=symbol,
                                 symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)
                self.legend.addItem(plt, pd.title)

            if 'hline' in conf and conf['hline'] is not None:
                self.plot.getPlotItem().removeItem(self.hline)
                self.hline = pyqtgraph.InfiniteLine(angle=0 + histoangle, movable=False, pen=self.hline_color)
                self.plot.getPlotItem().addItem(self.hline)
                self.hline.setPos(conf['hline'])

            if 'vline' in conf and conf['vline'] is not None:
                self.plot.getPlotItem().removeItem(self.vline)
                self.vline = pyqtgraph.InfiniteLine(angle=90 + histoangle, movable=False, pen=self.vline_color)
                self.plot.getPlotItem().addItem(self.vline)
                self.vline.setPos(conf['vline'])

            xmins.append(x.min())
            xmaxs.append(x.max())
            ymins.append(y.min())
            ymaxs.append(y.max())
            
            color_index += 1
            
            if (source.data_type[title] == 'vector') and (self._settings_diag.showTrendVector.isChecked()):
                for trend in ['mean', 'median', 'std', 'min', 'max']:
                    if eval('self._settings_diag.trendVector_%s.isChecked()' %trend):
                        _trend = getattr(numpy, trend)
                        if len(pd.y.shape) == 3:
                            ytrend = _trend(numpy.array(pd.y[:,1,:], copy=False), axis=0)
                        else:
                            ytrend = _trend(numpy.array(pd.y, copy=False), axis=0)
                        plt_trend = self.plot.plot(x=x, y=ytrend, clear=False, pen=self.line_colors[color_index % len(self.line_colors)], symbol=symbol,
                                                   symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)
                        self.legend.addItem(plt_trend, trend)
                        color_index += 1


        self.setWindowTitle(", ".join(titlebar))
        dt = self.get_time()
        # Round to miliseconds
        self.timeLabel.setText('%02d:%02d:%02d.%03d' % (dt.hour, dt.minute, dt.second, dt.microsecond/1000))
        self.dateLabel.setText(str(dt.date()))

        # Set ranges
        if len(xmins) > 0:
            self._set_range(min(xmins), max(xmaxs), min(ymins), max(ymaxs))
        
        # Various options
        if self._settings_diag.aspect_locked.isChecked():
            self.plot.getViewBox().setAspectLocked()
        if self._settings_diag.flip_x.isChecked():
            self.plot.getViewBox().invertX()
        if self._settings_diag.flip_y.isChecked():
            self.plot.getViewBox().invertY()
Пример #3
0
    def replot(self):
        """Replot data"""
        self.plot.clear()
        color_index = 0
        titlebar = []
        self.plot.plotItem.legend.items = []
        for source, title in self.source_and_titles():
            if(title not in source.plotdata or source.plotdata[title].y is None):
                continue
            pd = source.plotdata[title]
            titlebar.append(pd.title)

            color = self.line_colors[color_index % len(self.line_colors)]
            pen = None
            symbol = None
            symbol_pen = None
            symbol_brush = None
            symbol_size = None
            if(self.actionLines.isChecked()):
                pen = color
            if(self.actionPoints.isChecked()):
                symbol = 'o'
                symbol_pen = color
                symbol_brush = color
                symbol_size = 3

            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                y = numpy.array(pd.y, copy=False)
                self.last_vector_y = {}
                self.last_vector_x = None
            elif(source.data_type[title] == 'tuple'):
                y = pd.y[:,1]
                symbol_brush = (255,255,255,120)
                symbol_pen = None
                symbol_size = 8
            elif(source.data_type[title] == 'triple'):
                conf = source.conf[title]
                if self.colormap is None:
                    vmin, vmax = (0,1)
                    if 'vmin' in conf:
                        vmin = conf['vmin']
                    if 'vmax' in conf:
                        vmax = conf['vmax']
                    stops = numpy.r_[vmin, vmax]
                    colors = numpy.array([[0, 0, 1, 0.7], [1, 0, 0, 1.0]])
                    self.colormap = pyqtgraph.ColorMap(stops, colors)
                if 'zlabel' in conf:
                    zlabel = conf['zlabel']
                else:
                    zlabel = 'z'
                if self.colorbar is not None:
                    self.plot.scene().removeItem(self.colorbar)
                self.colorbar = ColorBar(self.colormap, 10, 200, label=zlabel)
                self.plot.scene().addItem(self.colorbar)
                self.actionPoints.setChecked(1)
                self.actionLines.setChecked(0)
                self.colorbar.translate(self.geometry().width() - self.colorbar.zone[2], 20.0)
                y = pd.y[:,1]
                z = pd.y[:,2]
                symbol_brush = self.colormap.map(z, 'qcolor')
                symbol_pen   = None
                symbol_size  = 8
            elif source.data_type[title] == 'vector':
                if(self.current_index == -1):
                    y = numpy.array(pd.y[self.current_index % pd.y.shape[0]], copy=False)
                    self.last_vector_y[title] = numpy.array(pd.y)
                    self.last_vector_x = numpy.array(pd.x)
                else:
                    y = self.last_vector_y[title][self.current_index % self.last_vector_y[title].shape[0]]

            x = None
            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                x = numpy.array(pd.x, copy=False)
                sorted_x = numpy.argsort(x)
                x = x[sorted_x]
                y = y[sorted_x]
                if self._settings_diag.showTrendScalar.isChecked():
                    wl = int(self._settings_diag.windowLength.text())
                    y = utils.array.runningMean(y, wl)
                    x = x[-max(len(y),1):]
                self._configure_ylimits(source, title)
            elif(source.data_type[title] == 'tuple') or (source.data_type[title] == 'triple'):
                x = pd.y[:,0]
            elif(source.data_type[title] == 'vector'):
                if len(y.shape) == 2:
                    x = y[0,:]
                    y = y[1,:]
                else:
                    xmin, xmax = self._configure_xlimits(source, title)
                    x = numpy.linspace(xmin,xmax, y.shape[-1])
            if(self._settings_diag.histogram.isChecked()):
                bins = int(self._settings_diag.histBins.text())
                if (self._settings_diag.histAutorange.isChecked()):
                    hmin, hmax = y.min(), y.max()
                    self._settings_diag.histMin.setText("%.2f"%hmin)
                    self._settings_diag.histMax.setText("%.2f"%hmax)
                else:
                    hmin = float(self._settings_diag.histMin.text())
                    hmax = float(self._settings_diag.histMax.text())
                y,x = numpy.histogram(y, range=(hmin, hmax), bins=bins)
                x = (x[:-1]+x[1:])/2.0
                self._configure_axis(source, title, hist=True)
            else:
                self._configure_axis(source, title)
            self.plot.setLogMode(x=self._settings_diag.logx.isChecked(),
                                 y=self._settings_diag.logy.isChecked())

            plt = self.plot.plot(x=x, y=y, clear=False, pen=pen, symbol=symbol,
                                 symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)

            self.legend.addItem(plt, pd.title)
            color_index += 1
            
            if (source.data_type[title] == 'vector') and (self._settings_diag.showTrendVector.isChecked()):
                for trend in ['mean', 'median', 'std', 'min', 'max']:
                    if eval('self._settings_diag.trendVector_%s.isChecked()' %trend):
                        _trend = getattr(numpy, trend)
                        if len(pd.y.shape) == 3:
                            ytrend = _trend(numpy.array(pd.y[:,1,:], copy=False), axis=0)
                        else:
                            ytrend = _trend(numpy.array(pd.y, copy=False), axis=0)
                        plt_trend = self.plot.plot(x=x, y=ytrend, clear=False, pen=self.line_colors[color_index % len(self.line_colors)], symbol=symbol,
                                                   symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)
                        self.legend.addItem(plt_trend, trend)
                        color_index += 1


        self.setWindowTitle(", ".join(titlebar))
        dt = self.get_time()
        # Round to miliseconds
        self.timeLabel.setText('%02d:%02d:%02d.%03d' % (dt.hour, dt.minute, dt.second, dt.microsecond/1000))
        self.dateLabel.setText(str(dt.date()))
Пример #4
0
class PlotWindow(DataWindow, Ui_plotWindow):
    """Window to display 2D plots"""
    def __init__(self, parent=None):
        DataWindow.__init__(self, parent)
        self.plot = pyqtgraph.PlotWidget(self.plotFrame, antialiasing=True)
        self.plot.hideAxis('bottom')
        self.legend = self.plot.addLegend()
        self.legend.hide()
        self._finish_layout()
        self.actionLegend_Box.triggered.connect(self.on_view_legend_box)
        self.actionX_axis.triggered.connect(self.on_view_x_axis)
        self.actionY_axis.triggered.connect(self.on_view_y_axis)
        self.acceptable_data_types = ['scalar', 'vector', 'tuple', 'triple', 'running_hist' ]
        self.exclusive_source = False
        self.line_colors = [(252, 175, 62), (114, 159, 207), (255, 255, 255),
                            (239, 41, 41), (138, 226, 52), (173, 127, 168)]
        self.colorbar = None
        self.colormap = None
        self.current_index = -1
        self.last_vector_y = {}
        self.last_vector_x = None
        self._settings_diag = LinePlotSettings(self)
        self.x_auto = True
        self.y_auto = True
        self.x_label = ''
        self.y_label = ''

    def on_view_legend_box(self):
        """Show/hide legend box"""
        action = self.sender()
        if(action.isChecked()):
            self.legend.show()
        else:
            self.legend.hide()

    def on_view_x_axis(self):
        """Show/hide X axis"""
        action = self.sender()
        if(action.isChecked()):
            self.plot.showAxis('bottom')
        else:
            self.plot.hideAxis('bottom')

    def on_view_y_axis(self):
        """Show/hide Y axis"""
        action = self.sender()
        if(action.isChecked()):
            self.plot.showAxis('left')
        else:
            self.plot.hideAxis('left')

    def _on_plot_settings(self):
        """Show the plot settings dialog"""
        self._settings_diag.x_auto.setChecked(self.x_auto)
        self._settings_diag.y_auto.setChecked(self.y_auto)
        self._settings_diag.x_label.setText(self.x_label)
        self._settings_diag.y_label.setText(self.y_label)
        self._settings_diag.histAutorange.toggled.connect(self._on_histogram_autorange)
        if(self._settings_diag.exec_()):
            self.x_auto = self._settings_diag.x_auto.isChecked()
            if(self.x_auto is False):
                self.x_label = self._settings_diag.x_label.text()
            self.y_auto = self._settings_diag.y_auto.isChecked()
            if(self.y_auto is False):
                self.y_label = self._settings_diag.y_label.text()
            # Show changes immediately
            self.replot()

    def _on_histogram_autorange(self, checked):
        if checked:
            self._settings_diag.histMin.setEnabled(False)
            self._settings_diag.histMax.setEnabled(False)
        else:
            self._settings_diag.histMin.setEnabled(True)
            self._settings_diag.histMax.setEnabled(True)

    def get_time(self, index=None):
        """Returns the time of the given index, or the time of the last data point"""
        if index is None:
            index = self.current_index
        # Check if we have last_vector
        if (self.last_vector_x is not None):
            dt = datetime.datetime.fromtimestamp(self.last_vector_x[index])
            return dt

        # Check if we have enabled_sources
        source = None
        if(self._enabled_sources):
            for ds in self._enabled_sources.keys():
                if(len(self._enabled_sources[ds])):
                    title = self._enabled_sources[ds][0]
                    source = ds
                    break

        # There might be no data yet, so no plotdata
        if(source is not None and title in source.plotdata and
           source.plotdata[title].x is not None):
            pd = source.plotdata[title]
            dt = datetime.datetime.fromtimestamp(pd.x[index])
            return dt
        else:
            return datetime.datetime.now()

    def _configure_axis(self, source, title, hist=False):
        """Configures the x and y axis of the plot, according to the
        source/title configuration and content type"""
        conf = source.conf[title]
        if(self.actionX_axis.isChecked()):
            if 'xlabel' in conf and self.x_auto:
                self.x_label = conf['xlabel']
            if hist:
                self.plot.setLabel('bottom', self.y_label)
            else:
                self.plot.setLabel('bottom', self.x_label)
        if(self.actionY_axis.isChecked()):
            if 'ylabel' in conf and self.y_auto:
                self.y_label = conf['ylabel']
            if hist:
                self.plot.setLabel('left', 'Counts')
            else:
                self.plot.setLabel('left', self.y_label)

    def _configure_xlimits(self, source, title):
        conf = source.conf[title]
        xmin = 0
        xmax = source.plotdata[title].y.shape[-1] + xmin
        if 'xmin' in conf and 'xmax' in conf:
            xmin = conf['xmin']
            xmax = conf['xmax']
        return xmin, xmax

    def _configure_ylimits(self, source, title):
        ymin = source.plotdata[title].y.min
        ymax = source.plotdata[title].y.max
        if ymin == ymax == 0:
            ymin = -0.1
            ymax = 0.1
        if not self._settings_diag.ylimits_auto.isChecked():
            ymin = float(str(self._settings_diag.ymin.text()))
            ymax = float(str(self._settings_diag.ymax.text()))
        self.plot.setRange(yRange=(ymin, ymax))
        
    def replot(self):
        """Replot data"""
        self.plot.clear()
        color_index = 0
        titlebar = []
        self.plot.plotItem.legend.items = []
        for source, title in self.source_and_titles():
            if(title not in source.plotdata or source.plotdata[title].y is None):
                continue
            pd = source.plotdata[title]
            titlebar.append(pd.title)

            color = self.line_colors[color_index % len(self.line_colors)]
            pen = None
            symbol = None
            symbol_pen = None
            symbol_brush = None
            symbol_size = None
            if(self.actionLines.isChecked()):
                pen = color
            if(self.actionPoints.isChecked()):
                symbol = 'o'
                symbol_pen = color
                symbol_brush = color
                symbol_size = 3

            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                y = numpy.array(pd.y, copy=False)
                self.last_vector_y = {}
                self.last_vector_x = None
            elif(source.data_type[title] == 'tuple'):
                y = pd.y[:,1]
                symbol_brush = (255,255,255,120)
                symbol_pen = None
                symbol_size = 8
            elif(source.data_type[title] == 'triple'):
                conf = source.conf[title]
                if self.colormap is None:
                    vmin, vmax = (0,1)
                    if 'vmin' in conf:
                        vmin = conf['vmin']
                    if 'vmax' in conf:
                        vmax = conf['vmax']
                    stops = numpy.r_[vmin, vmax]
                    colors = numpy.array([[0, 0, 1, 0.7], [1, 0, 0, 1.0]])
                    self.colormap = pyqtgraph.ColorMap(stops, colors)
                if 'zlabel' in conf:
                    zlabel = conf['zlabel']
                else:
                    zlabel = 'z'
                if self.colorbar is not None:
                    self.plot.scene().removeItem(self.colorbar)
                self.colorbar = ColorBar(self.colormap, 10, 200, label=zlabel)
                self.plot.scene().addItem(self.colorbar)
                self.actionPoints.setChecked(1)
                self.actionLines.setChecked(0)
                self.colorbar.translate(self.geometry().width() - self.colorbar.zone[2], 20.0)
                y = pd.y[:,1]
                z = pd.y[:,2]
                symbol_brush = self.colormap.map(z, 'qcolor')
                symbol_pen   = None
                symbol_size  = 8
            elif source.data_type[title] == 'vector':
                if(self.current_index == -1):
                    y = numpy.array(pd.y[self.current_index % pd.y.shape[0]], copy=False)
                    self.last_vector_y[title] = numpy.array(pd.y)
                    self.last_vector_x = numpy.array(pd.x)
                else:
                    y = self.last_vector_y[title][self.current_index % self.last_vector_y[title].shape[0]]

            x = None
            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                x = numpy.array(pd.x, copy=False)
                sorted_x = numpy.argsort(x)
                x = x[sorted_x]
                y = y[sorted_x]
                if self._settings_diag.showTrendScalar.isChecked():
                    wl = int(self._settings_diag.windowLength.text())
                    y = utils.array.runningMean(y, wl)
                    x = x[-max(len(y),1):]
                self._configure_ylimits(source, title)
            elif(source.data_type[title] == 'tuple') or (source.data_type[title] == 'triple'):
                x = pd.y[:,0]
            elif(source.data_type[title] == 'vector'):
                if len(y.shape) == 2:
                    x = y[0,:]
                    y = y[1,:]
                else:
                    xmin, xmax = self._configure_xlimits(source, title)
                    x = numpy.linspace(xmin,xmax, y.shape[-1])
            if(self._settings_diag.histogram.isChecked()):
                bins = int(self._settings_diag.histBins.text())
                if (self._settings_diag.histAutorange.isChecked()):
                    hmin, hmax = y.min(), y.max()
                    self._settings_diag.histMin.setText("%.2f"%hmin)
                    self._settings_diag.histMax.setText("%.2f"%hmax)
                else:
                    hmin = float(self._settings_diag.histMin.text())
                    hmax = float(self._settings_diag.histMax.text())
                y,x = numpy.histogram(y, range=(hmin, hmax), bins=bins)
                x = (x[:-1]+x[1:])/2.0
                self._configure_axis(source, title, hist=True)
            else:
                self._configure_axis(source, title)
            self.plot.setLogMode(x=self._settings_diag.logx.isChecked(),
                                 y=self._settings_diag.logy.isChecked())

            plt = self.plot.plot(x=x, y=y, clear=False, pen=pen, symbol=symbol,
                                 symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)

            self.legend.addItem(plt, pd.title)
            color_index += 1
            
            if (source.data_type[title] == 'vector') and (self._settings_diag.showTrendVector.isChecked()):
                for trend in ['mean', 'median', 'std', 'min', 'max']:
                    if eval('self._settings_diag.trendVector_%s.isChecked()' %trend):
                        _trend = getattr(numpy, trend)
                        if len(pd.y.shape) == 3:
                            ytrend = _trend(numpy.array(pd.y[:,1,:], copy=False), axis=0)
                        else:
                            ytrend = _trend(numpy.array(pd.y, copy=False), axis=0)
                        plt_trend = self.plot.plot(x=x, y=ytrend, clear=False, pen=self.line_colors[color_index % len(self.line_colors)], symbol=symbol,
                                                   symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)
                        self.legend.addItem(plt_trend, trend)
                        color_index += 1


        self.setWindowTitle(", ".join(titlebar))
        dt = self.get_time()
        # Round to miliseconds
        self.timeLabel.setText('%02d:%02d:%02d.%03d' % (dt.hour, dt.minute, dt.second, dt.microsecond/1000))
        self.dateLabel.setText(str(dt.date()))

    def _change_index_by(self, amount):
        """Changes the history index when displaying a vector"""
        if self.last_vector_x is None:
            return
        self.current_index += amount
        if(self.current_index > -1):
            self.current_index = -1
        if(self.current_index < -len(self.last_vector_x)):
            self.current_index = -len(self.last_vector_x)

    def keyPressEvent(self, event):
        """Handle key presses"""
        key = event.key()
        if key == QtCore.Qt.Key_Right:
            self._change_index_by(1)
            self.replot()
        elif key == QtCore.Qt.Key_Left:
            self._change_index_by(-1)
            self.replot()

    def get_state(self, _settings = None):
        """Returns settings that can be used to restore the widget to the current state"""
        settings = _settings or {}
        settings['window_type'] = 'PlotWindow'
        settings['viewbox'] = self.plot.getViewBox().getState()
        settings['x_view'] = self.actionX_axis.isChecked()
        settings['y_view'] = self.actionY_axis.isChecked()
        settings['lines'] = self.actionLines.isChecked()
        settings['points'] = self.actionPoints.isChecked()
        settings['legend'] = self.actionLegend_Box.isChecked()

        return DataWindow.get_state(self, settings)

    def restore_from_state(self, settings, data_sources):
        self.plot.getViewBox().setState(settings['viewbox'])
        self.actionX_axis.setChecked(settings['x_view'])
        self.actionX_axis.triggered.emit(settings['x_view'])
        self.actionY_axis.setChecked(settings['y_view'])
        self.actionY_axis.triggered.emit(settings['y_view'])
        self.actionLines.setChecked(settings['lines'])
        self.actionPoints.setChecked(settings['points'])
        self.actionLegend_Box.setChecked(settings['legend'])
        self.actionLegend_Box.triggered.emit(settings['legend'])
        return DataWindow.restore_from_state(self, settings, data_sources)
Пример #5
0
class PlotWindow(DataWindow, Ui_plotWindow):
    """Window to display 2D plots"""
    def __init__(self, parent=None):
        DataWindow.__init__(self, parent)
        self.plot = pyqtgraph.PlotWidget(self.plotFrame, antialiasing=True)
        self.plot.hideAxis('bottom')
        self.legend = self.plot.addLegend()
        self.legend.hide()
        self._finish_layout()
        self.actionLegend_Box.triggered.connect(self.on_view_legend_box)
        self.actionX_axis.triggered.connect(self.on_view_x_axis)
        self.actionY_axis.triggered.connect(self.on_view_y_axis)
        self.acceptable_data_types = ['scalar', 'vector', 'tuple', 'triple', 'running_hist', 'histogram' ]
        self.exclusive_source = False
        self.line_colors = [(252, 175, 62), (114, 159, 207), (255, 255, 255),
                            (239, 41, 41), (138, 226, 52), (173, 127, 168)]
        self.colorbar = None
        self.colormap = None
        self.current_index = -1
        self.last_vector_y = {}
        self.last_vector_x = None
        self.hline = None
        self.vline = None
        self.hline_color = (0,204,0)
        self.vline_color = (204,0,0)
        self._settings_diag = LinePlotSettings(self)
        self._histograms = {}        
        self.updateFonts()

        self.plot.scene().sigMouseMoved.connect(self._onMouseMoved)

    def on_view_legend_box(self):
        """Show/hide legend box"""
        action = self.sender()
        if(action.isChecked()):
            self.legend.show()
        else:
            self.legend.hide()

    def on_view_x_axis(self):
        """Show/hide X axis"""
        action = self.sender()
        if(action.isChecked()):
            self.plot.showAxis('bottom')
        else:
            self.plot.hideAxis('bottom')

    def on_view_y_axis(self):
        """Show/hide Y axis"""
        action = self.sender()
        if(action.isChecked()):
            self.plot.showAxis('left')
        else:
            self.plot.hideAxis('left')

    def _on_plot_settings(self):
        """Show the plot settings dialog"""
        self._settings_diag.histAutorange.toggled.connect(self._on_histogram_autorange)
        if(self._settings_diag.exec_()):
            self._settings_diag._read_bg_file()
            # Show changes immediately
            self.replot()

    def _on_histogram_autorange(self, checked):
        if checked:
            self._settings_diag.histMin.setEnabled(False)
            self._settings_diag.histMax.setEnabled(False)
        else:
            self._settings_diag.histMin.setEnabled(True)
            self._settings_diag.histMax.setEnabled(True)

    def get_time(self, index=None):
        """Returns the time of the given index, or the time of the last data point"""
        if index is None:
            index = self.current_index
        # Check if we have last_vector
        if (self.last_vector_x is not None):
            dt = datetime.datetime.fromtimestamp(self.last_vector_x[index])
            return dt

        # Check if we have enabled_sources
        source = None
        if(self._enabled_sources):
            for ds in self._enabled_sources.keys():
                if(len(self._enabled_sources[ds])):
                    title = self._enabled_sources[ds][0]
                    source = ds
                    break

        # There might be no data yet, so no plotdata
        if(source is not None and title in source.plotdata and
           source.plotdata[title].x is not None):
            pd = source.plotdata[title]
            dt = datetime.datetime.fromtimestamp(pd.x[index])
            return dt
        else:
            return datetime.datetime.now()
            
    def _configure_axis(self, source, title, hist=False):
        """Configures the x and y axis of the plot, according to the
        source/title configuration and content type"""
        conf = source.conf[title]
        if(self.actionX_axis.isChecked()):
            if 'xlabel' in conf and self._settings_diag.x_auto.isChecked():
                self._settings_diag.x_label.setText(conf['xlabel'])
            if hist:
                self.plot.setLabel('bottom', self._settings_diag.y_label.text())
            else:
                self.plot.setLabel('bottom', self._settings_diag.x_label.text())
        if(self.actionY_axis.isChecked()):
            if 'ylabel' in conf and self._settings_diag.y_auto.isChecked():
                self._settings_diag.y_label.setText(conf['ylabel'])
            if hist:
                self.plot.setLabel('left', 'Counts')
            else:
                self.plot.setLabel('left', self._settings_diag.y_label.text())

    def _set_range(self, xmin, xmax, ymin, ymax):
        if not self._settings_diag.xlimits_auto.isChecked():
            try:
                xmin = float(str(self._settings_diag.xmin.text()))
            except ValueError:
                pass
            try:
                xmax = float(str(self._settings_diag.xmax.text()))
            except ValueError:
                pass
        if not self._settings_diag.ylimits_auto.isChecked():
            try:
                ymin = float(str(self._settings_diag.ymin.text()))
            except ValueError:
                pass
            try:
                ymax = float(str(self._settings_diag.ymax.text()))
            except ValueError:
                pass
        if (xmax - xmin) == 0.:
            xmin -= 0.1
            xmax += 0.1
        if (ymax - ymin) == 0.:
            ymin -= 0.1
            ymax += 0.1
        self.plot.setRange(xRange=(xmin, xmax), yRange=(ymin, ymax))    
            
    def replot(self):
        """Replot data"""
        self.plot.clear()

        # Init background if defined in a data source
        if self._settings_diag.bg is None:
            alert_flag = False
            for source, title in self.source_and_titles():
                conf = source.conf[title]
                if "bg_filename" in conf:
                    conf_bg = {}
                    for k,v in conf.items():
                        if k.startswith("bg_"):
                            conf_bg[k] = v
                    self._settings_diag._configure_bg(**conf_bg)
                    # Use only first if there are many
                    break

        alert_flag = False
        for source, title in self.source_and_titles():
            conf = source.conf[title]
            if "alert" in conf and self.alert and conf['alert']:
                alert_flag = True

        if alert_flag:
            os.system('afplay -v %f src/interface/ui/sounds/%s.wav &' %(self.volume,self.sound))
            if not self.alertBlinkTimer.isActive():
                self.alertBlinkTimer.start()
        else:
            if self.alertBlinkTimer.isActive():
                self.alertBlinkTimer.stop()
                self.setStyleSheet("")



        # Load background if configured
        self._update_bg()
            
        color_index = 0
        titlebar = []
        self.plot.plotItem.legend.items = []

        xmins = []
        xmaxs = []
        ymins = []
        ymaxs = []
        
        for source, title in self.source_and_titles():
            
            if(title not in source.plotdata or source.plotdata[title].y is None):
                continue
            pd = source.plotdata[title]
            titlebar.append(pd.title)

            conf = source.conf[title]

            color = self.line_colors[color_index % len(self.line_colors)]
            pen = None
            symbol = None
            symbol_pen = None
            symbol_brush = None
            symbol_size = None
            histoangle = 0

            if(self.actionLines.isChecked()):
                pen = color
            if(self.actionPoints.isChecked()):
                symbol = 'o'
                symbol_pen = color
                symbol_brush = color
                symbol_size = 3

            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                y = numpy.array(pd.y, copy=False)
                self.last_vector_y = {}
                self.last_vector_x = None
            elif(source.data_type[title] == 'tuple'):
                y = pd.y[:,1]
                symbol_brush = (255,255,255,120)
                symbol_pen = None
                symbol_size = 8
            elif(source.data_type[title] == 'triple'):
                if self.colormap is None:
                    vmin, vmax = (0,1)
                    if 'vmin' in conf:
                        vmin = conf['vmin']
                    if 'vmax' in conf:
                        vmax = conf['vmax']
                    stops = numpy.r_[vmin, vmax]
                    colors = numpy.array([[0, 0, 1, 0.7], [1, 0, 0, 1.0]])
                    self.colormap = pyqtgraph.ColorMap(stops, colors)
                if 'zlabel' in conf:
                    zlabel = conf['zlabel']
                else:
                    zlabel = 'z'
                if self.colorbar is not None:
                    self.plot.scene().removeItem(self.colorbar)
                self.colorbar = ColorBar(self.colormap, 10, 200, label=zlabel)
                self.plot.scene().addItem(self.colorbar)
                self.actionPoints.setChecked(1)
                self.actionLines.setChecked(0)
                self.colorbar.translate(self.geometry().width() - self.colorbar.zone[2], 20.0)
                y = pd.y[:,1]
                z = pd.y[:,2]
                symbol_brush = self.colormap.map(z, 'qcolor')
                symbol_pen   = None
                symbol_size  = 8
            elif source.data_type[title] == 'vector':
                if(self.current_index == -1):
                    y = numpy.array(pd.y[self.current_index % pd.y.shape[0]], copy=False)
                    self.last_vector_y[title] = numpy.array(pd.y)
                    self.last_vector_x = numpy.array(pd.x)
                else:
                    y = self.last_vector_y[title][self.current_index % self.last_vector_y[title].shape[0]]
            elif source.data_type[title] == 'histogram':
                if title not in self._histograms:
                    self._histograms[title] = Histogram(conf["hmin"], conf["hmax"], conf["bins"])
                x = self._histograms[title].values_x
                y = self._histograms[title].values_y
                
            x = None
            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                x = numpy.array(pd.x, copy=False)
                sorted_x = numpy.argsort(x)
                x = x[sorted_x]
                y = y[sorted_x]
                if self._settings_diag.showTrendScalar.isChecked():
                    wl = int(self._settings_diag.windowLength.text())
                    y = utils.array.runningMean(y, min(y.size-1,wl))
                    x = x[-y.size:]
            elif(source.data_type[title] == 'tuple') or (source.data_type[title] == 'triple'):
                x = pd.y[:,0]
            elif(source.data_type[title] == 'vector'):
                if len(y.shape) == 2:
                    x = y[0,:]
                    y = y[1,:]
                else:
                    if 'xmin' in conf and 'xmax' in conf:
                        xmin = conf['xmin']
                        xmax = conf['xmax']
                    else:
                        xmin = 0
                        xmax = source.plotdata[title].y.shape[-1] + xmin
                    x = numpy.linspace(xmin,xmax, y.shape[-1])
            if(self._settings_diag.histogram.isChecked()):
                bins = int(self._settings_diag.histBins.text())
                histMode = self._settings_diag.histMode.currentText()
                if (self._settings_diag.histAutorange.isChecked()):
                    hmin, hmax = y.min(), y.max()
                    self._settings_diag.histMin.setText("%.2f"%hmin)
                    self._settings_diag.histMax.setText("%.2f"%hmax)
                else:
                    hmin = float(self._settings_diag.histMin.text())
                    hmax = float(self._settings_diag.histMax.text())
                if histMode == 'count':
                    y,x = numpy.histogram(y, range=(hmin, hmax), bins=bins)
                elif histMode == 'mean':
                    num,x = numpy.histogram(y, range=(hmin, hmax), bins=bins, weights=x)
                    den,x = numpy.histogram(y, range=(hmin, hmax), bins=bins)
                    y = num/(den+1e-20)
                x = (x[:-1]+x[1:])/2.0
                histoangle = 90
                self._configure_axis(source, title, hist=True)
            elif(source.data_type[title] == "histogram"):
                ringbuffer = pd.y
                self._histograms[title].add_values_from_ringbuffer(ringbuffer)
                x = self._histograms[title].values_x
                y = self._histograms[title].values_y
            else:
                self._configure_axis(source, title)
            self.plot.setLogMode(x=self._settings_diag.logx.isChecked(),
                                 y=self._settings_diag.logy.isChecked())

            plt = self.plot.plot(x=x, y=y, clear=False, pen=pen, symbol=symbol,
                                 symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)

            if 'hline' in conf and conf['hline'] is not None:
                self.plot.getPlotItem().removeItem(self.hline)
                self.hline = pyqtgraph.InfiniteLine(angle=0 + histoangle, movable=False, pen=self.hline_color)
                self.plot.getPlotItem().addItem(self.hline)
                self.hline.setPos(conf['hline'])

            if 'vline' in conf and conf['vline'] is not None:
                self.plot.getPlotItem().removeItem(self.vline)
                self.vline = pyqtgraph.InfiniteLine(angle=90 + histoangle, movable=False, pen=self.vline_color)
                self.plot.getPlotItem().addItem(self.vline)
                self.vline.setPos(conf['vline'])

            xmins.append(x.min())
            xmaxs.append(x.max())
            ymins.append(y.min())
            ymaxs.append(y.max())

            self.legend.addItem(plt, pd.title)
            color_index += 1
            
            if (source.data_type[title] == 'vector') and (self._settings_diag.showTrendVector.isChecked()):
                for trend in ['mean', 'median', 'std', 'min', 'max']:
                    if eval('self._settings_diag.trendVector_%s.isChecked()' %trend):
                        _trend = getattr(numpy, trend)
                        if len(pd.y.shape) == 3:
                            ytrend = _trend(numpy.array(pd.y[:,1,:], copy=False), axis=0)
                        else:
                            ytrend = _trend(numpy.array(pd.y, copy=False), axis=0)
                        plt_trend = self.plot.plot(x=x, y=ytrend, clear=False, pen=self.line_colors[color_index % len(self.line_colors)], symbol=symbol,
                                                   symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)
                        self.legend.addItem(plt_trend, trend)
                        color_index += 1


        self.setWindowTitle(", ".join(titlebar))
        dt = self.get_time()
        # Round to miliseconds
        self.timeLabel.setText('%02d:%02d:%02d.%03d' % (dt.hour, dt.minute, dt.second, dt.microsecond/1000))
        self.dateLabel.setText(str(dt.date()))

        # Set ranges
        if len(xmins) > 0:
            self._set_range(min(xmins), max(xmaxs), min(ymins), max(ymaxs))
        
        # Various options
        if self._settings_diag.aspect_locked.isChecked():
            self.plot.getViewBox().setAspectLocked()
        if self._settings_diag.flip_x.isChecked():
            self.plot.getViewBox().invertX()
        if self._settings_diag.flip_y.isChecked():
            self.plot.getViewBox().invertY()

    def _change_index_by(self, amount):
        """Changes the history index when displaying a vector"""
        if self.last_vector_x is None:
            return
        self.current_index += amount
        if(self.current_index > -1):
            self.current_index = -1
        if(self.current_index < -len(self.last_vector_x)):
            self.current_index = -len(self.last_vector_x)

    def keyPressEvent(self, event):
        """Handle key presses"""
        key = event.key()
        if key == QtCore.Qt.Key_Right:
            self._change_index_by(1)
            self.replot()
        elif key == QtCore.Qt.Key_Left:
            self._change_index_by(-1)
            self.replot()

    def get_state(self, _settings = None):
        """Returns settings that can be used to restore the widget to the current state"""
        settings = _settings or {}
        settings['window_type'] = 'PlotWindow'
        settings['viewbox'] = self.plot.getViewBox().getState()
        settings['x_view'] = self.actionX_axis.isChecked()
        settings['y_view'] = self.actionY_axis.isChecked()
        settings['lines'] = self.actionLines.isChecked()
        settings['points'] = self.actionPoints.isChecked()
        settings['legend'] = self.actionLegend_Box.isChecked()
        settings = self._settings_diag.get_state(settings)
        return DataWindow.get_state(self, settings)

    def restore_from_state(self, settings, data_sources):
        self._settings_diag.restore_from_state(settings)
        self.plot.getViewBox().setState(settings['viewbox'])
        self.actionX_axis.setChecked(settings['x_view'])
        self.actionX_axis.triggered.emit(settings['x_view'])
        self.actionY_axis.setChecked(settings['y_view'])
        self.actionY_axis.triggered.emit(settings['y_view'])
        self.actionLines.setChecked(settings['lines'])
        self.actionPoints.setChecked(settings['points'])
        self.actionLegend_Box.setChecked(settings['legend'])
        self.actionLegend_Box.triggered.emit(settings['legend'])
        return DataWindow.restore_from_state(self, settings, data_sources)
    
    def _update_bg(self):
        if self._settings_diag.bg is not None:
            VB = self.plot.getViewBox()
            B = pyqtgraph.ImageItem(image=self._settings_diag.bg, autoLevels=True)
            xmin = float(self._settings_diag.bg_xmin.text())
            ymin = float(self._settings_diag.bg_xmin.text())
            width  = float(self._settings_diag.bg_xmax.text()) - xmin
            height = float(self._settings_diag.bg_ymax.text()) - ymin
            rect = QtCore.QRectF(xmin, ymin, width, height)
            B.setRect(rect)
            VB.addItem(B, ignoreBounds=True)


    def updateFonts(self):
        f = self.title.font()
        size = int(self.settings.value("plotFontSize"))
        f.setPointSize(size)
        self.title.setFont(f)

        f = QtGui.QFont()
        f.setPointSize(size)
        ax = self.plot.getAxis('left')
        ax.setTickFont(f)
        ax = self.plot.getAxis('bottom')
        ax.setTickFont(f)

    def _onMouseMoved(self, pos):
        view = self.plot
        xy = view.mapToView(pos)
        x = xy.x()
        y = xy.y()
        self.xLabel.setText("%f" % (x))
        self.yLabel.setText("%f" % (y))
Пример #6
0
    def replot(self):
        """Replot data"""
        self.plot.clear()

        # Init background if defined in a data source
        if self._settings_diag.bg is None:
            alert_flag = False
            for source, title in self.source_and_titles():
                conf = source.conf[title]
                if "bg_filename" in conf:
                    conf_bg = {}
                    for k,v in conf.items():
                        if k.startswith("bg_"):
                            conf_bg[k] = v
                    self._settings_diag._configure_bg(**conf_bg)
                    # Use only first if there are many
                    break

        alert_flag = False
        for source, title in self.source_and_titles():
            conf = source.conf[title]
            if "alert" in conf and self.alert and conf['alert']:
                alert_flag = True

        if alert_flag:
            os.system('afplay -v %f src/interface/ui/sounds/%s.wav &' %(self.volume,self.sound))
            if not self.alertBlinkTimer.isActive():
                self.alertBlinkTimer.start()
        else:
            if self.alertBlinkTimer.isActive():
                self.alertBlinkTimer.stop()
                self.setStyleSheet("")



        # Load background if configured
        self._update_bg()
            
        color_index = 0
        titlebar = []
        self.plot.plotItem.legend.items = []

        xmins = []
        xmaxs = []
        ymins = []
        ymaxs = []
        
        for source, title in self.source_and_titles():
            
            if(title not in source.plotdata or source.plotdata[title].y is None):
                continue
            pd = source.plotdata[title]
            titlebar.append(pd.title)

            conf = source.conf[title]

            color = self.line_colors[color_index % len(self.line_colors)]
            pen = None
            symbol = None
            symbol_pen = None
            symbol_brush = None
            symbol_size = None
            histoangle = 0

            if(self.actionLines.isChecked()):
                pen = color
            if(self.actionPoints.isChecked()):
                symbol = 'o'
                symbol_pen = color
                symbol_brush = color
                symbol_size = 3

            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                y = numpy.array(pd.y, copy=False)
                self.last_vector_y = {}
                self.last_vector_x = None
            elif(source.data_type[title] == 'tuple'):
                y = pd.y[:,1]
                symbol_brush = (255,255,255,120)
                symbol_pen = None
                symbol_size = 8
            elif(source.data_type[title] == 'triple'):
                if self.colormap is None:
                    vmin, vmax = (0,1)
                    if 'vmin' in conf:
                        vmin = conf['vmin']
                    if 'vmax' in conf:
                        vmax = conf['vmax']
                    stops = numpy.r_[vmin, vmax]
                    colors = numpy.array([[0, 0, 1, 0.7], [1, 0, 0, 1.0]])
                    self.colormap = pyqtgraph.ColorMap(stops, colors)
                if 'zlabel' in conf:
                    zlabel = conf['zlabel']
                else:
                    zlabel = 'z'
                if self.colorbar is not None:
                    self.plot.scene().removeItem(self.colorbar)
                self.colorbar = ColorBar(self.colormap, 10, 200, label=zlabel)
                self.plot.scene().addItem(self.colorbar)
                self.actionPoints.setChecked(1)
                self.actionLines.setChecked(0)
                self.colorbar.translate(self.geometry().width() - self.colorbar.zone[2], 20.0)
                y = pd.y[:,1]
                z = pd.y[:,2]
                symbol_brush = self.colormap.map(z, 'qcolor')
                symbol_pen   = None
                symbol_size  = 8
            elif source.data_type[title] == 'vector':
                if(self.current_index == -1):
                    y = numpy.array(pd.y[self.current_index % pd.y.shape[0]], copy=False)
                    self.last_vector_y[title] = numpy.array(pd.y)
                    self.last_vector_x = numpy.array(pd.x)
                else:
                    y = self.last_vector_y[title][self.current_index % self.last_vector_y[title].shape[0]]
            elif source.data_type[title] == 'histogram':
                if title not in self._histograms:
                    self._histograms[title] = Histogram(conf["hmin"], conf["hmax"], conf["bins"])
                x = self._histograms[title].values_x
                y = self._histograms[title].values_y
                
            x = None
            if(source.data_type[title] == 'scalar') or (source.data_type[title] == 'running_hist'):
                x = numpy.array(pd.x, copy=False)
                sorted_x = numpy.argsort(x)
                x = x[sorted_x]
                y = y[sorted_x]
                if self._settings_diag.showTrendScalar.isChecked():
                    wl = int(self._settings_diag.windowLength.text())
                    y = utils.array.runningMean(y, min(y.size-1,wl))
                    x = x[-y.size:]
            elif(source.data_type[title] == 'tuple') or (source.data_type[title] == 'triple'):
                x = pd.y[:,0]
            elif(source.data_type[title] == 'vector'):
                if len(y.shape) == 2:
                    x = y[0,:]
                    y = y[1,:]
                else:
                    if 'xmin' in conf and 'xmax' in conf:
                        xmin = conf['xmin']
                        xmax = conf['xmax']
                    else:
                        xmin = 0
                        xmax = source.plotdata[title].y.shape[-1] + xmin
                    x = numpy.linspace(xmin,xmax, y.shape[-1])
            if(self._settings_diag.histogram.isChecked()):
                bins = int(self._settings_diag.histBins.text())
                histMode = self._settings_diag.histMode.currentText()
                if (self._settings_diag.histAutorange.isChecked()):
                    hmin, hmax = y.min(), y.max()
                    self._settings_diag.histMin.setText("%.2f"%hmin)
                    self._settings_diag.histMax.setText("%.2f"%hmax)
                else:
                    hmin = float(self._settings_diag.histMin.text())
                    hmax = float(self._settings_diag.histMax.text())
                if histMode == 'count':
                    y,x = numpy.histogram(y, range=(hmin, hmax), bins=bins)
                elif histMode == 'mean':
                    num,x = numpy.histogram(y, range=(hmin, hmax), bins=bins, weights=x)
                    den,x = numpy.histogram(y, range=(hmin, hmax), bins=bins)
                    y = num/(den+1e-20)
                x = (x[:-1]+x[1:])/2.0
                histoangle = 90
                self._configure_axis(source, title, hist=True)
            elif(source.data_type[title] == "histogram"):
                ringbuffer = pd.y
                self._histograms[title].add_values_from_ringbuffer(ringbuffer)
                x = self._histograms[title].values_x
                y = self._histograms[title].values_y
            else:
                self._configure_axis(source, title)
            self.plot.setLogMode(x=self._settings_diag.logx.isChecked(),
                                 y=self._settings_diag.logy.isChecked())

            plt = self.plot.plot(x=x, y=y, clear=False, pen=pen, symbol=symbol,
                                 symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)

            if 'hline' in conf and conf['hline'] is not None:
                self.plot.getPlotItem().removeItem(self.hline)
                self.hline = pyqtgraph.InfiniteLine(angle=0 + histoangle, movable=False, pen=self.hline_color)
                self.plot.getPlotItem().addItem(self.hline)
                self.hline.setPos(conf['hline'])

            if 'vline' in conf and conf['vline'] is not None:
                self.plot.getPlotItem().removeItem(self.vline)
                self.vline = pyqtgraph.InfiniteLine(angle=90 + histoangle, movable=False, pen=self.vline_color)
                self.plot.getPlotItem().addItem(self.vline)
                self.vline.setPos(conf['vline'])

            xmins.append(x.min())
            xmaxs.append(x.max())
            ymins.append(y.min())
            ymaxs.append(y.max())

            self.legend.addItem(plt, pd.title)
            color_index += 1
            
            if (source.data_type[title] == 'vector') and (self._settings_diag.showTrendVector.isChecked()):
                for trend in ['mean', 'median', 'std', 'min', 'max']:
                    if eval('self._settings_diag.trendVector_%s.isChecked()' %trend):
                        _trend = getattr(numpy, trend)
                        if len(pd.y.shape) == 3:
                            ytrend = _trend(numpy.array(pd.y[:,1,:], copy=False), axis=0)
                        else:
                            ytrend = _trend(numpy.array(pd.y, copy=False), axis=0)
                        plt_trend = self.plot.plot(x=x, y=ytrend, clear=False, pen=self.line_colors[color_index % len(self.line_colors)], symbol=symbol,
                                                   symbolPen=symbol_pen, symbolBrush=symbol_brush, symbolSize=symbol_size)
                        self.legend.addItem(plt_trend, trend)
                        color_index += 1


        self.setWindowTitle(", ".join(titlebar))
        dt = self.get_time()
        # Round to miliseconds
        self.timeLabel.setText('%02d:%02d:%02d.%03d' % (dt.hour, dt.minute, dt.second, dt.microsecond/1000))
        self.dateLabel.setText(str(dt.date()))

        # Set ranges
        if len(xmins) > 0:
            self._set_range(min(xmins), max(xmaxs), min(ymins), max(ymaxs))
        
        # Various options
        if self._settings_diag.aspect_locked.isChecked():
            self.plot.getViewBox().setAspectLocked()
        if self._settings_diag.flip_x.isChecked():
            self.plot.getViewBox().invertX()
        if self._settings_diag.flip_y.isChecked():
            self.plot.getViewBox().invertY()