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, VCPWidget

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, VCPWidget): """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")