Source code for qtpyvcp.widgets.hal_widgets.hal_plot


import os

from qtpy.QtGui import QColor
from qtpy.QtWidgets import *
from qtpy.QtCore import Property, Signal, Slot, QTime, QTimer, Qt
from collections import deque

import pyqtgraph as pg
import numpy as np

from qtpyvcp import hal
from qtpyvcp.widgets import HALWidget

IN_DESIGNER = os.getenv('DESIGNER', False)


class TimeAxisItem(pg.AxisItem):
    """Internal timestamp for x-axis"""
    def __init__(self, *args, **kwargs):
        super(TimeAxisItem, self).__init__(*args, **kwargs)

    def tickStrings(self, values, scale, spacing):
        """Function overloading the weak default version to provide timestamp"""
        return [QTime().currentTime().addMSecs(int(value)).toString('mm:ss') for value in values]


[docs]class HalPlot(QWidget, HALWidget): """HAL Plot Plots HAL pin values over time, similar to HAL scope. Up to four HAL pin values can be plotted. .. table:: Generated HAL Pins ================================== =========== ========= HAL Pin Name Type Direction ================================== =========== ========= qtpyvcp.pinBaseName.seriesXname.in float in ================================== =========== ========= both pinBaseName and seriesXname can be set in the property editor in QtDesigner. """ def __init__(self, parent=None): super(HalPlot, self).__init__(parent) # HAL sampling frequency parameters self._frequency = 1 # Hz self._timeWindow = 600 # seconds # Internal timestamp for x-axis - data values are ms from when "timestamp" was started self.timestamp = QTime() self.timestamp.start() self._legend = False self._yAxisLabel = 'y label' self._yAxisUnits = 'y units' self._minY = 0 self._maxY = 1 self._s1enable = True self._s1name = "Series 1" self._s1colour = QColor('red') self._s1width = 1 self._s1style = Qt.SolidLine self._s1_pin = None self._s2enable = False self._s2name = "Series 2" self._s2colour = QColor('blue') self._s2width = 1 self._s2style = Qt.SolidLine self._s2_pin = None self._s3enable = False self._s3name = "Series 3" self._s3colour = QColor('green') self._s3width = 1 self._s3style = Qt.SolidLine self._s3_pin = None self._s4enable = False self._s4name = "Series 4" self._s4colour = QColor('yellow') self._s4width = 1 self._s4style = Qt.SolidLine self._s4_pin = None # PyQtGraph stuff self.graph = pg.GraphicsLayoutWidget() self.yAxis = pg.AxisItem(orientation='left') self.yAxis.setLabel(self._yAxisLabel, units=self._yAxisUnits) self.yAxis.setGrid(125) self.plot = self.graph.addPlot(axisItems={'bottom': TimeAxisItem(orientation='bottom'), 'left': self.yAxis}) self.plot.setYRange(self._minY, self._maxY, padding=0.0) self.legend = self.plot.addLegend() self.p1 = pg.PlotCurveItem(name=self._s1name) self.p2 = pg.PlotCurveItem(name=self._s2name) self.p3 = pg.PlotCurveItem(name=self._s3name) self.p4 = pg.PlotCurveItem(name=self._s4name) self.setSeries() self.setData() self.Vlayout = QVBoxLayout(self) self.Vlayout.addWidget(self.graph) # HAL stuff self._typ = "float" self._fmt = "%s" if IN_DESIGNER: return # QTimer self.updatetimer = QTimer(self) self.updatetimer.timeout.connect(self.updateplot) self.updatetimer.start(self._refreshRate) def setSeries(self): # first remove the legend as it does not update correnctly try: self.legend.scene().removeItem(self.legend) except: pass # remove all plot items self.plot.clear() # add the legend and plot itmes if self._legend: self.legend = self.plot.addLegend() if self._s1enable: self.p1 = pg.PlotCurveItem(name=self._s1name) self.plot.addItem(self.p1) self.p1.setPen(QColor(self._s1colour), width=self._s1width, style=self._s1style) if self._s2enable: self.p2 = pg.PlotCurveItem(name=self._s2name) self.plot.addItem(self.p2) self.p2.setPen(QColor(self._s2colour), width=self._s2width, style=self._s2style) if self._s3enable: self.p3 = pg.PlotCurveItem(name=self._s3name) self.plot.addItem(self.p3) self.p3.setPen(QColor(self._s3colour), width=self._s3width, style=self._s3style) if self._s4enable: self.p4 = pg.PlotCurveItem(name=self._s4name) self.plot.addItem(self.p4) self.p4.setPen(QColor(self._s4colour), width=self._s4width, style=self._s4style) def setData(self): # Data stuff self._period = 1.0/self._frequency self._refreshRate = int(self._period * 1000) # sample period in milliseconds self._timeWindowMS = self._timeWindow * 1000 # time window in milliseconds self._bufsize = int(self._timeWindowMS / self._refreshRate) # Data containers: collections.deque is list-like container with fast appends and pops on either end self.x = np.linspace(-self.timeWindow, 0.0, self._bufsize) self.now = self.timestamp.elapsed() self.x_data = deque(np.linspace(self.now-self._timeWindowMS, self.now, self._bufsize),self._bufsize) self.s1 = np.zeros(self._bufsize, dtype=float) self.s1_data = deque([0.0] * self._bufsize, self._bufsize) self.s2 = np.zeros(self._bufsize, dtype=float) self.s2_data = deque([0.0] * self._bufsize, self._bufsize) self.s3 = np.zeros(self._bufsize, dtype=float) self.s3_data = deque([0.0] * self._bufsize, self._bufsize) self.s4 = np.zeros(self._bufsize, dtype=float) self.s4_data = deque([0.0] * self._bufsize, self._bufsize) def updateplot(self): self.x_data.append(self.timestamp.elapsed()) self.x[:] = self.x_data if self._s1enable: self.s1_data.append(self._s1_pin.value) self.s1[:] = self.s1_data self.p1.setData(self.x, self.s1) if self._s2enable: self.s2_data.append(self._s2_pin.value) self.s2[:] = self.s2_data self.p2.setData(self.x, self.s2) if self._s3enable: self.s3_data.append(self._s3_pin.value) self.s3[:] = self.s3_data self.p3.setData(self.x, self.s3) if self._s4enable: self.s4_data.append(self._s4_pin.value) self.s4[:] = self.s4_data self.p4.setData(self.x, self.s4) def setyAxis(self): self.yAxis.setLabel(self._yAxisLabel, units=self._yAxisUnits) def setYRange(self): self.plot.setYRange(self._minY, self._maxY, padding = 0.0) @Property(int) def frequency(self): return self._frequency @frequency.setter def frequency(self, frequency): self._frequency = frequency return self.setData() @Property(int) def timeWindow(self): return self._timeWindow @timeWindow.setter def timeWindow(self, timeWindow): self._timeWindow = timeWindow return self.setData() @Property(str) def yAxisLabel(self): return self._yAxisLabel @yAxisLabel.setter def yAxisLabel(self, yAxisLabel): self._yAxisLabel = yAxisLabel return self.setyAxis() @Property(str) def yAxisUnits(self): return self._yAxisUnits @yAxisUnits.setter def yAxisUnits(self, yAxisUnits): self._yAxisUnits = yAxisUnits return self.setyAxis() @Property(float) def minYRange(self): return self._minY @minYRange.setter def minYRange(self, minY): self._minY = minY return self.setYRange() @Property(float) def maxYRange(self): return self._maxY @maxYRange.setter def maxYRange(self, maxY): self._maxY = maxY return self.setYRange() # Legend propterties @Property(bool) def legendenable(self): return self._legend @legendenable.setter def legendenable(self, legendenable): self._legend = legendenable self.setSeries() # Series 1 properties @Property(bool) def series1enable(self): return self._s1enable @series1enable.setter def series1enable(self, series1enable): self._s1enable = series1enable self.setSeries() @Property(str) def series1name(self): return self._s1name @series1name.setter def series1name(self, series1name): self._s1name = series1name self.setSeries() @Property(QColor) def series1colour(self): return self._s1colour @series1colour.setter def series1colour(self, series1colour): self._s1colour = series1colour self.setSeries() @Property(int) def series1width(self): return self._s1width @series1width.setter def series1width(self, series1width): self._s1width = series1width self.setSeries() @Property(Qt.PenStyle) def series1style(self): return self._s1style @series1style.setter def series1style(self, series1style): self._s1style = series1style self.setSeries() # Series 2 properties @Property(bool) def series2enable(self): return self._s2enable @series2enable.setter def series2enable(self, series2enable): self._s2enable = series2enable self.setSeries() @Property(str) def series2name(self): return self._s2name @series2name.setter def series2name(self, series2name): self._s2name = series2name self.setSeries() @Property(QColor) def series2colour(self): return self._s2colour @series2colour.setter def series2colour(self, series2colour): self._s2colour = series2colour self.setSeries() @Property(int) def series2width(self): return self._s2width @series2width.setter def series2width(self, series2width): self._s2width = series2width self.setSeries() @Property(Qt.PenStyle) def series2style(self): return self._s2style @series2style.setter def series2style(self, series2style): self._s2style = series2style self.setSeries() # Series 3 properties @Property(bool) def series3enable(self): return self._s3enable @series3enable.setter def series3enable(self, series3enable): self._s3enable = series3enable self.setSeries() @Property(str) def series3name(self): return self._s3name @series3name.setter def series3name(self, series3name): self._s3name = series3name self.setSeries() @Property(QColor) def series3colour(self): return self._s3colour @series3colour.setter def series3colour(self, series3colour): self._s3colour = series3colour self.setSeries() @Property(int) def series3width(self): return self._s3width @series3width.setter def series3width(self, series3width): self._s3width = series3width self.setSeries() @Property(Qt.PenStyle) def series3style(self): return self._s3style @series3style.setter def series3style(self, series3style): self._s3style = series3style self.setSeries() # Series 4 properties @Property(bool) def series4enable(self): return self._s4enable @series4enable.setter def series4enable(self, series4enable): self._s4enable = series4enable self.setSeries() @Property(str) def series4name(self): return self._s4name @series4name.setter def series4name(self, series4name): self._s4name = series4name self.setSeries() @Property(QColor) def series4colour(self): return self._s4colour @series4colour.setter def series4colour(self, series4colour): self._s4colour = series4colour self.setSeries() @Property(int) def series4width(self): return self._s4width @series4width.setter def series4width(self, series4width): self._s4width = series4width self.setSeries() @Property(Qt.PenStyle) def series4style(self): return self._s4style @series4style.setter def series4style(self, series4style): self._s4style = series4style self.setSeries() def initialize(self): comp = hal.getComponent() obj_name = self.getPinBaseName() # add HAL pins if self._s1enable: self._s1_pin = comp.addPin(obj_name + "." + self._s1name.replace(' ', ''), self._typ, "in") if self._s2enable: self._s2_pin = comp.addPin(obj_name + "." + self._s2name.replace(' ', ''), self._typ, "in") if self._s3enable: self._s3_pin = comp.addPin(obj_name + "." + self._s3name.replace(' ', ''), self._typ, "in") if self._s4enable: self._s4_pin = comp.addPin(obj_name + "." + self._s4name.replace(' ', ''), self._typ, "in")