TG-PlatformPlus/UserScripts/ShowData.py

370 lines
12 KiB
Python

import sys, json, time
from multiprocessing.connection import Client
import numpy as np
import pyqtgraph as pg
from pyqtgraph.console import ConsoleWidget
from pyqtgraph.dockarea.Dock import Dock
from pyqtgraph.dockarea.DockArea import DockArea
from pyqtgraph.Qt import QtWidgets, QtCore
from pyqtgraph.Qt.QtGui import QKeySequence, QShortcut
from user_common import nowStr
import pyqtgraph.parametertree.parameterTypes as pTypes
from pyqtgraph.parametertree import Parameter, ParameterTree
app = pg.mkQApp("MCA")
win = QtWidgets.QMainWindow()
area = DockArea()
win.setCentralWidget(area)
win.resize(1000,500)
win.setWindowTitle('MultiChannel Analyzer')
## Create docks, place them into the window one at a time.
## Note that size arguments are only a suggestion; docks will still have to
## fill the entire dock area and obey the limits of their internal widgets.
d1 = Dock("Log Window", size=(100,600)) ## give this dock the minimum possible size
d2 = Dock("Params Window", size=(100,600))
d3 = Dock("PHA Window", size=(500,100))
d4 = Dock("", size=(500,600)) ## give this dock the minimum possible size
d3.hideTitleBar()
d4.hideTitleBar()
area.addDock(d3, 'left') ## place d1 at left edge of dock area (it will fill the whole space since there are no other docks yet)
area.addDock(d1, 'right') ## place d2 at right edge of dock area
area.addDock(d2, 'right', d1) ## place d3 at bottom edge of d1
area.moveDock(d1, 'bottom', d2)
area.moveDock(d4, 'bottom', d3)
## Add widgets into each dock
## first dock gets save/restore buttons
w1 = pg.LayoutWidget()
label = QtWidgets.QLabel(""" -- DockArea Example --
This window has 6 Dock widgets in it. Each dock can be dragged
by its title bar to occupy a different space within the window
but note that one dock has its title bar hidden). Additionally,
the borders between docks may be dragged to resize. Docks that are dragged on top
of one another are stacked in a tabbed layout. Double-click a dock title
bar to place it in its own window.
""")
textEdt = QtWidgets.QTextEdit()
clearBtn = QtWidgets.QPushButton('Clear Logs')
clearBtn.setEnabled(True)
w1.addWidget(textEdt, row=0, col=0)
w1.addWidget(clearBtn, row=1, col=0)
d1.addWidget(w1)
def clear():
global tempStr
tempStr = ''
clearBtn.clicked.connect(clear)
## test subclassing parameters
## This parameter automatically generates two child parameters which are always reciprocals of each other
class ComplexParameter(pTypes.GroupParameter):
def __init__(self, **opts):
opts['type'] = 'bool'
opts['value'] = True
pTypes.GroupParameter.__init__(self, **opts)
self.addChild({'name': 'A = 1/B', 'type': 'float', 'value': 7, 'suffix': 'Hz', 'siPrefix': True})
self.addChild({'name': 'B = 1/A', 'type': 'float', 'value': 1/7., 'suffix': 's', 'siPrefix': True})
self.a = self.param('A = 1/B')
self.b = self.param('B = 1/A')
self.a.sigValueChanged.connect(self.aChanged)
self.b.sigValueChanged.connect(self.bChanged)
def aChanged(self):
self.b.setValue(1.0 / self.a.value(), blockSignal=self.bChanged)
def bChanged(self):
self.a.setValue(1.0 / self.b.value(), blockSignal=self.aChanged)
## test add/remove
## this group includes a menu allowing the user to add new parameters into its child list
class ScalableGroup(pTypes.GroupParameter):
def __init__(self, **opts):
opts['type'] = 'group'
opts['addText'] = "Add"
opts['addList'] = ['str', 'float', 'int']
pTypes.GroupParameter.__init__(self, **opts)
def addNew(self, typ):
val = {
'str': '',
'float': 0.0,
'int': 0
}[typ]
self.addChild(dict(name="ScalableParam %d" % (len(self.childs)+1), type=typ, value=val, removable=True, renamable=True))
# params = [
# {'name': 'Save/Restore', 'type': 'group', 'children': [
# {'name': 'Save State', 'type': 'action'},
# {'name': 'Restore State', 'type': 'action', 'children': [
# {'name': 'Add missing items', 'type': 'bool', 'value': True},
# {'name': 'Remove extra items', 'type': 'bool', 'value': True},
# ]},
# ]},
# {'name': 'Custom context menu', 'type': 'group', 'children': [
# {'name': 'List contextMenu', 'type': 'float', 'value': 0, 'context': [
# 'menu1',
# 'menu2'
# ]},
# {'name': 'Dict contextMenu', 'type': 'float', 'value': 0, 'context': {
# 'changeName': 'Title',
# 'internal': 'What the user sees',
# }},
# ]},
# ComplexParameter(name='Custom parameter group (reciprocal values)'),
# ScalableGroup(name="Expandable Parameter Group", tip='Click to add children', children=[
# {'name': 'ScalableParam 1', 'type': 'str', 'value': "default param 1"},
# {'name': 'ScalableParam 2', 'type': 'str', 'value': "default param 2"},
# ]),
# ]
params = [
{'name': 'Save/Restore', 'type': 'group', 'children': [
{'name': 'Save State', 'type': 'action'},
{'name': 'Restore State', 'type': 'action', 'children': [
{'name': 'Add missing items', 'type': 'bool', 'value': True},
{'name': 'Remove extra items', 'type': 'bool', 'value': True},
]},
]},
{'name':'ROIs', 'type':'group', 'children':[
]},
]
## Create tree of Parameter objects
p = Parameter.create(name='params', type='group', children=params)
## If anything changes in the tree, print a message
def change(param, changes):
# print("tree changes:")
for param, change, data in changes:
path = p.childPath(param)
if path is not None:
childName = '.'.join(path)
else:
childName = param.name()
# print(' parameter: %s'% childName)
# print(' change: %s'% change)
# print(' data: %s'% str(data))
# print(' ----------')
p.sigTreeStateChanged.connect(change)
def valueChanging(param, value):
print("Value changing (not finalized): %s %s" % (param, value))
# Only listen for changes of the 'widget' child:
for child in p.child('Save/Restore'):
if 'widget' in child.names:
child.child('widget').sigValueChanging.connect(valueChanging)
def save():
global state
state = p.saveState()
def restore():
global state
add = p['Save/Restore', 'Restore State', 'Add missing items']
rem = p['Save/Restore', 'Restore State', 'Remove extra items']
p.restoreState(state, addChildren=add, removeChildren=rem)
p.param('Save/Restore', 'Save State').sigActivated.connect(save)
p.param('Save/Restore', 'Restore State').sigActivated.connect(restore)
w2 = ParameterTree()
w2.setParameters(p, showTop=False)
w2.setWindowTitle('pyqtgraph example: Parameter Tree')
d2.addWidget(w2)
## Hide title bar on dock 3
# d3.hideTitleBar()
data = []
w3 = pg.PlotWidget()
w3.enableAutoRange('xy', False)
w3.setXRange(0, len(data))
w3.hideAxis('left')
w3.hideAxis('bottom')
w3.setMouseEnabled(x=False, y=False)
w3.setLogMode(False, True)
lr = pg.LinearRegionItem([0,len(data)])
lr.setZValue(0)
w3.addItem(lr)
curve_w3 = w3.plot(data)
d3.addWidget(w3)
# w4 = pg.PlotWidget()
# plt = w4.plot(data)
# w4.setXRange(0, len(data))
# w4.setMouseEnabled(y=False)
# w4.setAutoVisible(y=True)
# cursorLine = pg.InfiniteLine(angle=90, movable=True)
# w4.addItem(cursorLine)
# def updatePlot():
# global w3, w4
# w4.setXRange(*lr.getRegion(), padding=0)
# w4.enableAutoRange('y', True)
# def updateRegion():
# global w3, w4
# lr.setRegion(w4.getViewBox().viewRange()[0])
# w4.enableAutoRange('y', True)
# def mouseMoved(evt):
# global cursorLine, plt
# if type(evt) != QtCore.QPointF:
# return
# cursorLine.setPos(int(plt.mapFromScene(evt).x()))
# def mouseClicked(evt):
# return
# global cursorLine, plt
# if evt.button() == QtCore.Qt.MouseButton.LeftButton:
# pos = plt.mapFromScene(evt.scenePos())
# cursorLine.setPos(int(pos.x()))
# plt.scene().sigMouseMoved.connect(mouseMoved)
# plt.scene().sigMouseClicked.connect(mouseClicked)
# lr.sigRegionChanged.connect(updatePlot)
# w4.sigXRangeChanged.connect(updateRegion)
# w4.enableAutoRange('y', True)
# # for i in range(1):
# # w4.plot(range(2400,2500,1), data[2400:2500], fillLevel=0, brush=(255, 0, 0, 100))
# updatePlot()
# d4.addWidget(w4)
w5 = pg.GraphicsLayoutWidget()
label = pg.LabelItem(justify='left')
label.setText(f"Channel=?, Count=?")
w5.addItem(label, row=0, col=0)
plt = pg.PlotItem()
curve_w5 = plt.plot(data)
w5.addItem(plt, row=1, col=0)
plt.setXRange(0, len(data))
plt.setMouseEnabled(y=False)
plt.setAutoVisible(y=True)
plt.showGrid(x=True, y=True)
cursorLine = pg.InfiniteLine(angle=90, movable=True)
plt.addItem(cursorLine)
def updatePlot():
global w3, plt
plt.setXRange(*lr.getRegion(), padding=0)
plt.enableAutoRange('y', True)
def updateRegion():
global w3, plt
lr.setRegion(plt.getViewBox().viewRange()[0])
plt.enableAutoRange('y', True)
def mouseClicked(evt):
return
global cursorLine, plt
if evt.button() == QtCore.Qt.MouseButton.LeftButton:
pos = plt.mapFromScene(evt.scenePos())
cursorLine.setPos(int(pos.x()))
def mouseMoved(evt):
global cursorLine, plt, label
if type(evt) != QtCore.QPointF:
return
cursorLine.setPos(int(plt.mapToView(evt).x()))
if int(plt.mapToView(evt).x()) >=0 and int(plt.mapToView(evt).x()) < len(data):
lbStr = f"<font color='green'><B>Channel={int(plt.mapToView(evt).x())}, Count={data[int(plt.mapToView(evt).x())]}</B></font>"
label.setText(lbStr)
ROIs = {}
currentROI = []
ROIPlotItems = {}
def markROI():
global ROIs, currentROI, cursorLine, tempStr, w2, ROIPlotItems, p
if len(currentROI) == 0:
currentROI.append(int(cursorLine.pos()[0]))
elif len(currentROI) == 1:
currentROI.append(int(cursorLine.pos()[0]))
lch = min(currentROI[0],currentROI[1])
rch = max(currentROI[0],currentROI[1])
currentROI = [lch, rch]
ROIs[f"ROI{lch}_{rch}"] = currentROI
tempDict = [{'name':'lChannel', 'type':'int', 'value':lch, 'removable':False, 'renamable':False, 'readonly':True},
{'name':'rChannel', 'type':'int', 'value':rch, 'removable':False, 'renamable':False, 'readonly':True},]
tempParameter = Parameter.create(name=f"ROI{lch}_{rch}", type='group', children=tempDict)
paramROIs = p.child('ROIs')
paramROIs.addChild(tempParameter,autoIncrementName=False)
p.removeChild(paramROIs)
p.addChild(paramROIs)
w2.setParameters(p, showTop=False)
tempStr = f"{nowStr()} Create new ROI: ({lch}, {rch})\n" + tempStr
textEdt.setText(tempStr)
ROIPlotItems[f"ROI{lch}_{rch}"] = plt.plot(range(lch, rch, 1), data[lch:rch], fillLevel=0, brush=(255, 0, 0, 100))
currentROI = []
def delROI():
global ROIs, currentROI, cursorLine, tempStr, w2, ROIPlotItems, p
pos = int(cursorLine.pos()[0])
error = len(data)
index = -1
for key, value in ROIs.items():
lch = value[0]
rch = value[1]
if pos >= lch and pos <= rch and rch - lch < error:
index = key
error = rch - lch
if index in ROIs:
optionalROI = ROIs[index]
tempStr = f"{nowStr()} Delete ROI: ({optionalROI[0]}, {optionalROI[1]})\n" + tempStr
textEdt.setText(tempStr)
ROIs.pop(index)
plt.removeItem(ROIPlotItems[index])
ROIPlotItems.pop(index)
paramROI = p.child("ROIs").child(f"ROI{optionalROI[0]}_{optionalROI[1]}")
p.child("ROIs").removeChild(paramROI)
w2.setParameters(p, showTop=False)
else:
pass
QShortcut(QKeySequence("Ctrl+Q"), w5).activated.connect(markROI)
QShortcut(QKeySequence("Ctrl+D"), w5).activated.connect(delROI)
plt.scene().sigMouseMoved.connect(mouseMoved)
plt.scene().sigMouseClicked.connect(mouseClicked)
lr.sigRegionChanged.connect(updatePlot)
plt.sigXRangeChanged.connect(updateRegion)
updatePlot()
d4.addWidget(w5)
tempStr = ''
client = Client(('127.0.0.1', 8000))
def update():
global client, tempStr, textEdt, curve_w5, curve_w3
sendData = 'send data'
client.send(sendData)
data = json.loads(client.recv()) # 等待接受数据
# data = list(np.linspace(0,4095,4096))
# temp = data
print(data)
temp = [round(i, 3) for i in data]
curve_w3.setData(temp)
curve_w5.setData(temp)
tempStr = f"[{nowStr()}]: {len(data)}\n" + tempStr
textEdt.setText(tempStr)
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(1000)
win.show()
if __name__ == '__main__':
pg.exec()