Files
ecmc_plugin_motion/tools/ecmcRTCanvas.py

180 lines
5.6 KiB
Python

#*************************************************************************
# Copyright (c) 2020 European Spallation Source ERIC
# ecmc is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#
# ecmcRTCanvas.py
#
# Created on: July 6, 2020
# Author: Anders Sandström
#
# Heavily inspired by: https://exceptionshub.com/real-time-plotting-in-while-loop-with-matplotlib.html
#
#***************************************************************************
import sys
import os
import epics
from PySide2 import QtCore, QtGui, QtWidgets
#from PyQt5.QtWidgets import *
#from PyQt5 import QtWidgets
#
#from PyQt5.QtCore import *
#from PyQt5.QtGui import *
import functools
import numpy as np
import random as rd
import matplotlib
matplotlib.use("Qt5Agg")
from matplotlib.figure import Figure
from matplotlib.animation import TimedAnimation
from matplotlib.lines import Line2D
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import time
import threading
class ecmcRTCanvas(FigureCanvas, TimedAnimation):
def __init__(self, title):
self.pause = 0
self.addedData = []
self.exceptCount = 0
self.autoZoom = False
print(matplotlib.__version__)
# The data
self.xlim = 1000
self.n = np.linspace(-(self.xlim - 1), 0, self.xlim)
self.y = (self.n * 0.0)
# The window
self.fig = Figure(figsize=(5,5), dpi=100)
self.ax1 = self.fig.add_subplot(111)
# self.ax1 settings
self.ax1.set_xlabel('samples')
self.ax1.set_ylabel('data')
self.ax1.set_title(title)
self.line1 = Line2D([], [], color='blue')
self.line1_tail = Line2D([], [], color='red', linewidth=2)
self.line1_head = Line2D([], [], color='red', marker='o', markeredgecolor='r')
self.ax1.add_line(self.line1)
self.ax1.add_line(self.line1_tail)
self.ax1.add_line(self.line1_head)
self.ax1.set_xlim(-(self.xlim - 1),0)
self.ax1.set_ylim(-100, 100)
self.ax1.grid()
self.firstUpdatedData = True
FigureCanvas.__init__(self, self.fig)
TimedAnimation.__init__(self, self.fig, interval = 50, blit = True)
return
def new_frame_seq(self):
return iter(range(self.n.size))
def setBufferSize(self, bufferSize):
if bufferSize<1000 :
print("Buffer size out of range: " + str(bufferSize))
return
fillValue = self.y[0]
oldSize = self.xlim
self.xlim = int(bufferSize)
self.n = np.linspace(-(self.xlim - 1),0,self.xlim)
if self.xlim > oldSize:
tempArray = np.full(self.xlim - oldSize,fillValue)
self.y = np.concatenate((tempArray, self.y))
else:
self.y = self.y[oldSize-self.xlim:-1]
self.ax1.set_xlim(-(self.xlim-1), 1)
self.draw()
def pauseUpdate(self):
if self.pause:
self.pause = 0
else:
self.pause = 1
def _init_draw(self):
lines = [self.line1, self.line1_tail, self.line1_head]
for l in lines:
l.set_data([], [])
return
def addData(self, value):
if self.pause == 0:
self.addedData.append(value)
return
def zoomAuto(self):
bottom = np.min(self.y)
top = np.max(self.y)
# ensure different values
if bottom == top:
top = bottom +1
self.ax1.clear()
self.ax1.grid(b=True)
range = top - bottom
top += range * 0.1
bottom -= range *0.1
self.ax1.set_ylim(bottom,top)
self.ax1.set_xlim(-(self.xlim-1), 1)
self.draw()
return
def zoomLow(self, value):
top = self.ax1.get_ylim()[1]
bottom = value
self.ax1.set_ylim(bottom,top)
self.draw()
return
def zoomHigh(self, value):
bottom = self.ax1.get_ylim()[0]
top = value
self.ax1.set_ylim(bottom,top)
self.draw()
return
def _step(self, *args):
# Extends the _step() method for the TimedAnimation class.
try:
TimedAnimation._step(self, *args)
except Exception as e:
self.exceptCount += 1
print(str(self.exceptCount))
TimedAnimation._stop(self)
pass
return
def getYLims(self):
return self.ax1.get_ylim()
def _draw_frame(self, framedata):
margin = 1
while(len(self.addedData) > 0):
self.y = np.roll(self.y, -1)
self.y[-1] = self.addedData[0]
if self.firstUpdatedData:
if len(self.addedData) > 0:
self.y[0:-1] = self.addedData[0] # Set entire array to start value
self.firstUpdatedData = False
self.zoomAuto()
del(self.addedData[0])
self.line1.set_data(self.n[ 0 : self.n.size - margin ], self.y[ 0 : self.n.size - margin ])
self.line1_tail.set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]), np.append(self.y[-10:-1 - margin], self.y[-1 - margin]))
self.line1_head.set_data(self.n[-1 - margin], self.y[-1 - margin])
self._drawn_artists = [self.line1, self.line1_tail, self.line1_head]
return
def setYLabel(self,label):
self.ax1.set_ylabel(label)
self.draw()
def setTitle(self,label):
self.ax1.set_title(label)
self.draw()