158 lines
5.4 KiB
Python
158 lines
5.4 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.
|
|
#
|
|
# ecmcFFTGui.py
|
|
#
|
|
# Created on: October 6, 2020
|
|
# Author: Anders Sandström
|
|
#
|
|
# Plots two waveforms (x vs y) updates for each callback on the y-pv
|
|
#
|
|
#*************************************************************************
|
|
|
|
import sys
|
|
import epics
|
|
from PyQt5.QtWidgets import *
|
|
from PyQt5 import QtWidgets
|
|
from PyQt5.QtCore import *
|
|
from PyQt5.QtGui import *
|
|
import numpy as np
|
|
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 matplotlib.pyplot as plt
|
|
import threading
|
|
|
|
class comSignal(QObject):
|
|
data_signal = pyqtSignal(object)
|
|
|
|
class ecmcFFTGui(QtWidgets.QDialog):
|
|
def __init__(self,xname=None,yname=None):
|
|
super(ecmcFFTGui, self).__init__()
|
|
self.comSignalX = comSignal()
|
|
self.comSignalX.data_signal.connect(self.callbackFuncX)
|
|
self.comSignalY = comSignal()
|
|
self.comSignalY.data_signal.connect(self.callbackFuncY)
|
|
self.pause = 0
|
|
self.spectX = None
|
|
self.spectY = None
|
|
self.figure = plt.figure()
|
|
self.plotted_line = None
|
|
self.ax = None
|
|
self.canvas = FigureCanvas(self.figure)
|
|
self.toolbar = NavigationToolbar(self.canvas, self)
|
|
self.pauseBtn = QPushButton(text = 'pause')
|
|
self.pauseBtn.setFixedSize(100, 50)
|
|
self.pauseBtn.clicked.connect(self.pauseBtnAction)
|
|
self.pauseBtn.setStyleSheet("background-color: green");
|
|
self.pvNameY = yname # "IOC_TEST:Plugin-FFT1-Spectrum-Amp-Act"
|
|
self.pvNameX = xname # "IOC_TEST:Plugin-FFT1-Spectrum-X-Axis-Act"
|
|
self.connectPvs() # Epics
|
|
self.setGeometry(300, 300, 900, 700)
|
|
self.setWindowTitle("ecmc FFT plot: " + self.pvNameY + ' vs ' + self.pvNameX)
|
|
layout = QVBoxLayout()
|
|
layout.addWidget(self.toolbar)
|
|
layout.addWidget(self.canvas)
|
|
layout.addWidget(self.pauseBtn)
|
|
self.setLayout(layout)
|
|
return
|
|
|
|
def connectPvs(self):
|
|
|
|
if self.pvNameX is None:
|
|
raise RuntimeError("pvname X must not be 'None'")
|
|
if len(self.pvNameX)==0:
|
|
raise RuntimeError("pvname X must not be ''")
|
|
|
|
if self.pvNameY is None:
|
|
raise RuntimeError("pvname y must not be 'None'")
|
|
if len(self.pvNameY)==0:
|
|
raise RuntimeError("pvname y must not be ''")
|
|
|
|
self.pvX = epics.PV(self.pvNameX)
|
|
#print('self.pvX: ' + self.pvX.info)
|
|
|
|
self.pvY = epics.PV(self.pvNameY)
|
|
#print('self.pvY: ' + self.pvY.info)
|
|
|
|
self.pvX.add_callback(self.onChangePvX)
|
|
self.pvY.add_callback(self.onChangePvY)
|
|
QCoreApplication.processEvents()
|
|
|
|
def onChangePvX(self,pvname=None, value=None, char_value=None,timestamp=None, **kw):
|
|
self.comSignalX.data_signal.emit(value)
|
|
|
|
def onChangePvY(self,pvname=None, value=None, char_value=None,timestamp=None, **kw):
|
|
self.comSignalY.data_signal.emit(value)
|
|
|
|
def pauseBtnAction(self):
|
|
self.pause = not self.pause
|
|
if self.pause:
|
|
self.pauseBtn.setStyleSheet("background-color: red");
|
|
else:
|
|
self.pauseBtn.setStyleSheet("background-color: green");
|
|
self.comSignalY.data_signal.emit(self.spectY)
|
|
return
|
|
|
|
|
|
def callbackFuncX(self, value):
|
|
if(np.size(value)) > 0:
|
|
self.spectX = value
|
|
self.xDataValid = 1
|
|
return
|
|
|
|
def callbackFuncY(self, value):
|
|
if(np.size(value)) > 0:
|
|
self.spectY = value
|
|
self.plotSpect()
|
|
return
|
|
|
|
def plotSpect(self):
|
|
if self.pause:
|
|
return
|
|
if self.spectX is None:
|
|
return
|
|
if self.spectY is None:
|
|
return
|
|
|
|
# create an axis
|
|
if self.ax is None:
|
|
self.ax = self.figure.add_subplot(111)
|
|
|
|
# plot data
|
|
if self.plotted_line is not None:
|
|
self.plotted_line.remove()
|
|
|
|
self.plotted_line, = self.ax.plot(self.spectX,self.spectY, 'b*-')
|
|
self.ax.grid(True)
|
|
|
|
plt.xlabel(self.pvNameX +' [' + self.pvX.units + ']')
|
|
plt.ylabel(self.pvNameY +' [' + self.pvY.units + ']')
|
|
# refresh canvas
|
|
self.canvas.draw()
|
|
|
|
self.ax.autoscale(enable=False)
|
|
|
|
def printOutHelp():
|
|
print("ecmcFFTGui: Plots waveforms of FFT data (updates on Y data callback). ")
|
|
print("python ecmcFFTGui.py <x.pv> <y.pv>")
|
|
print("example: python ecmcFFTGui.py IOC_TEST:Plugin-FFT1-Spectrum-X-Axis-Act IOC_TEST:Plugin-FFT1-Spectrum-Amp-Act")
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
if len(sys.argv)!=3:
|
|
printOutHelp()
|
|
sys.exit()
|
|
xname=sys.argv[1]
|
|
yname=sys.argv[2]
|
|
app = QtWidgets.QApplication(sys.argv)
|
|
window=ecmcFFTGui(xname=xname,yname=yname)
|
|
window.show()
|
|
sys.exit(app.exec_())
|