Source code for diaGrabber.plot.pyQtGraph

# -*- coding: utf-8 *-*
#import numpy as np
#from copy import deepcopy
import sys
#import scipy

from diaGrabber import  _utils
from ._plot import _plot

from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
import pyqtgraph.dockarea as pgDock
import pyqtgraph.parametertree.parameterTypes as pTypes
from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType



[docs]class interactive(object): def __init__(self): self.hasInteractiveModus = True
[docs] def plot(self, matrixClass, **kwargs): ''' Optional kwargs ("keyword arguments") are: ================ ========================================= Keyword Description ================ ========================================= *interactive* bool: [True, False] *merge* list: instances of mergeDimension of the source *basis* list: instances of basisDimension of the source *fps* float: frames per seconds *enableAutoRange* list: ["x", "y"] *showType* string: ["together", "widget"] *colorTheme* string: ["default", "bright"] artists *windowSize* list: [size_x, size_y] e.g. **[1000,600]** *showPreferences* bool: [True, False] ================ ========================================= ''' self.matrixClass = matrixClass self.sortMatrix = self.matrixClass.sortMatrix self.mergeMatrix = self.matrixClass.mergeMatrix self._merge_dim = self.matrixClass._merge_dim self._basis_dim = self.matrixClass._basis_dim self.nDim = self.matrixClass.nDim self.nMerge = self.matrixClass.nMerge #standard show_merge = range(self.nMerge)#show all merge-dim show_basis = range(self.nDim)#show all basis-dim interactive = False fps = 20 self.windowSize = [1000,600] self.enableAutoRange = [] self.showType = "together" colorTheme = "default" self.build_preferences_dock = True #individual for key in kwargs: if key == "interactive": interactive = bool(kwargs[key]) elif key == "merge": show_merge = [] for merge in kwargs[key]: ##proove for mergeDim fehlt show_merge.append(merge._mergeIndex) self.nMerge = len(show_merge) elif key == "basis": show_basis = [] for basis in kwargs[key]: ##proove for mergeDim fehlt show_basis.append(basis._basisIndex) self.nDim = len(show_basis) elif key == "fps": fps = kwargs[key] elif key == "enableAutoRange": self.enableAutoRange = kwargs[key] elif key == "showType": self.showType = kwargs[key] elif key == "colorTheme": colorTheme = kwargs[key] elif key == "windowSize": self.windowSize = list( int(kwargs[key][0]), int(kwargs[key][1]) ) elif key == "showPreferences": self.build_preferences_dock = bool(kwargs[key]) self.setColorTheme(colorTheme) self.end_readOut = False self.wait_ms = 1000/fps #frames per second ##create qt-window app = QtGui.QApplication([]) win = QtGui.QMainWindow() #win = pg.GraphicsWindow(title="Interactive Plot") win.resize(self.windowSize[0],self.windowSize[1]) self.area = pgDock.DockArea() win.setCentralWidget(self.area) self.docks = [] plot_size_x = int(self.windowSize[0]*0.1)#int(windowSize[0]*(2/3)) if self.showType == "together": self.docks.append(pgDock.Dock("together", size=(plot_size_x, 1))) self.area.addDock(self.docks[-1]) elif self.showType == "widged": for m in range(self.nMerge): self.docks.append(pgDock.Dock("widget %s" %m, size=(plot_size_x, 1))) #for m in range(self.nMerge): self.area.addDock(self.docks[-1]) else: sys.exit("ERROR: showType invalid") if self.nDim > 1: #set axis name and range #========= yAxis = pg.AxisItem("left")##y #yScale = self._basis_dim[1].resolution/self._basis_dim[1] #yAxis.setScale(0.001) yAxis.setLabel(units = self._basis_dim[1].name) xAxis = pg.AxisItem("bottom")##y xAxis.setLabel(units = self._basis_dim[0].name) #yAxis.setRange(self._basis_dim[1].include_from_to[1],self._basis_dim[1].include_from_to[0]) #self.plot = pg.ImageView(view=pg.PlotItem(title="testtest", axisItems = {"left": yAxis, "bottom": xAxis})) #self.plot = win.addItem(pg.ImageView()) self.plot = win.addViewBox(lockAspect=True) self.img = pg.ImageItem() self.plot.addItem(self.img) self.plot.autoRange() else:#simple 2d-plot - no imag yAxis = []#pg.AxisItem("left")##y xAxis = []#pg.AxisItem("bottom")##y #xAxis.setLabel(units = self._basis_dim[0].name) self.plots = [] self.curves = [] colorList = ['r', 'g', 'b', 'c', 'm', 'y', 'k', 'w'] if self.showType == "together": yAxis.append(pg.AxisItem("left"))##y xAxis.append(pg.AxisItem("bottom"))##y xAxis[-1].setLabel(units = self._basis_dim[0].name) self.plots.append(pg.PlotWidget(axisItems = {"left": yAxis[0], "bottom": xAxis[0]})) docks[0].addWidget(self.plots[0]) #self.plot = win.addPlot(title="Updating plot", axisItems = {"left": yAxis, "bottom": xAxis}) self.plots[0].enableAutoRange('xy', False) if self.nMerge > 1:#if there are more plots draw a legend self.plots[0].addLegend() else: yAxis[0].setLabel(units = self._merge_dim[0].name) #create all plots and ink in range of the colorlist for i in show_merge: self.curves.append(self.plots[0].plot(pen=colorList[i%len(colorList)], symbol='+', name=self._merge_dim[i].name)) elif self.showType == "widged": for n,m in enumerate(show_merge): yAxis.append(pg.AxisItem("left", pen=self.ticks_color))##y xAxis.append(pg.AxisItem("bottom", pen=self.ticks_color))##y labelStyle = {'color': self.label_color} xAxis[-1].setLabel(units = self._basis_dim[0].name, **labelStyle) self.plots.append(pg.PlotWidget(axisItems = {"left": yAxis[-1], "bottom": xAxis[-1]})) self.docks[n].addWidget(self.plots[-1]) self.plots[-1].enableAutoRange('xy', False) yAxis[-1].setLabel(units = self._merge_dim[m].name, **labelStyle) self.curves.append(self.plots[-1].plot(pen=colorList[n%len(colorList)], symbol='+', symbolPen=self.ticks_color, name=self._merge_dim[m].name)) self.plots[-1].setBackground(self.bg_color) else: sys.exit(NotImplemented) if self.build_preferences_dock: self.buildPreferencesDock() win.show() def updateValues(): #lineWise updating data done_readOut = self.matrixClass._fillInteractive(self.end_readOut) if done_readOut or done_readOut == None: #done_readOut = None, if the readoutprocess doesnt func app.quit()#close the window def updatePlot(): ########################################## if self.nDim == 1: basis_extract = self.sortMatrix[show_basis[0]][self._basis_dim[show_basis[0]]._plot_range] for n,m in enumerate(show_merge): merge_extract = self.mergeMatrix[m][self._basis_dim[show_basis[0]]._plot_range] self.curves[n].setData(basis_extract, merge_extract ) for p in self.plots: if "x" in self.enableAutoRange: p.setXRange(self._basis_dim[show_basis[0]]._include_from_to[0],self._basis_dim[show_basis[0]]._include_from_to[1]) if "y" in self.enableAutoRange: ##get min, max values for all merge-dims #miny = self._merge_dim[0]._include_from_to[0] #maxy = self._merge_dim[0]._include_from_to[1] #for i in range(1,self.nMerge): #if self._merge_dim[i]._include_from_to[0] < miny: #miny = self._merge_dim[i]._include_from_to[0] #if self._merge_dim[i]._include_from_to[1] > maxy: #maxy = self._merge_dim[i]._include_from_to[1] #print miny,maxy #self.plot.setYRange(miny,maxy) p.enableAutoRange('y', True) elif self.nDim == 2: sys.exit("mehrere merge noch nicht drinne für image") merge_extract = self.mergeMatrix[self._basis_dim[0]._plot_range][self._basis_dim[1]._plot_range] self.img.setImage(_utils.nanToZeros(merge_extract)) else: sys.exit(NotImplemented) if interactive: #set timer timerValues = QtCore.QTimer() #get new basis-merge-values timerValues.timeout.connect(updateValues) timerValues.start(0) timerPlot = QtCore.QTimer() timerPlot.timeout.connect(updatePlot) timerPlot.start(self.wait_ms) if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): QtGui.QApplication.instance().exec_()
[docs] def setColorTheme(self, colorTheme): '''choose the colortheme for the plot-output, possible values are: * "default" * "bright" ''' if colorTheme == "default" or colorTheme == "": self.ticks_color = (200,200,200) self.label_color = '#fff' self.bg_color = (0,0,0) elif colorTheme == "bright": self.ticks_color = (30,30,30) self.label_color = '#000' self.bg_color = 'w'
[docs] def buildPreferencesDock(self): ## 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': 'Basic parameter data types', 'type': 'group', 'children': [ {'name': 'Integer', 'type': 'int', 'value': 10}, {'name': 'Float', 'type': 'float', 'value': 10.5, 'step': 0.1}, {'name': 'String', 'type': 'str', 'value': "hi"}, {'name': 'List', 'type': 'list', 'values': [1,2,3], 'value': 2}, {'name': 'Named List', 'type': 'list', 'values': {"one": 1, "two": 2, "three": 3}, 'value': 2}, {'name': 'Boolean', 'type': 'bool', 'value': True, 'tip': "This is a checkbox"}, {'name': 'Color', 'type': 'color', 'value': "FF0", 'tip': "This is a color button"}, {'name': 'Gradient', 'type': 'colormap'}, {'name': 'Subgroup', 'type': 'group', 'children': [ {'name': 'Sub-param 1', 'type': 'int', 'value': 10}, {'name': 'Sub-param 2', 'type': 'float', 'value': 1.2e6}, ]}, {'name': 'Text Parameter', 'type': 'text', 'value': 'Some text...'}, {'name': 'Action Parameter', 'type': 'action'}, ]}, {'name': 'Numerical Parameter Options', 'type': 'group', 'children': [ {'name': 'Units + SI prefix', 'type': 'float', 'value': 1.2e-6, 'step': 1e-6, 'siPrefix': True, 'suffix': 'V'}, {'name': 'Limits (min=7;max=15)', 'type': 'int', 'value': 11, 'limits': (7, 15), 'default': -6}, {'name': 'DEC stepping', 'type': 'float', 'value': 1.2e6, 'dec': True, 'step': 1, 'siPrefix': True, 'suffix': 'Hz'}, ]}, {'name': 'Save/Restore functionality', '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': 'Extra Parameter Options', 'type': 'group', 'children': [ {'name': 'Read-only', 'type': 'float', 'value': 1.2e6, 'siPrefix': True, 'suffix': 'Hz', 'readonly': True}, {'name': 'Renamable', 'type': 'float', 'value': 1.2e6, 'siPrefix': True, 'suffix': 'Hz', 'renamable': True}, {'name': 'Removable', 'type': 'float', 'value': 1.2e6, 'siPrefix': True, 'suffix': 'Hz', 'removable': True}, ]}, ComplexParameter(name='Custom parameter group (reciprocal values)'), ScalableGroup(name="Expandable Parameter Group", children=[ {'name': 'ScalableParam 1', 'type': 'str', 'value': "default param 1"}, {'name': 'ScalableParam 2', 'type': 'str', 'value': "default param 2"}, ]), ] ## 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 save(): global state state = p.saveState() def restore(): global state add = p['Save/Restore functionality', 'Restore State', 'Add missing items'] rem = p['Save/Restore functionality', 'Restore State', 'Remove extra items'] p.restoreState(state, addChildren=add, removeChildren=rem) p.param('Save/Restore functionality', 'Save State').sigActivated.connect(save) p.param('Save/Restore functionality', 'Restore State').sigActivated.connect(restore) ## Create ParameterTree widget, t = ParameterTree() t.setParameters(p, showTop=False) #t.show() #only nec. when allone #t.resize(400,800) #create new dock self.docks.append( pgDock.Dock("Preferences", size=(1, 1)) ) #append parameterTree-instance to dock self.docks[-1].addWidget(t) # add dock to area self.area.addDock(self.docks[-1], 'left') ## test save/restore s = p.saveState() p.restoreState(s)