class SerialReader(QtCore.QObject): sigDataReady = QtCore.pyqtSignal(list) def __init__(self, device, baud, converter=float, timeout=0.001, **kwargs): super(SerialReader, self).__init__() self.serial = serial.Serial(device, baud, timeout=timeout, **kwargs) self.conv = converter self.fragment = bytearray() self.running = False self.thread = QtCore.QThread() self.moveToThread(self.thread) self.thread.started.connect(self.run) def start(self): self.thread.start() def stop(self): self.running = False self.thread.quit() self.thread.wait() self.serial.close() def run(self): self.running = True while self.running: input = self.serial.read(4096) if len(input) > 0: buf = self.fragment + input lines = buf.split(b'\n') self.fragment = lines.pop() for line in lines: try: data = self.conv(line) if data is not None: self.sigDataReady.emit(data) except (ValueError, IndexError): print(line)
class RelCheckboxGrid(QtGui.QWidget): #{{{ """ """ changed = QtCore.pyqtSignal(int) def __init__(self, parent): # super(RelCheckboxGrid, self).__init__(parent=parent) QtGui.QWidget.__init__(self, parent=parent) self.grid = [] # array of checkbox objects def addCheckbox(self, i, st): step = 16 x0 = 5 y0 = 25 self.grid.append( QtGui.QCheckBox(parent=self, text=QtCore.QString.fromUtf8(st), geometry=QtCore.QRect(x0, y0 + i * step, 350, 20))) self.grid[i].clicked.connect(self._emitState) def setState(self, state): i = 0 while i < len(self.grid): self.grid[i].setChecked((state >> i) & 1) i += 1 def getState(self): i = 0 state = 0 while i < len(self.grid): if self.grid[i].checkState(): state += 1 << i i += 1 return state def _emitState(self): self.changed.emit(self.getState())
class options(QtGui.QWidget): kbuttonDown, kbuttonUp, kbuttonRight, kbuttonLeft, kbuttonEsc, kbuttonEnt = QtCore.pyqtSignal( ), QtCore.pyqtSignal(), QtCore.pyqtSignal(), QtCore.pyqtSignal( ), QtCore.pyqtSignal(), QtCore.pyqtSignal() def __init__(self): #init window QtGui.QWidget.__init__(self) self.ui = uic.loadUi( os.path.dirname(os.path.abspath(__file__)) + '/ekgui/options.ui', self) self.setWindowFlags(QtCore.Qt.FramelessWindowHint) #init buttons self.ui.enterButton.clicked.connect(self.enter) self.ui.backButton.clicked.connect(self.back) self.kbuttonEsc.connect(self.back) self.kbuttonEnt.connect(self.enter) self.ui.showMaximized() self.setFocus() self.ui.options.setFocus() #triggers keyboard button press events def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Right: self.kbuttonRight.emit() elif event.key() == QtCore.Qt.Key_Left: self.kbuttonLeft.emit() elif event.key() == QtCore.Qt.Key_Up: self.kbuttonUp.emit() elif event.key() == QtCore.Qt.Key_Down: self.kbuttonDown.emit() elif event.key() == QtCore.Qt.Key_Escape: self.kbuttonEsc.emit() elif event.key() == QtCore.Qt.Key_Enter or event.key( ) == QtCore.Qt.Key_Return: self.kbuttonEnt.emit() def back(self): self.close() def enter(self): self.close()
class DotDragSignal(QtCore.QObject): moved = QtCore.pyqtSignal(object, int) def __init__(self, pt, ind): QtCore.QObject.__init__(self) self._pt = pt self._ind = ind @property def pt(self): return self._pt @property def ind(self): return self._ind @pt.setter def pt(self, new_pt): self._pt = new_pt self.moved.emit(new_pt, self.ind) @ind.setter def ind(self, new_ind): self._ind = new_ind
class MonitorIntervalInput(QtGui.QWidget): """ Simple form-like widget for entering a monitor/refresh interval. Only has a label and a spin-box as input. It's signal `intervalChanged(int)' is emitted when the value of the spinbox has changed. """ intervalChanged = QtCore.pyqtSignal(int) def __init__(self, parent=None): super().__init__(parent) self.spin = QtGui.QSpinBox() layout = QtGui.QFormLayout() layout.addRow('Refresh interval (s)', self.spin) self.setLayout(layout) self.spin.valueChanged.connect(self.spinValueChanged) @QtCore.pyqtSlot(int) def spinValueChanged(self, val): self.intervalChanged.emit(val)
class TimeSliderThread(QtCore.QThread): update_signal = QtCore.pyqtSignal(int) def __init__(self, current, playback_speed, max_time): QtCore.QThread.__init__(self) self.current = current self.playback_speed = playback_speed self.max = max_time self.allowed_to_run = True def run(self): index = 0 calculations_per_second = 30 r = rospy.Rate(calculations_per_second) while self.allowed_to_run: index += 1 value = (self.current + float(index) / calculations_per_second * self.playback_speed) % self.max self.update_signal.emit(value) r.sleep() def stop(self): self.allowed_to_run = False
class ToggleEye(QtGui.QLabel): activeChanged = QtCore.pyqtSignal(bool) def __init__(self, parent=None): super(ToggleEye, self).__init__(parent=parent) self._active = True path = os.path.dirname(os.path.abspath(__file__)) self._eye_open = QtGui.QPixmap( os.path.join(path, "icons/stock-eye-20.png")) self._eye_closed = QtGui.QPixmap( os.path.join(path, "icons/stock-eye-20-gray.png")) self.setPixmap(self._eye_open) def active(self): return self._active def setActive(self, b): if b == self._active: return self._active = b if b: self.setPixmap(self._eye_open) else: self.setPixmap(self._eye_closed) def toggle(self): if self.active(): self.setActive(False) else: self.setActive(True) def mousePressEvent(self, ev): self.toggle() self.activeChanged.emit(self._active)
class MaskController(QtWidgets.QWidget): update_mask = QtCore.pyqtSignal(str, int, name="update_mask") def __init__(self, path): super().__init__() self._path = path self._checkboxes = {} self._state = {} self._layout = QtGui.QHBoxLayout() self.setLayout(self._layout) self._layout.addWidget(QtWidgets.QLabel(text="Mask:")) b = QtWidgets.QPushButton("Update") b.clicked.connect(self._update_mask) self._layout.addWidget(b) def _update_mask(self): mask = 0 for sensor_no, is_masked in self._state.items(): mask |= is_masked << sensor_no self.update_mask.emit(self._path, mask) def update(self, path, sensor_no, _quat): if path == self._path and sensor_no not in self._checkboxes: cb = self._checkboxes[sensor_no] = QtWidgets.QCheckBox( str(sensor_no), self) def update_state(state): self._state[sensor_no] = state == 2 # from the docs cb.stateChanged.connect(update_state) known = [(so, w) for so, w in self._checkboxes.items()] pos = bisect.bisect_left(known, (sensor_no, cb)) pos += 1 self._layout.insertWidget(pos, cb)
class DlgCycleDetection(ui.Ui_CycleDetection, QtWidgets.QDialog): dlgdata = QtCore.pyqtSignal(object) def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) self.okButton.clicked.connect(self.accept) self.cancelButton.clicked.connect(self.reject) self.choices = {} plotframe = self.parent().tabWidget.currentWidget() if plotframe is None: return for n, curvename in enumerate(plotframe.curves.keys()): combo = QtGui.QComboBox() combo.addItems([ft.value for ft in CycleId]) curveitem = QtGui.QTableWidgetItem(curvename) self.table.insertRow(n) self.table.setItem(n, 0, curveitem) self.table.setCellWidget(n, 1, combo) self.choices[curvename] = combo self.table.horizontalHeader().setResizeMode( QtGui.QHeaderView.ResizeToContents) def accept(self): result = { curve: combo.currentText() for (curve, combo) in self.choices.items() } self.dlgdata.emit(result) super().accept()
class DlgSetupPULoop(ui.Ui_SetupPULoop, QtWidgets.QDialog): dlgdata = QtCore.pyqtSignal(object) def __init__(self, sourcewidget, parent=None): super().__init__(parent=parent) self.setupUi(self) self.okButton.clicked.connect(self.accept) self.cancelButton.clicked.connect(self.reject) try: curvenames = list(sourcewidget.curves.keys()) except AttributeError: return self.comboU.addItems(curvenames) self.comboP.addItems(curvenames) def accept(self): uname = self.comboU.currentText() pname = self.comboP.currentText() result = (uname, pname) self.dlgdata.emit(result) super().accept()
class tickMC(QtGui.QWidget): stateChanged = QtCore.pyqtSignal(int) """docstring for tickMC""" def __init__(self, owner, name): super(tickMC, self).__init__() self._label = QtGui.QLabel() self._name = name self._label.setText(self._name.capitalize() + ": ") self._box = QtGui.QCheckBox("Nu only") self._box.setChecked(False) self._box.stateChanged.connect(self.emitSignal) # This is the widget itself, so set it up self._layout = QtGui.QVBoxLayout() self._layout.addWidget(self._label) self._layout.addWidget(self._box) self.setLayout(self._layout) def emitSignal(self, state): self.stateChanged.emit(state) def name(self): return self._name
class ThreadTemperature(QtCore.QThread): """ Thread pour la lecture de la temperature toute les 2 secondes """ TEMP =QtCore.pyqtSignal(float) # signal pour afichage temperature def __init__(self, parent=None,mte=None): super(ThreadTemperature,self).__init__(parent) self.mte = mte self.stopTemp=False def run(self): while self.mte.cam is not None: temp = self.mte.GetTemperature() time.sleep(2) self.TEMP.emit(temp) if self.stopTemp: break def stopThreadTemp(self): self.stopTemp=True print ('stop thread temperature') self.terminate()
class Worker(QtCore.QObject): finished = QtCore.pyqtSignal() def __init__(self): QtCore.QObject.__init__(self) import socket import sys self.HOST = '' # Means all if self.PORT = 30001 # Udp socket try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) print 'Socket created' except socket.error, msg: print 'Failed to create socket. Error Code : ' + str( msg[0]) + ' Message ' + msg[1] sys.exit() # Bind socket to local host and port try: self.sock.bind((self.HOST, self.PORT)) except socket.error, msg: print 'Bind failed. Error Code : ' + str( msg[0]) + ' Message ' + msg[1] sys.exit()
class DataWorker(QtCore.QObject): run_start = QtCore.pyqtSignal() run_config_data = QtCore.pyqtSignal(dict) global_config_data = QtCore.pyqtSignal(dict) filename = QtCore.pyqtSignal(dict) interpreted_data = QtCore.pyqtSignal(dict) meta_data = QtCore.pyqtSignal(dict) finished = QtCore.pyqtSignal() def __init__(self): QtCore.QObject.__init__(self) self.integrate_readouts = 1 self.n_readout = 0 self._stop_readout = Event() self.reset_lock = Lock() def connect(self, socket_addr): self.socket_addr = socket_addr self.context = zmq.Context() self.socket_pull = self.context.socket(zmq.SUB) # subscriber self.socket_pull.setsockopt(zmq.SUBSCRIBE, '') # do not filter any data self.socket_pull.connect(self.socket_addr) def process_data(self): while (not self._stop_readout.wait(0.01) ): # use wait(), do not block here with self.reset_lock: data = self.socket_pull.recv() p_hist = zlib.decompress(data) data_array = pickle.loads(p_hist) if self.integrate_readouts != 0 and self.n_readout % self.integrate_readouts == 0: interpreted_data = {'occupancy': data_array} self.interpreted_data.emit(interpreted_data) self.finished.emit() def stop(self): self._stop_readout.set()
class DropPlot(QtGui.QWidget): dropped = QtCore.pyqtSignal(list) def __init__(self, parent=None, data_range=[-100, 0]): QtGui.QWidget.__init__(self, parent=parent) self.setContentsMargins(0, 0, 0, 0) self.setAcceptDrops(True) self.layout = QtGui.QVBoxLayout() self.setLayout(self.layout) self.plotwidget = pg.PlotWidget(name='Plot1') self.plotwidget.addLegend(size=(10, 10), offset=(10, 10)) self.layout.addWidget(self.plotwidget) self.layout.setMargin(0) self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.targets_area = QtGui.QWidget() self.targets_layout = QtGui.QHBoxLayout() self.targets_area.setLayout(self.targets_layout) self.targets_area.setHidden(True) self.targets = [] self.layout.addWidget(self.targets_area) self.dataRange = data_range #sourceTarget=Curve2DBox("data", self, color=pg.intColor(len(self.targets))) #self.targets.append(sourceTarget) #self.targets_layout.addWidget(sourceTarget) def sizeHint(self): return QtCore.QSize(500, 500) def removeTarget(self, target): self.plotwidget.removeItem(target.curve) self.targets_layout.removeWidget(target) target.deleteLater() self.targets.remove(target) def rebuildLegend(self): for t in self.targets: self.plotwidget.plotItem.legend.removeItem( t.sources[1].currentName) for t in self.targets: print "adding ", t.sources[1].currentName self.plotwidget.plotItem.legend.addItem(t.curve, t.sources[1].currentName) #self.myParent.plotwidget.plotItem.legend.updateSize() def updateSource(self, source): self.source = source def updatePlot(self): for t in self.targets: t.updateValue() def dragEnterEvent(self, event): print "drag_enter plot" self.targets_area.setHidden(False) if event.mimeData().hasFormat('application/x-mavplot'): event.accept() else: event.ignore() def dropEvent(self, event): #self.updatePlot() new_source = event.source().model()._rootNode.retrieveByKey( str(event.mimeData().text()).split(':')) if new_source.__class__.__name__ == "ValueNode": self.addSource(sourceY=new_source) print "dropped on plot!" elif new_source.__class__.__name__ == "MsgNode": #add all values of the message # look for time_boot_ms: timestamp = new_source.getValueByName("time_boot_ms") for val in new_source.getChildrenNames(): val_node = new_source.getValueByName(val) print val_node.name() if val_node.name() != "time_boot_ms": self.addSource(sourceY=val_node, sourceX=timestamp) else: print "This plot doesn't accept this type:", new_source.__class__.__name__ def addSource(self, sourceX=None, sourceY=None): if (sourceX is not None and not (isinstance(sourceX.content(), int) or isinstance(sourceX.content(), float) or isinstance(sourceY.content(), list) )) or \ (sourceY is not None and not (isinstance(sourceY.content(), int) or isinstance(sourceY.content(), float) or isinstance(sourceY.content(), list))): print "cannot add this type as source:", sourceX, isinstance( sourceY.content(), list) return sourceTarget = Curve2DBox("data", self, dataRange=self.dataRange, color=pg.intColor(len(self.targets))) if sourceX is not None: sourceTarget.sources[0].updateSource(sourceX) if sourceY is not None: sourceTarget.sources[1].updateSource(sourceY) self.targets.append(sourceTarget) self.targets_layout.addWidget(sourceTarget) self.rebuildLegend() def enterEvent(self, event): self.targets_area.setHidden(False) pass def leaveEvent(self, event): self.targets_area.setHidden(True) None def mouseMoveEvent(self, event): print(event.pos()) def mousePressEvent(self, event): self.targets_area.setHidden(False) def closeEvent(self, event): while len(self.targets) > 0: self.targets[0].deleteTarget() print "closing window"
class MyParamTree(ParameterTree): """The parameter tree widget that lives in the bottom of the main window. This is where the current parameters of the application live. When a parameter here is changed by ANY method (UI, gamepad, keyboard), this object sends a signal to the MainWindow to get forward to the salient thread/object. The values are initialized from the config parameter passed in when instantiating this object. Attributes: params: a nested dictionary which contains the visable and edit-able parameters during program run-time p: the actual parameter tree object that contains the values """ paramChange = QtCore.pyqtSignal( object, object) # MyParamTree outputs a signal with param and changes. def __init__(self, config): super().__init__() self.params = [{ 'name': 'Signal Design Parameters', 'type': 'group', 'children': [{ 'name': 'Toggle Output', 'type': 'bool', 'value': False, 'tip': "Toggle the output" }, { 'name': 'Voltage Multiplier', 'type': 'float', 'value': config.defaults['vmulti'], 'step': 0.25 }, { 'name': 'Frequency', 'type': 'float', 'value': config.defaults['freq'], 'step': 10, 'siPrefix': True, 'suffix': 'Hz' }, { 'name': 'Z-Phase', 'type': 'float', 'value': config.defaults['zphase'], 'step': 90 }, { 'name': 'Field Camber', 'type': 'int', 'value': config.defaults['camber'], 'step': 1, 'siPrefix': True, 'suffix': '°' }] }, { 'name': 'Calibration', 'type': 'group', 'children': [{ 'name': 'Output Mode', 'type': 'list', 'values': ['Normal', 'Calibration'], 'value': 'Normal' }, { 'name': 'Calibration X-Voltage Ampl.', 'type': 'float', 'value': config.defaults['calib_xamp'], 'step': 0.1, 'siPrefix': True, 'suffix': 'V' }, { 'name': 'Calibration Y-Voltage Ampl.', 'type': 'float', 'value': config.defaults['calib_yamp'], 'step': 0.1, 'siPrefix': True, 'suffix': 'V' }, { 'name': 'Calibration Z-Voltage Ampl.', 'type': 'float', 'value': config.defaults['calib_zamp'], 'step': 0.1, 'siPrefix': True, 'suffix': 'V' }, { 'name': 'Z-Coefficient', 'type': 'float', 'value': config.defaults['zcoeff'], 'step': 0.001 }] }] # Create my parameter object and link it to methods self.p = Parameter.create(name='self.params', type='group', children=self.params) self.setParameters(self.p, showTop=False) self.p.sigTreeStateChanged.connect( self.sendChange) # When the params change, send to method to emit. # Connect keyPresses self.setFocusPolicy(Qt.NoFocus) def sendChange(self, param, changes): self.paramChange.emit(param, changes) # Convienience methods for modifying parameter values. def getParamValue(self, child, branch='Signal Design Parameters'): """Get the current value of a parameter.""" return self.p.param(branch, child).value() def setParamValue(self, child, value, branch='Signal Design Parameters'): """Set the current value of a parameter.""" return self.p.param(branch, child).setValue(value) def stepParamValue(self, child, delta, branch='Signal Design Parameters'): """Change a parameter by a delta. Can be negative or positive.""" param = self.p.param(branch, child) curVal = param.value() newVal = curVal + delta return param.setValue(newVal) def on_key(self, key): """ On a keypress on the plot widget, forward the keypress to the correct function below.""" qtk = QtCore.Qt # Its necessary to have this func map because the key is simply an integer I need to check against # the key dictionary in QtCore.Qt. func_map = { qtk.Key_Left: self.Key_Left, qtk.Key_Right: self.Key_Right, qtk.Key_Up: self.Key_Up, qtk.Key_Down: self.Key_Down, qtk.Key_G: self.Key_G, qtk.Key_F: self.Key_F, qtk.Key_B: self.Key_B, qtk.Key_V: self.Key_V, qtk.Key_Q: self.Key_Q, qtk.Key_W: self.Key_W, qtk.Key_T: self.Key_T } func = func_map.get(key, lambda: 'Not bound yet') return func() def Key_Left(self): self.setParamValue('Z-Phase', 90) def Key_Right(self): self.setParamValue('Z-Phase', 270) def Key_Up(self): self.setParamValue('Z-Phase', 0) def Key_Down(self): self.setParamValue('Z-Phase', 180) def Key_G(self): self.stepParamValue('Frequency', 10) def Key_F(self): self.stepParamValue('Frequency', -10) def Key_B(self): self.stepParamValue('Field Camber', 10) def Key_V(self): self.stepParamValue('Field Camber', -10) def Key_Q(self): self.stepParamValue('Voltage Multiplier', -0.25) def Key_W(self): self.stepParamValue('Voltage Multiplier', 0.25) def Key_T(self): """Toggles the toggle value""" curbool = self.getParamValue('Toggle Output') setbool = not curbool self.setParamValue('Toggle Output', setbool) def on_gamepad_event(self, gamepadEvent): """ Parses the incoming gamepad events and forwards it to the appropriate keybind function below. For ease and less repetition, some buttons are forwarded to the keyboard functions. Args: gamepadEvent (list): incoming list from the controller class of format ['button', val]. ex. ['LJOY', 45] """ func_map = { 'X': self.Key_F, 'Y': self.Key_G, 'B': self.Key_B, 'A': self.Key_V, 'LEFT_SHOULDER': self.Key_Q, 'RIGHT_SHOULDER': self.Key_W, 'LEFT_THUMB': self.Key_T, 'LJOY': self.Joystick_Left } func = func_map.get(gamepadEvent[0], lambda: 'Not bound yet') if gamepadEvent[0] == 'LJOY': return func(gamepadEvent[1]) else: return func() def Joystick_Left(self, degree): degree = 360 - degree # convert joystick degrees to a zphase that makes sense self.setParamValue('Z-Phase', degree)
class SEELIGHTTHREAD(QWidget) : '''open and plot file : SEE(file='nameFile,path=pathFileName,confpath,confMot) Make plot profile ands differents measurements(max,min mean...) Can open .spe .SPE .sif .TIFF files confpath :usefull if more than 2 SEE object used confMot usefull if RSAI motors is read ''' newMesurment=QtCore.pyqtSignal(object) def __init__(self,parent=None,file=None,path=None,**kwds): print('LightThread') super(SEELIGHTTHREAD, self).__init__() self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) # dark style self.parent=parent version=__version__ p = pathlib.Path(__file__) sepa=os.sep self.icon=str(p.parent) + sepa+'icons' +sepa ## kwds definition: if "confpath"in kwds : self.confpath=kwds["confpath"] self.conf=QtCore.QSettings(self.confpath, QtCore.QSettings.IniFormat) else: self.conf=QtCore.QSettings(str(p.parent / 'confVisu.ini'), QtCore.QSettings.IniFormat) if "name" in kwds: self.name=kwds["name"] else: self.name="VISU" if "meas" in kwds: self.meas=kwds["meas"] else: self.meas="on" if "confMot" in kwds: print('motor accepted') if self.meas=="on": self.confMot=kwds["confoMot"] self.winM=MEAS(confMot=self.confMot,conf=self.conf,name=self.name) else : if self.meas=="on": self.winM=MEAS(self,conf=self.conf,name=self.name) if "aff" in kwds: self.aff=kwds["aff"] else: self.aff="left" if "saveTiff" in kwds: self.tiff=kwds["saveTiff"] else: self.tiff=True self.nomFichier='' self.ite=None self.path=path self.setWindowTitle('Visualization'+' v.'+ version) self.bloqKeyboard=bool((self.conf.value(self.name+"/bloqKeyboard")) ) # block cross by keyboard self.bloqq=1 # block the cross by click on mouse self.setup() self.shortcut() self.actionButton() self.activateWindow() self.raise_() self.showNormal() self.setWindowIcon(QIcon(self.icon+'LOA.png')) def twoD_Gaussian(x,y, amplitude, xo, yo, sigma_x, sigma_y, theta, offset): xo = float(xo) yo = float(yo) a = (np.cos(theta)**2)/(2*sigma_x**2) + (np.sin(theta)**2)/(2*sigma_y**2) b = -(np.sin(2*theta))/(4*sigma_x**2) + (np.sin(2*theta))/(4*sigma_y**2) c = (np.sin(theta)**2)/(2*sigma_x**2) + (np.cos(theta)**2)/(2*sigma_y**2) return offset + amplitude*np.exp( - (a*((x-xo)**2) + 2*b*(x-xo)*(y-yo) + c*((y-yo)**2))) if file==None: # to have a gaussian picture when we start self.dimy=960 self.dimx=1240 # Create x and y index self.x = np.arange(0,self.dimx) self.y = np.arange(0,self.dimy) self.y,self.x = np.meshgrid(self.y, self.x) self.data=twoD_Gaussian(self.x, self.y,450, 800, 600, 40, 40, 0, 10)+(50*np.random.rand(self.dimx,self.dimy)).round() #self.data=(50*np.random.rand(self.dimx,self.dimy)).round() + 150 else: if path==None: self.path=self.conf.value(self.name+"/path") self.data=self.OpenF(fileOpen=self.path+'/'+file) self.Display(self.data) def setup(self): # definition of all button TogOff=self.icon+'Toggle_Off.png' TogOn=self.icon+'Toggle_On.png' TogOff=pathlib.Path(TogOff) TogOff=pathlib.PurePosixPath(TogOff) TogOn=pathlib.Path(TogOn) TogOn=pathlib.PurePosixPath(TogOn) self.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(%s);}""QCheckBox::indicator:checked { image: url(%s);}""QCheckBox{font :10pt;}" % (TogOff,TogOn) ) vbox1=QVBoxLayout() self.hbox0=QHBoxLayout() vbox1.addLayout(self.hbox0) hbox1=QHBoxLayout() self.checkBoxPlot=QCheckBox('CROSS',self) self.checkBoxPlot.setChecked(False) self.label_CrossValue=QLabel() self.label_CrossValue.setStyleSheet("font:13pt") hbox1.addWidget(self.checkBoxPlot) hbox1.addWidget(self.label_CrossValue) hbox2=QHBoxLayout() self.label_Cross=QLabel() #self.label_Cross.setMaximumHeight(20) self.label_Cross.setMaximumWidth(170) self.label_Cross. setStyleSheet("font:12pt") hbox2.addWidget(self.label_Cross) vbox1.addLayout(hbox1) vbox1.addLayout(hbox2) self.ZoomLabel=QLabel('Zoom') vbox1.addWidget(self.ZoomLabel) self.checkBoxZoom=QSlider(Qt.Horizontal) self.checkBoxZoom.setMaximumWidth(250) self.checkBoxZoom.setMinimum(0) self.checkBoxZoom.setMaximum(200) self.checkBoxZoom.setValue(0) vbox1.addWidget(self.checkBoxZoom) self.checkBoxScale=QCheckBox('Auto Scale',self) self.checkBoxScale.setChecked(True) self.checkBoxScale.setMaximumWidth(100) self.checkBoxColor=QCheckBox('Color',self) self.checkBoxColor.setChecked(True) self.checkBoxHist=QCheckBox('Hist',self) self.checkBoxHist.setChecked(False) self.maxGraphBox=QCheckBox('Max',self) hbox3=QHBoxLayout() grid_layout = QGridLayout() grid_layout.setVerticalSpacing(0) grid_layout.setHorizontalSpacing(10) grid_layout.addWidget(self.checkBoxScale, 0, 0) grid_layout.addWidget(self.checkBoxColor,1,0) grid_layout.addWidget(self.checkBoxHist, 0, 1) #grid_layout.addWidget(self.checkBoxZoom, 1, 0) grid_layout.addWidget(self.maxGraphBox, 1,1) hbox3.addLayout(grid_layout) vbox1.addLayout(hbox3) hbox4=QHBoxLayout() if self.meas=='on': self.MeasButton=QPushButton('Meas.') hbox4.addWidget(self.MeasButton) vbox1.addLayout(hbox4) vbox1.addStretch(1) self.winImage = pg.GraphicsLayoutWidget() #self.winImage.setContentsMargins(1,1,1,1) self.winImage.setAspectLocked(True) self.winImage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) #self.winImage.ci.setContentsMargins(1,1,1,1) vbox2=QVBoxLayout() # self.dockImage=QDockWidget(self) # self.dockImage.setWidget(self.winImage) # self.dockImage.setFeatures(QDockWidget.DockWidgetFloatable) #vbox2.addWidget(self.dockImage) vbox2.addWidget(self.winImage) vbox2.setContentsMargins(0,0,0,0) self.p1=self.winImage.addPlot() self.imh=pg.ImageItem() self.axeX=self.p1.getAxis('bottom') self.axeY=self.p1.getAxis('left') self.p1.addItem(self.imh) self.p1.setMouseEnabled(x=False,y=False) self.p1.setContentsMargins(0,0,0,0) self.p1.setAspectLocked(True,ratio=1) self.p1.showAxis('right',show=False) self.p1.showAxis('top',show=False) self.p1.showAxis('left',show=True) self.p1.showAxis('bottom',show=True) if self.bloqKeyboard==True: self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='r') self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='r') else: self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='y') self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='y') self.xc=int(self.conf.value(self.name+"/xc")) self.yc=int(self.conf.value(self.name+"/yc")) self.rx=int(self.conf.value(self.name+"/rx")) self.ry=int(self.conf.value(self.name+"/ry")) self.vLine.setPos(self.xc) self.hLine.setPos(self.yc) self.ro1=pg.EllipseROI([self.xc,self.yc],[self.rx,self.ry],pen='y',movable=False,maxBounds=QtCore.QRectF(0,0,self.rx,self.ry)) self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)]) # text for fwhm on p1 self.textX = pg.TextItem(angle=-90) self.textY = pg.TextItem() #histogram self.hist = pg.HistogramLUTItem() self.hist.setImageItem(self.imh) self.hist.autoHistogramRange() self.hist.gradient.loadPreset('flame') ## XY graph self.curve2=pg.PlotCurveItem() self.curve3=pg.PlotCurveItem() ## main layout hMainLayout=QHBoxLayout() if self.aff=='right': hMainLayout.addLayout(vbox2) hMainLayout.addLayout(vbox1) else : hMainLayout.addLayout(vbox1) hMainLayout.addLayout(vbox2) hMainLayout.setContentsMargins(1,1,1,1) hMainLayout.setSpacing(1) hMainLayout.setStretch(10,1) self.setLayout(hMainLayout) self.setContentsMargins(1,1,1,1) def actionButton(self): # action of button self.checkBoxColor.stateChanged.connect(self.Color) self.checkBoxPlot.stateChanged.connect(self.PlotXY) self.ro1.sigRegionChangeFinished.connect(self.roiChanged) self.checkBoxZoom.valueChanged.connect(self.Zoom) #self.checkBoxZoom.stateChanged.connect(self.Zoom) self.checkBoxHist.stateChanged.connect(self.HIST) self.maxGraphBox.stateChanged.connect(self.Coupe) if self.meas=='on': self.MeasButton.clicked.connect(self.Measurement,QtCore.Qt.DirectConnection) # send data to widget measurement if self.parent is not None : # reveceive data display it self.parent.dataSignal.connect(self.Display)#,QtCore.Qt.DirectConnection) def shortcut(self): # keyboard shortcut self.shortcutPu=QShortcut(QtGui.QKeySequence("+"),self) self.shortcutPu.activated.connect(self.paletteup) self.shortcutPu.setContext(Qt.ShortcutContext(3)) #3: The shortcut is active when its parent widget, or any of its children has focus. default O The shortcut is active when its parent widget has focus. self.shortcutPd=QtGui.QShortcut(QtGui.QKeySequence("-"),self) self.shortcutPd.activated.connect(self.palettedown) self.shortcutPd.setContext(Qt.ShortcutContext(3)) self.shortcutOpen=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+o"),self) self.shortcutOpen.activated.connect(self.OpenF) self.shortcutOpen.setContext(Qt.ShortcutContext(3)) self.shortcutSave=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+s"),self) self.shortcutSave.activated.connect(self.SaveF) self.shortcutSave.setContext(Qt.ShortcutContext(3)) if self.meas=='on': self.shortcutMeas=QtGui.QShortcut(QtGui.QKeySequence('Ctrl+m'),self) self.shortcutMeas.activated.connect(self.Measurement) self.shortcutMeas.setContext(Qt.ShortcutContext(3)) self.shortcutBloq=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+b"),self) self.shortcutBloq.activated.connect(self.bloquer) self.shortcutBloq.setContext(Qt.ShortcutContext(3)) self.shortcutDebloq=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+d"),self) self.shortcutDebloq.activated.connect(self.debloquer) self.shortcutDebloq.setContext(Qt.ShortcutContext(3)) # mousse action: self.proxy=pg.SignalProxy(self.p1.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) self.p1.scene().sigMouseClicked.connect(self.mouseClick) self.vb=self.p1.vb def Measurement(self) : # show widget for measurement on all image or ROI (max, min mean ...) if self.ite=='rect': self.RectChanged() self.winM.setFile(self.nomFichier) self.open_widget(self.winM) self.winM.Display(self.cut) if self.ite=='cercle': self.CercChanged() self.winM.setFile(self.nomFichier) self.open_widget(self.winM) self.winM.Display(self.cut) # if self.ite=='line': # self.LigneChanged() # self.winM.setFile(self.nomFichier) # self.open_widget(self.winM) # self.winM.Display(self.cut) if self.meas=="on": if self.ite==None: self.winM.setFile(self.nomFichier) self.open_widget(self.winM) self.winM.Display(self.data) def Display(self,data): # display the data and refresh all the calculated things and plots self.data=data self.dimy=np.shape(self.data)[1] self.dimx=np.shape(self.data)[0] self.p1.setXRange(0,self.dimx) self.p1.setYRange(0,self.dimy) self.p1.setAspectLocked(True,ratio=1) if self.checkBoxScale.isChecked()==1: # autoscale on self.imh.setImage(self.data.astype(float),autoLevels=True,autoDownsample=True) else : self.imh.setImage(self.data.astype(float),autoLevels=False,autoDownsample=True) if self.meas=="on" : if self.winM.isWinOpen==True: self.newMesurment.emit(self.data)# measurement update #self.Measurement() self.Zoom() # update zoom def mouseClick(self): # block the cross if mousse button clicked if self.bloqq==1: self.bloqq=0 else : self.bloqq=1 self.conf.setValue(self.name+"/xc",int(self.xc)) # save cross postion in ini file self.conf.setValue(self.name+"/yc",int(self.yc)) def mouseMoved(self,evt): ## the cross mouve with the mousse mvt if self.bloqKeyboard==False : #mouse not blocked by keyboard if self.bloqq==0: # mouse not blocked by mouse click pos = evt[0] ## using signal proxy turns original arguments into a tuple if self.p1.sceneBoundingRect().contains(pos): mousePoint = self.vb.mapSceneToView(pos) self.xMouse = (mousePoint.x()) self.yMouse= (mousePoint.y()) if ((self.xMouse>0 and self.xMouse<self.dimx-1) and (self.yMouse>0 and self.yMouse<self.dimy-1) ): self.xc = self.xMouse self.yc= self.yMouse self.vLine.setPos(self.xc) self.hLine.setPos(self.yc) # the cross move only in the graph #self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)]) self.PlotXY() def fwhm(self,x, y, order=3): """ Determine full-with-half-maximum of a peaked set of points, x and y. """ y=gaussian_filter(y,5) # filtre for reducing noise half_max = np.amax(y)/2.0 s = splrep(x, y - half_max,k=order) # F roots = sproot(s) # Given the knots . if len(roots) > 2: pass elif len(roots) < 2: pass else: return np.around(abs(roots[1] - roots[0]),decimals=2) def Coupe(self): # make plot profile on cross if self.maxGraphBox.isChecked()==True and self.bloqKeyboard==False: # find and fix the cross on the maximum of the image dataF=gaussian_filter(self.data,5) (self.xc,self.yc)=pylab.unravel_index(dataF.argmax(),self.data.shape) #take the max ndimage.measurements.center_of_mass(dataF)# self.vLine.setPos(self.xc) self.hLine.setPos(self.yc) dataCross=self.data[int(self.xc),int(self.yc)] coupeX=self.data[int(self.xc),:] coupeY=self.data[:,int(self.yc)] xxx=np.arange(0,int(self.dimx),1)# yyy=np.arange(0,int(self.dimy),1)# coupeXMax=np.max(coupeX) coupeYMax=np.max(coupeY) if coupeXMax==0: # avoid zero coupeXMax=1 if coupeYMax==0: coupeYMax=1 self.label_Cross.setText('x='+ str(int(self.xc)) + ' y=' + str(int(self.yc)) ) dataCross=round(dataCross,3) # take data value on the cross self.label_CrossValue.setText(' v.=' + str(dataCross)) coupeXnorm=(self.data.shape[0]/10)*(coupeX/coupeXMax) # normalize the curves self.curve2.setData(20+self.xminR+coupeXnorm,yyy,clear=True) coupeYnorm=(self.data.shape[1]/10)*(coupeY/coupeYMax) self.curve3.setData(xxx,20+self.yminR+coupeYnorm,clear=True) def PlotXY(self): # plot curves on the graph if self.checkBoxPlot.isChecked()==1: self.p1.addItem(self.vLine, ignoreBounds=False) self.p1.addItem(self.hLine, ignoreBounds=False) self.p1.addItem(self.curve2) self.p1.addItem(self.curve3) self.p1.showAxis('left',show=True) self.p1.showAxis('bottom',show=True) self.p1.addItem(self.textX) self.p1.addItem(self.textY) self.Coupe() else: self.p1.removeItem(self.vLine) self.p1.removeItem(self.hLine) self.p1.removeItem(self.curve2) self.p1.removeItem(self.curve3) self.p1.removeItem(self.textX) self.p1.removeItem(self.textY) self.p1.showAxis('left',show=False) self.p1.showAxis('bottom',show=False) self.p1.removeItem(self.textX) self.p1.removeItem(self.textY) def paletteup(self): # change the color scale levels=self.imh.getLevels() if levels[0]==None: xmax =self.data.max() xmin=self.data.min() else : xmax=levels[1] xmin=levels[0] self.imh.setLevels([xmin, xmax-(xmax- xmin) / 10]) #hist.setImageItem(imh,clear=True) self.hist.setHistogramRange(xmin,xmax) def palettedown(self): levels=self.imh.getLevels() if levels[0]==None: xmax=self.data.max() xmin=self.data.min() else : xmax=levels[1] xmin=levels[0] self.imh.setLevels([xmin, xmax+ (xmax- xmin) / 10]) #hist.setImageItem(imh,clear=True) self.hist.setHistogramRange(xmin,xmax) def Color(self): """ image in colour/n&b """ if self.checkBoxColor.isChecked()==1: self.hist.gradient.loadPreset('flame') else: self.hist.gradient.loadPreset('grey') def Zoom(self): """Zoom function """ self.zo=self.checkBoxZoom.value() # if self.checkBoxPlot.isChecked()==0: # self.xc=self.dimx/2 # self.yc=self.dimy/2 if self.zo<=2: self.zo=0 self.p1.setXRange(0,self.dimx) self.p1.setYRange(0,self.dimy) self.xminR=0 self.yminR=0 self.xmaxR=self.dimx self.ymaxR=self.dimy else: self.xminR=self.xc-(self.dimx-self.xc)*(1-self.zo/200) self.xmaxR=self.xc+(self.dimx-self.xc)*(1-self.zo/200) self.yminR=self.yc-(self.dimy-self.yc)*(1-self.zo/200) self.ymaxR=self.yc+(self.dimy-self.yc)*(1-self.zo/200) if self.xminR<0: self.xminR=0 if self.xmaxR>self.dimx: self.xmaxR=self.dimx if self.yminR<0: self.yminR=0 if self.ymaxR>self.dimy: self.ymaxR=self.dimy self.p1.setXRange(self.xminR,self.xmaxR) self.p1.setYRange(self.yminR,self.ymaxR) self.Coupe() def roiChanged(self): self.rx=self.ro1.size()[0] self.ry=self.ro1.size()[1] self.conf.setValue(self.name+"/rx",int(self.rx)) self.conf.setValue(self.name+"/ry",int(self.ry)) def bloquer(self): # block the cross self.bloqKeyboard=bool(True) self.conf.setValue(self.name+"/xc",int(self.xc))# save cross postion in ini file self.conf.setValue(self.name+"/yc",int(self.yc)) self.conf.setValue(self.name+"/bloqKeyboard",bool(self.bloqKeyboard)) self.vLine.setPen('r') self.hLine.setPen('r') def debloquer(self): # unblock the cross self.bloqKeyboard=bool(False) self.vLine.setPen('y') self.hLine.setPen('y') self.conf.setValue(self.name+"/bloqKeyboard",bool(self.bloqKeyboard)) def HIST(self): #show histogramm if self.checkBoxHist.isChecked()==1: self.winImage.addItem(self.hist) else: self.winImage.removeItem(self.hist) def OpenF(self,fileOpen=False): #open file in txt spe TIFF sif format fileOpen=fileOpen print(fileOpen) print('open') if fileOpen==False: print('ici') chemin=self.conf.value(self.name+"/path") fname=QtGui.QFileDialog.getOpenFileName(self,"Open File",chemin,"Images (*.txt *.spe *.TIFF *.sif *.tif);;Text File(*.txt);;Ropper File (*.SPE);;Andor File(*.sif);; TIFF file(*.TIFF)") fichier=fname[0] else: fichier=str(fileOpen) ext=os.path.splitext(fichier)[1] if ext=='.txt': # text file data=np.loadtxt(str(fichier)) elif ext=='.spe' or ext=='.SPE': # SPE file dataSPE=SpeFile(fichier) data1=dataSPE.data[0]#.transpose() # first frame data=data1#np.flipud(data1) elif ext=='.TIFF' or ext=='.tif':# tiff File dat=Image.open(fichier) data=np.array(dat) elif ext=='.sif': sifop=SifFile() im=sifop.openA(fichier) data=np.rot90(im,3) # self.data=self.data[250:495,:] else : msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Wrong file format !") msg.setInformativeText("The format of the file must be : .SPE .TIFF .sif or .txt ") msg.setWindowTitle("Warning ...") msg.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) msg.exec_() chemin=os.path.dirname(fichier) self.conf.setValue(self.name+"/path",chemin) self.conf.setValue(self.name+"/lastFichier",os.path.split(fichier)[1]) self.fileName.setText(os.path.split(fichier)[1]) self.nomFichier=os.path.split(fichier)[1] self.newDataReceived(data) def SaveF (self): # save data in TIFF if self.tiff==True: fname=QtGui.QFileDialog.getSaveFileName(self,"Save data as TIFF",self.path) self.path=os.path.dirname(str(fname[0])) fichier=fname[0] ext=os.path.splitext(fichier)[1] #print(ext) print(fichier,' is saved') self.conf.setValue(self.name+"/path",self.path) time.sleep(0.1) img_PIL = Image.fromarray(self.data) img_PIL.save(str(fname[0])+'.TIFF',format='TIFF') else : fname=QtGui.QFileDialog.getSaveFileName(self,"Save data as txt",self.path) self.path=os.path.dirname(str(fname[0])) fichier=fname[0] ext=os.path.splitext(fichier)[1] #print(ext) print(fichier,' is saved') self.conf.setValue(self.name+"/path",self.path) time.sleep(0.1) np.savetxt(str(fichier)+'.txt',self.data) def newDataReceived(self,data): # Do display and save origin data when new data is sent to visu self.data=data self.dimy=np.shape(self.data)[1] self.dimx=np.shape(self.data)[0] #self.Display(self.data) self.dataSignal.emit(self.data) def open_widget(self,fene): """ open new widget """ if fene.isWinOpen==False: fene.setup fene.isWinOpen=True #fene.Display(self.data) fene.show() else: #fene.activateWindow() fene.raise_() fene.showNormal() def closeEvent(self,event): # when the window is closed if self.winM.isWinOpen==True: self.winM.close()
class CrosshairTool(QtCore.QObject): """ 此类给pg.PlotWidget()添加crossHair功能,PlotWidget实例需要初始化时传入 """ signal = QtCore.pyqtSignal(type(tuple([]))) #---------------------------------------------------------------------- def __init__(self, pw, xAxis, viwe, parent=None): self.__view = viwe self.pw = pw self.xData = xAxis['tradingday'].values.tolist() self.yData = xAxis['spread'].values.tolist() super(CrosshairTool, self).__init__() self.xAxis = 0 self.yAxis = 0 # 在y轴动态mid跟随最新价显示最新价和最新时间 self.rects = [self.__view.vb.sceneBoundingRect()] self.__textDate = pg.TextItem() self.__textSig = pg.TextItem() self.__textDate.setZValue(2) self.__textSig.setZValue(2) #动态跟随 self.__textInfo = pg.TextItem('lastBarInfo') self.__textInfo.setZValue(2) self.__textInfo.border = pg.mkPen(color=(230, 255, 0, 255), width=1.2) self.__textInfo.setText(U"日期") # 注册十字光标 self.vLine = pg.InfiniteLine(angle=90, movable=False) self.hLine = pg.InfiniteLine(angle=0, movable=False) self.vLine.setPos(0) self.hLine.setPos(0) self.__view.vb.addItem(self.vLine, ignoreBounds=True) self.__view.vb.addItem(self.hLine, ignoreBounds=True) self.__view.vb.addItem(self.__textDate, ignoreBounds=True) self.__view.vb.addItem(self.__textSig, ignoreBounds=True) self.__view.vb.addItem(self.__textInfo, ignoreBounds=True) self.proxy = pg.SignalProxy(self.pw.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) # 跨线程刷新界面支持 self.signal.connect(self.update) # ---------------------------------------------------------------------- def update(self, pos): """刷新界面显示""" xAxis, yAxis = pos xAxis, yAxis = (self.xAxis, self.yAxis) if xAxis is None else (xAxis, yAxis) self.moveTo(xAxis, yAxis) # ---------------------------------------------------------------------- def mouseMoved(self, evt): pos = evt[ 0] ## using signal proxy turns original arguments into a tuple self.rects = [self.__view.vb.sceneBoundingRect()] # if self.pw.sceneBoundingRect().contains(pos): mousePoint = self.__view.vb.mapSceneToView(pos) xAxis = mousePoint.x() yAxis = mousePoint.y() self.moveTo(xAxis, yAxis) # ---------------------------------------------------------------------- def moveTo(self, xAxis, yAxis): xAxis, yAxis = (self.xAxis, self.yAxis) if xAxis is None else (xAxis, yAxis) self.rects = [self.__view.sceneBoundingRect()] if not xAxis or not yAxis: return self.xAxis = xAxis self.yAxis = yAxis self.vhLinesSetXY(xAxis, yAxis) self.plotVolue(xAxis, yAxis) # ---------------------------------------------------------------------- def vhLinesSetXY(self, xAxis, yAxis): """水平和竖线位置设置""" self.vLine.setPos(xAxis) self.hLine.setPos(yAxis) # ---------------------------------------------------------------------- def plotVolue(self, xAxis, yAxis): if xAxis < len(self.xData) and xAxis >= 0: if int(round(xAxis)) <= len(self.xData) - 1: xValueText = self.xData[int(round(xAxis))] yValue = self.yData[int(round(xAxis))] elif int(xAxis) > len(self.xData) - 1: xValueText = self.xData[len(self.xData) - 1] yValue = self.yData[len(self.xData) - 1] else: xValueText = self.xData[int(xAxis)] yValue = self.yData[int(xAxis)] else: xValueText = "" yValue = 0 self.__textDate.setHtml( U'<div style="text-align: center">\ <span style="color: yellow; font-size: 20px;">%s</span>\ </div>' \ % (xValueText)) self.__textSig.setHtml( '<div style="text-align: right">\ <span style="color: yellow; font-size: 20px;">y=%0.2f</span>\ </div>' \ % (yAxis)) self.__textInfo.setHtml( U'<div style="text-align: center"><br><br>\ <span style="color: yellow; font-size: 20px;">日期:%s</span><br>\ <span style="color: yellow; font-size: 20px;">价差:%0.2f</span>\ </div>' \ % (xValueText,yValue)) # y,右上角显示 rightAxis = self.__view.getAxis('right') rightAxisWidth = rightAxis.width() rectTextsig = self.__textDate.boundingRect() rectTextsigwidth = rectTextsig.width() topRight = self.__view.vb.mapSceneToView( QtCore.QPointF( self.rects[0].width() - (rightAxisWidth + rectTextsigwidth), self.rects[0].top())) if yAxis < self.rects[0].top(): self.__textSig.anchor = Point((1, 1)) else: self.__textSig.anchor = Point((1, 0)) self.__textSig.setPos(topRight.x(), yAxis) # X坐标 rectTextDate = self.__textDate.boundingRect() rectTextDateHeight = rectTextDate.height() bottomAxis = self.__view.getAxis('bottom') bottomAxisHeight = bottomAxis.height() bottomRight = self.__view.vb.mapSceneToView(QtCore.QPointF(self.rects[0].width(), \ self.rects[0].bottom() - ( bottomAxisHeight + rectTextDateHeight))) # # 修改对称方式防止遮挡 if xAxis > self.rects[0].width(): self.__textDate.anchor = Point((1, 0)) else: self.__textDate.anchor = Point((0, 0)) self.__textDate.setPos(xAxis, bottomRight.y()) self.__textInfo.setPos(0, (topRight.y()))
class DataWorker(QtCore.QObject): run_start = QtCore.pyqtSignal() run_config_data = QtCore.pyqtSignal(dict) global_config_data = QtCore.pyqtSignal(dict) filename = QtCore.pyqtSignal(dict) interpreted_data = QtCore.pyqtSignal(dict) meta_data = QtCore.pyqtSignal(dict) finished = QtCore.pyqtSignal() def __init__(self): QtCore.QObject.__init__(self) self.integrate_readouts = 1 self.n_readout = 0 self._stop_readout = Event() self.setup_raw_data_analysis() self.reset_lock = Lock() def setup_raw_data_analysis(self): self.interpreter = PyDataInterpreter() self.histogram = PyDataHistograming() self.interpreter.set_warning_output(False) self.histogram.set_no_scan_parameter() self.histogram.create_occupancy_hist(True) self.histogram.create_rel_bcid_hist(True) self.histogram.create_tot_hist(True) self.histogram.create_tdc_hist(True) try: self.histogram.create_tdc_distance_hist(True) self.interpreter.use_tdc_trigger_time_stamp(True) except AttributeError: self.has_tdc_distance = False else: self.has_tdc_distance = True def connect(self, socket_addr): self.socket_addr = socket_addr self.context = zmq.Context() self.socket_pull = self.context.socket(zmq.SUB) # subscriber self.socket_pull.setsockopt(zmq.SUBSCRIBE, '') # do not filter any data self.socket_pull.connect(self.socket_addr) def on_set_integrate_readouts(self, value): self.integrate_readouts = value def reset(self): with self.reset_lock: self.histogram.reset() self.interpreter.reset() self.n_readout = 0 def analyze_raw_data(self, raw_data): self.interpreter.interpret_raw_data(raw_data) self.histogram.add_hits(self.interpreter.get_hits()) def process_data( self ): # infinite loop via QObject.moveToThread(), does not block event loop while (not self._stop_readout.wait(0.01) ): # use wait(), do not block here with self.reset_lock: try: meta_data = self.socket_pull.recv_json(flags=zmq.NOBLOCK) except zmq.Again: pass else: name = meta_data.pop('name') if name == 'ReadoutData': data = self.socket_pull.recv() # reconstruct numpy array buf = buffer(data) dtype = meta_data.pop('dtype') shape = meta_data.pop('shape') data_array = np.frombuffer(buf, dtype=dtype).reshape(shape) # count readouts and reset self.n_readout += 1 if self.integrate_readouts != 0 and self.n_readout % self.integrate_readouts == 0: self.histogram.reset() # we do not want to reset interpreter to keep the error counters # self.interpreter.reset() # interpreted data self.analyze_raw_data(data_array) if self.integrate_readouts == 0 or self.n_readout % self.integrate_readouts == self.integrate_readouts - 1: interpreted_data = { 'occupancy': self.histogram.get_occupancy(), 'tot_hist': self.histogram.get_tot_hist(), 'tdc_counters': self.interpreter.get_tdc_counters(), 'tdc_distance': self.interpreter.get_tdc_distance() if self.has_tdc_distance else np.zeros( (256, ), dtype=np.uint8), 'error_counters': self.interpreter.get_error_counters(), 'service_records_counters': self.interpreter.get_service_records_counters( ), 'trigger_error_counters': self.interpreter.get_trigger_error_counters(), 'rel_bcid_hist': self.histogram.get_rel_bcid_hist() } self.interpreted_data.emit(interpreted_data) # meta data meta_data.update({ 'n_hits': self.interpreter.get_n_hits(), 'n_events': self.interpreter.get_n_events() }) self.meta_data.emit(meta_data) elif name == 'RunConf': self.run_config_data.emit(meta_data) elif name == 'GlobalRegisterConf': trig_count = int(meta_data['conf']['Trig_Count']) self.interpreter.set_trig_count(trig_count) self.global_config_data.emit(meta_data) elif name == 'Reset': self.histogram.reset() self.interpreter.reset() self.run_start.emit() elif name == 'Filename': self.filename.emit(meta_data) self.finished.emit() def stop(self): self._stop_readout.set()
class evd_manager_base(QtCore.QObject): eventChanged = QtCore.pyqtSignal() drawFreshRequested = QtCore.pyqtSignal() metaRefreshed = QtCore.pyqtSignal(event_meta3D) """docstring for lariat_manager""" def __init__(self, config, _file=None): super(evd_manager_base, self).__init__() QtCore.QObject.__init__(self) # self.init_manager(_file) def init_manager(self, _file): self._entry = 0 self._io_manager = gate.Centella.instance(gate.MUTE) self._io_manager.addInputFile(_file) self._io_manager.initialize() self._entry = 0 self._run = 0 self._Run = None self._Event = None self.go_to_entry(0) # # Meta keeps track of information about number of planes, visible # # regions, etc.: self._meta = event_meta3D() # Drawn classes is a list of things getting drawn, as well. self._drawnClasses = dict() self._keyTable = dict() self._meta.refresh() def meta(self): return self._meta # This function returns the list of products that can be drawn: def getDrawableProducts(self): return self._drawableItems.getDict() # def internalEvent(self): def entry(self): return self._entry def run(self): return self._run def event(self): return self._Event.GetEventID() def n_entries(self): if self._io_manager is not None: return self._io_manager.getNumEventsFile() else: return 0 def n_runs(self): if self._io_manager is not None: return self._io_manager.getNumRunsFile() else: return 0 # override the functions from manager as needed here def next(self): if self.entry() + 1 < self.n_entries(): # print self._driver.event() self.go_to_entry(self._entry + 1) else: print "On the last event, can't go to next." def prev(self): if self.entry != 0: self.go_to_entry(self._entry - 1) else: print "On the first event, can't go to previous." def go_to_entry(self, entry): if entry >= 0 and entry < self.n_entries(): self._entry = entry self._Event = self._io_manager.read(self._entry) if self._Run is None or self._io_manager.isNewFile(): self._Run = self._io_manager.read_irun_info(self._run) # Temporary, listing available things: # print "GetEnergy size: {}".format(self._Event.GetEnergy().size()) print "GetHits size: {}".format(self._Event.GetHits().size()) print "GetHitMaps size: {}".format(self._Event.GetHitMaps().size()) print "GetClusters size: {}".format( self._Event.GetClusters().size()) print "GetTracks size: {}".format(self._Event.GetTracks().size()) print "GetSignals size: {}".format(self._Event.GetSignals().size()) print "GetParticles size: {}".format( self._Event.GetParticles().size()) print "GetMCHits size: {}".format(self._Event.GetMCHits().size()) print "GetMCSensHits size: {}".format( self._Event.GetMCSensHits().size()) print "GetMCTracks size: {}".format( self._Event.GetMCTracks().size()) print "GetMCParticles size: {}".format( self._Event.GetMCParticles().size()) print self.eventChanged.emit() else: print "Can't go to entry {}, entry is out of range.".format(entry)
class scatterPlot(QWidget): signalAdded = QtCore.pyqtSignal('QString') scatterSelectionChanged = QtCore.pyqtSignal('QString', 'QString') def __init__(self, stripplot=None, parent=None, plotRateBar=False, selectionBar=True, color=0): super(scatterPlot, self).__init__(parent) self.pg = pg self.paused = True self.signalLength = 10 self.plotrate = 1 self.plotScaleConnection = True self.pauseIcon = QtGui.QIcon( str(os.path.dirname(os.path.abspath(__file__))) + '\icons\pause.png') ''' create the scatterPlot as a grid layout ''' self.scatterPlot = QtGui.QVBoxLayout() self.plotThread = QTimer() if not stripplot == None: self.stripPlot = stripplot self.records = stripplot.records else: self.stripPlot = self self.records = {} self.globalPlotRange = [-1000, 0] ''' Create generalPlot object ''' self.plotWidget = scatterPlotPlot(self, color=color) ''' If connected to stripplot - link plotranges ''' if not stripplot == None: self.stripPlot.plotWidget.changePlotScale.connect( self.plotWidget.setPlotRange) ''' set-up setupSelectionBar ''' self.selectionBar = self.setupSelectionBar() ''' set-up plot rate slider ''' self.setupPlotRateSlider() selectionBarOffset = 0 if selectionBar: self.scatterPlot.addLayout(self.selectionBarLayout, 1) self.stripPlot.signalAdded.connect(self.updateSelectionBar) self.stripPlot.signalRemoved.connect(self.updateSelectionBar) selectionBarOffset = 1 self.scatterPlot.addWidget(self.plotWidget.plotWidget, 5) if plotRateBar: self.scatterPlot.addWidget(self.plotRateLabel, selectionBarOffset + 5, 0) self.scatterPlot.addWidget(self.plotRateSlider, selectionBarOffset + 5, 1) self.setLayout(self.scatterPlot) logger.debug('scatterPlot initiated!') def saveAllCurves(self, saveFileName=None): for name in self.records: if self.records[name]['parent'] == self: filename, file_extension = os.path.splitext(saveFileName) saveFileName2 = filename + '_' + self.records[name][ 'name'] + file_extension self.legend.saveCurve(self.records[name]['name'], saveFileName2) def saveCurve(self, name, saveFileName=None): self.legend.saveCurve(name, saveFileName) def setupSelectionBar(self): spacer = QtGui.QSpacerItem(100, 20) self.combobox1 = QtGui.QComboBox() self.combobox1.setMaximumWidth(200) self.combobox1.setMinimumWidth(100) # self.combobox1.setMaximumHeight(20) self.combobox1.currentIndexChanged.connect(self.selectionBarChanged) self.combobox2 = QtGui.QComboBox() self.combobox2.setMaximumWidth(200) self.combobox2.setMinimumWidth(100) # self.combobox2.setMaximumHeight(20) self.combobox2.currentIndexChanged.connect(self.selectionBarChanged) for name in sorted(self.records): self.combobox1.addItem(name) self.combobox2.addItem(name) self.combobox1.setCurrentIndex(0) self.combobox2.setCurrentIndex(1) self.selectionBarLayout = QtGui.QHBoxLayout() self.selectionBarLayout.addSpacerItem(spacer) self.selectionBarLayout.addWidget(self.combobox1) self.selectionBarLayout.addSpacerItem(spacer) self.selectionBarLayout.addWidget(self.combobox2) self.selectionBarLayout.addSpacerItem(spacer) def selectionBarChanged(self, index): # print 'index = ', index self.scatterSelectionChanged.emit(self.combobox1.currentText(), self.combobox2.currentText()) self.plotWidget.update() def updateSelectionBar(self): combobox1text = self.combobox1.currentText() combobox2text = self.combobox2.currentText() allnames = [] for name in sorted(self.records): allnames.append(name) if self.combobox1.findText(name) == -1: self.combobox1.addItem(name) self.combobox2.addItem(name) for index in range(self.combobox1.count()): if not self.combobox1.itemText(index) in allnames: self.combobox1.removeItem(index) self.combobox2.removeItem(index) else: if self.combobox1.itemText(index) == combobox1text: self.combobox1.setCurrentIndex(index) if self.combobox2.itemText(index) == combobox2text: self.combobox2.setCurrentIndex(index) def setupPlotRateSlider(self): self.plotRateLabel = QtGui.QLabel() self.plotRateLabel.setText('Plot Update Rate [' + str(self.plotrate) + ' Hz]:') self.plotRateLabel.setAlignment(Qt.AlignCenter) self.plotRateSlider = QtGui.QSlider() self.plotRateSlider.setOrientation(QtCore.Qt.Horizontal) self.plotRateSlider.setInvertedAppearance(False) self.plotRateSlider.setInvertedControls(False) self.plotRateSlider.setMinimum(1) self.plotRateSlider.setMaximum(50) self.plotRateSlider.setValue(self.plotrate) self.plotRateSlider.valueChanged.connect(self.setPlotRate) def setPlotRate(self, value): self.plotrate = value self.plotRateLabel.setText('Plot Update Rate [' + str(self.plotrate) + ' Hz]:') self.plotThread.setInterval(1000 * 1 / value) def start(self, timer=1000): self.plotUpdate() self.plotThread.start(timer) self.plotThread.timeout.connect(self.plotUpdate) def addSignal(self, name, pen, timer, function, *args): if not name in self.records: signalrecord = createSignalRecord(records=self.records, name=name, timer=timer, function=function, *args) self.records[name]['record'] = signalrecord self.records[name]['parent'] = self self.records[name]['pen'] = pen self.signalAdded.emit(name) logger.info('Signal ' + name + ' added!') else: logger.warning('Signal ' + name + ' already exists!') def plotUpdate(self): self.plotWidget.currentPlotTime = time.time() self.plotWidget.update() def removeSignal(self, name): del self.records[name] logger.info('Signal ' + name + ' removed!') def pausePlotting(self, value=True): self.paused = value self.plotWidget.togglePause(self.paused) def setDecimateLength(self, value=5000): self.plotWidget.decimateScale = value def setPlotRange(self, plotrange): self.plotWidget.setPlotRange(plotrange) def setPlotScale(self, xRange=None, yRange=None): self.plotWidget.setPlotScale(xRange=xRange, yRange=yRange)
class Helper(QtCore.QObject): update = QtCore.pyqtSignal()
class DataGridderWidget(QtGui.QWidget): NOGRID = 1 GUESSSHAPE = 2 SPECIFYSHAPE = 3 FINDGRID = 4 optionSelected = QtCore.pyqtSignal(object) ## Decorators for GUI/Node communication ## # TODO: those should eventually go into the Node base class def updateGuiFromNode(func): # @wraps(func) def wrap(self, *arg, **kw): self._emitGuiChange = False ret = func(self, *arg, **kw) self._emitGuiChange = True return ret return wrap def emitGuiUpdate(signalName): def decorator(func): # @wraps(func) def wrap(self, *arg, **kw): ret = func(self, *arg, **kw) if self._emitGuiChange: sig = getattr(self, signalName) sig.emit(ret) return wrap return decorator def __init__(self, parent=None): super().__init__(parent) self._emitGuiChange = True ## make radio buttons and layout ## self.buttons = { self.NOGRID: QtGui.QRadioButton('No grid'), self.GUESSSHAPE: QtGui.QRadioButton('Guess shape'), self.SPECIFYSHAPE: QtGui.QRadioButton('Specify shape'), } btnLayout = QtGui.QVBoxLayout() self.btnGroup = QtGui.QButtonGroup(self) for i in [self.NOGRID, self.GUESSSHAPE, self.SPECIFYSHAPE]: btn = self.buttons[i] self.btnGroup.addButton(btn, i) btnLayout.addWidget(btn) btnBox = QtGui.QGroupBox('Grid') btnBox.setLayout(btnLayout) ## make shape spec widget ## self.shapeSpec = ShapeSpecification() shapeLayout = QtGui.QVBoxLayout() shapeLayout.addWidget(self.shapeSpec) shapeBox = QtGui.QGroupBox('Shape') shapeBox.setLayout(shapeLayout) # Widget layout layout = QtGui.QHBoxLayout() layout.addWidget(btnBox) layout.addWidget(shapeBox) layout.addStretch() self.setLayout(layout) ## Connect signals/slots ## self.btnGroup.buttonToggled.connect(self.gridButtonSelected) self.shapeSpec.confirm.clicked.connect(self.shapeSpecified) def getGrid(self): activeBtn = self.btnGroup.checkedButton() activeId = self.btnGroup.id(activeBtn) if activeId == self.GUESSSHAPE: return 'guess' elif activeId == self.SPECIFYSHAPE: return self.shapeSpec.getShape() elif activeId == self.NOGRID: return False else: return None @QtCore.pyqtSlot(QtGui.QAbstractButton, bool) def gridButtonSelected(self, btn, checked): if checked: self.signalGridOption(self.getGrid()) @QtCore.pyqtSlot() def shapeSpecified(self): shape = self.shapeSpec.getShape() self.signalGridOption(shape) @emitGuiUpdate('optionSelected') def signalGridOption(self, grid): return grid ## methods for setting from the node ## @updateGuiFromNode def setGrid(self, val): if isinstance(val, tuple): self.setShape(val) self.shapeSpec.enableEditing(True) self.buttons[self.SPECIFYSHAPE].setChecked(True) else: self.shapeSpec.enableEditing(False) if val == 'guess': self.buttons[self.GUESSSHAPE].setChecked(True) if val == False: self.buttons[self.NOGRID].setChecked(True) @QtCore.pyqtSlot(list) @updateGuiFromNode def setAxes(self, axes): self.shapeSpec.setAxes(axes) self.setGrid(self.getGrid()) @QtCore.pyqtSlot(tuple) @updateGuiFromNode def setShape(self, shape): self.shapeSpec.setShape(shape)
class DataGridder(Node): """ A node that can put data onto or off a grid. Has one property: grid. That can have the following values: * ... """ nodeName = "Gridder" uiClass = DataGridderWidget guiOptions = { 'grid': { 'widget': None, 'setFunc': 'setGrid', } } shapeDetermined = QtCore.pyqtSignal(tuple) axesList = QtCore.pyqtSignal(list) def __init__(self, *arg, **kw): self._grid = None self._shape = None self._invalid = False super().__init__(*arg, **kw) if self.ui is not None: self.axesList.connect(self.ui.setAxes) self.shapeDetermined.connect(self.ui.setShape) ### Properties @property def grid(self): return self._grid @grid.setter @Node.updateOption('grid') def grid(self, val): self._invalid = False if isinstance(val, tuple): try: self._grid = tuple(int(s) for s in val) except ValueError: self._invalid = True self.logger().error(f"Invalid grid option {val}") raise elif val in [None, False, 'guess']: self._grid = val else: self._invalid = True self.logger().error(f"Invalid grid option {val}") ### Processing def process(self, **kw): data = super().process(**kw) if data is None: return None data = data['dataOut'] if self.ui is not None: self.updateUiDataIn(data) dout = None shape = tuple() if self._invalid: return None if self._grid is None: dout = data elif self._grid is False and isinstance(data, DataDict): dout = data elif self._grid is False and isinstance(data, MeshgridDataDict): dout = dd.meshgrid_to_datadict(data) elif self._grid == 'guess' and isinstance(data, DataDict): dout = dd.datadict_to_meshgrid(data) elif self._grid == 'guess' and isinstance(data, MeshgridDataDict): dout = data elif isinstance(self._grid, tuple): dout = dd.datadict_to_meshgrid(data, target_shape=self._grid) else: self.logger().error( f"Unknown grid option {self._grid}. Most likely a bug :/") return None if dout is None: return None if self.ui is not None: self.updateUiDataOut(dout) return dict(dataOut=dout) ### Setup UI def setupUi(self): self.ui.setGrid(self._grid) self.ui.optionSelected.connect(self._setGrid) def updateUiDataOut(self, data): if isinstance(data, MeshgridDataDict): shape = data.shape() else: shape = tuple() self.shapeDetermined.emit(shape) def updateUiDataIn(self, data): axes = data.axes() self.axesList.emit(axes) ### Receiving UI changes @QtCore.pyqtSlot(object) def _setGrid(self, val): self.grid = val
class clusterParams(QtCore.QObject): # recoBase): """docstring for clusterParams""" mouseEnter = QtCore.pyqtSignal(QtGui.QGraphicsSceneHoverEvent) mouseExit = QtCore.pyqtSignal(QtGui.QGraphicsSceneHoverEvent) highlightChange = QtCore.pyqtSignal() def __init__(self, params, geom): super(clusterParams, self).__init__() self._listOfStartPoints = [] self._params = params self._geom = geom self._isHighlighted = False # Some member params i'm not filling forrectly. def setParams(self, params): self._params = params def hoverEnter(self, e): for circle in self._listOfStartPoints: circle.setPen(pg.mkPen((0, 0, 0), width=1)) # When the function is called from a box, the sender is none # When its passed from the params, the sender is something if self.sender() == None: self.mouseEnter.emit(e) def hoverExit(self, e): if self._isHighlighted: return for circle in self._listOfStartPoints: circle.setPen(pg.mkPen(None)) # When the function is called from a box, the sender is none # When its passed from the params, the sender is something if self.sender() == None: self.mouseExit.emit(e) def toggleHighlight(self): self._isHighlighted = not self._isHighlighted # When the function is called from a box, the sender is none # When its passed from the params, the sender is something if self.sender() == None: self.highlightChange.emit() # Can connect clusterparams to other clusterparams or to box collections def connect(self, other): self.mouseEnter.connect(other.hoverEnter) self.mouseExit.connect(other.hoverExit) self.highlightChange.connect(other.toggleHighlight) def genToolTip(self): return self.toolTip() def toolTip(self): tip = "Hits: \t\t " + str(self._params.N_Hits) + "\n" tip += "Start: \t\t (" + "{:.2f}".format(self._params.start_point.w) + ", " tip += "{:.2f}".format(self._params.start_point.t) + ")\n" tip += ("Shower Start \t (" + "{:.2f}".format(self._params.showering_point.w) + ", ") tip += "{:.2f}".format(self._params.showering_point.t) + ")\n" tip += "End: \t\t (" + "{:.2f}".format(self._params.end_point.w) + ", " tip += "{:.2f}".format(self._params.end_point.t) + ")\n" if self._params.principal_dir[0] != 0: slope = self._params.principal_dir[1]/self._params.principal_dir[0] tip += ("Slope: \t\t " + "{:.2f}".format(slope) + "\n") else: tip += "Slope: \t\t inf\n" if self._params.start_dir[0] != 0: tip += "Start Slope: \t " + \ "{:.2f}".format( self._params.start_dir[1]/self._params.start_dir[0]) + "\n" else: tip += "Start Slope: \t inf\n" tip += "Angle: \t\t " + "{:.2f}".format(self._params.angle_2d) + "\n" tip += "\n" fannVec = vector(float)() self._params.GetFANNVector(fannVec) fannTitle = self._params.GetFANNVectorTitle() for title, value in zip(fannTitle,fannVec): tip += "{:.2f}: ".format(value) + "{title}\n".format(title=title) tip += "\nAdd more in python/datatypes/cluster.py:clusterParams:toolTip!" return tip def draw(self, view): # This function is responsible for all clusterparams drawing red = (255, 0, 0) green = (0, 255, 0) black = (0, 0, 0) blue = (0, 0, 255) planeOffset = view._geometry.planeOriginX(self._params.plane_id.Plane) trigOffset = view._geometry.triggerOffset() t2cm = view._geometry.time2cm(); w2cm = view._geometry.wire2cm(); # Draw the start and end points: sW = self._params.start_point.w / w2cm sT = (self._params.start_point.t - planeOffset) / t2cm + trigOffset eW = self._params.end_point.w / w2cm eT = (self._params.end_point.t - planeOffset) / t2cm + trigOffset showeringW = self._params.showering_point.w / w2cm showeringT = (self._params.showering_point.t - planeOffset) / t2cm + trigOffset radBigW = 0.5 / self._geom.wire2cm() radBigT = (0.5) / self._geom.time2cm() radSmallW = 0.25 / self._geom.wire2cm() radSmallT = (0.25) / self._geom.time2cm() bigCircleStart = connectedCircle( sW-radBigW, sT-radBigT, 2*radBigW, 2*radBigT) if self._isHighlighted: bigCircleStart.setPen(pg.mkPen(black)) else: bigCircleStart.setPen(pg.mkPen(None)) bigCircleStart.setBrush(pg.mkColor(green)) bigCircleStart.setOpacity(0.6) bigCircleStart.connectOwnerHoverEnter(self.hoverEnter) bigCircleStart.connectOwnerHoverExit(self.hoverExit) bigCircleStart.connectToggleHighlight(self.toggleHighlight) bigCircleStart.connectToolTip(self.genToolTip) smallCircleStart = QtGui.QGraphicsEllipseItem( sW-radSmallW, sT-radSmallT, 2*radSmallW, 2*radSmallT) smallCircleStart.setPen(pg.mkPen(None)) smallCircleStart.setBrush(pg.mkColor(black)) bigCircleEnd = connectedCircle( eW-radBigW, eT-radBigT, 2*radBigW, 2*radBigT) bigCircleEnd.setPen(pg.mkPen(None)) bigCircleEnd.setBrush(pg.mkColor(red)) bigCircleEnd.setOpacity(0.6) bigCircleEnd.connectOwnerHoverEnter(self.hoverEnter) bigCircleEnd.connectOwnerHoverExit(self.hoverExit) bigCircleEnd.connectToggleHighlight(self.toggleHighlight) bigCircleEnd.connectToolTip(self.genToolTip) smallCircleEnd = QtGui.QGraphicsEllipseItem( eW-radSmallW, eT-radSmallT, 2*radSmallW, 2*radSmallT) smallCircleEnd.setPen(pg.mkPen(None)) smallCircleEnd.setBrush(pg.mkColor(black)) radW = 0.5 / self._geom.wire2cm() radT = (0.5) / self._geom.time2cm() showeringPoint = connectedCircle( showeringW - radW, showeringT - radT, 2*radW, 2*radT) showeringPoint.setBrush(pg.mkColor(blue)) showeringPoint.setOpacity(0.6) showeringPoint.connectOwnerHoverEnter(self.hoverEnter) showeringPoint.connectOwnerHoverExit(self.hoverExit) showeringPoint.connectToggleHighlight(self.toggleHighlight) showeringPoint.connectToolTip(self.genToolTip) self._listOfStartPoints.append(bigCircleStart) self._listOfStartPoints.append(smallCircleStart) self._listOfStartPoints.append(bigCircleEnd) self._listOfStartPoints.append(smallCircleEnd) self._listOfStartPoints.append(showeringPoint) view._view.addItem(bigCircleStart) view._view.addItem(smallCircleStart) view._view.addItem(bigCircleEnd) view._view.addItem(smallCircleEnd) view._view.addItem(showeringPoint) ######################################## # 2D Polygon Drawing ######################################## # Not super hard to do with the poly object self._thisPolyF = QtGui.QPolygonF() for p in xrange(self._params.PolyObject.Size()): point = self._params.PolyObject.Point(p) qpoint = QtCore.QPointF( point.first / w2cm, (point.second - planeOffset) / t2cm + trigOffset) self._thisPolyF.append(qpoint) self._thisPoly = QtGui.QGraphicsPolygonItem(self._thisPolyF) pen = self._thisPoly.pen() pen.setStyle(QtCore.Qt.DashLine) self._thisPoly.setPen(pen) view._view.addItem(self._thisPoly) ######################################## # 2D Principal Axis Drawing ######################################## # Draw the axis # The axis is just a line between two points. self._axisPolygon = QtGui.QPolygonF() self._axisPolygon.append(QtCore.QPointF(sW, sT)) l = self._params.length if l < 1: l = (self._params.start_point.w - self._params.end_point.w)**2 l += (self._params.start_point.t - self._params.end_point.t)**2 l = math.sqrt(l) axisEndW = sW + l*self._params.principal_dir.at(0)/self._geom.wire2cm() axisEndT = sT + (l*self._params.principal_dir.at(1)) / \ self._geom.time2cm() # Check to see if this line needs to be reversed: sign = (sW - axisEndW)*(sW - eW) + (sT - axisEndT)*(sT - eT) if sign < 0: axisEndW = sW - l * \ self._params.principal_dir.at(0)/self._geom.wire2cm() axisEndT = sT - \ (l*self._params.principal_dir.at(1))/self._geom.time2cm() self._axisPolygon.append(QtCore.QPointF(axisEndW, axisEndT)) self._axisPath = QtGui.QPainterPath() self._axisPath.addPolygon(self._axisPolygon) self._polyGraphicsItem = QtGui.QGraphicsPathItem(self._axisPath) pen = self._polyGraphicsItem.pen() pen.setWidth(2) pen.setBrush(pg.mkColor((0, 0, 0, 125))) self._polyGraphicsItem.setPen(pen) view._view.addItem(self._polyGraphicsItem) ######################################## # 2D Start Axis Drawing ######################################## # Draw an line to show the start direction of the shower self._startAxis = QtGui.QPolygonF() self._startAxis.append(QtCore.QPointF(sW, sT)) startDirEndW = sW + l*self._params.start_dir.at(0)/self._geom.wire2cm() startDirEndT = sT + \ (l*self._params.start_dir.at(1))/self._geom.time2cm() # print sign sign = (sW - startDirEndW)*(sW - eW) + (sT - startDirEndT)*(sT - eT) if sign < 0: startDirEndW = sW - l * \ self._params.start_dir.at(0)/self._geom.wire2cm() startDirEndT = sT - \ (l*self._params.start_dir.at(1))/self._geom.time2cm() self._startAxis.append(QtCore.QPointF(startDirEndW, startDirEndT)) self._startAxisPath = QtGui.QPainterPath() self._startAxisPath.addPolygon(self._startAxis) self._startAxisPolyItem = QtGui.QGraphicsPathItem(self._startAxisPath) pen = self._startAxisPolyItem.pen() pen.setWidth(1) pen.setStyle(QtCore.Qt.DashLine) pen.setBrush(pg.mkColor((0, 0, 0, 200))) self._startAxisPolyItem.setPen(pen) view._view.addItem(self._startAxisPolyItem) def clear(self, view): # This function clears all of this cluster params # for item in self._listOfStartPoints: view._view.removeItem(item) self._listOfStartPoints = [] view._view.removeItem(self._thisPoly) view._view.removeItem(self._polyGraphicsItem) view._view.removeItem(self._startAxisPolyItem)
class TempestaSLMKatanaGUI(QtGui.QMainWindow): """Main GUI class. This class calls other modules in the control folder :param Laser greenlaser: object controlling one laser :param Laser redlaser: object controlling one laser :param Laser stedlaser: object controlling one laser :param Camera orcaflash: object controlling a CCD camera :param SLMdisplay slm: object controlling a SLM :param Scanner scanXY: object controlling a Marzhauser XY-scanning stage :param Scanner scanZ: object controlling a Piezoconcept Z-scanning inset """ liveviewStarts = QtCore.pyqtSignal() liveviewEnds = QtCore.pyqtSignal() #def __init__(self, stedlaser, slm, scanZ, scanXY, webcamFocusLock, # webcamWidefield, aotf, leicastand, *args, **kwargs): def __init__(self, stedlaser, slm, scanZ, scanXY, webcamFocusLock, aotf, leicastand, *args, **kwargs): super().__init__(*args, **kwargs) # os.chdir('C:\\Users\\STEDred\Documents\TempestaSnapshots') self.slm = slm self.scanZ = scanZ self.aotf = aotf self.scanXY = scanXY self.dmi8 = leicastand self.imspector = sp.Imspector() self.filewarning = FileWarning() self.s = Q_(1, 's') self.lastTime = time.clock() self.fps = None # Actions in menubar menubar = self.menuBar() fileMenu = menubar.addMenu('&File') self.savePresetAction = QtGui.QAction('Save configuration...', self) self.savePresetAction.setShortcut('Ctrl+S') self.savePresetAction.setStatusTip('Save camera & recording settings') savePresetFunction = lambda: guitools.savePreset(self) self.savePresetAction.triggered.connect(savePresetFunction) fileMenu.addAction(self.savePresetAction) fileMenu.addSeparator() self.exportTiffAction = QtGui.QAction('Export HDF5 to Tiff...', self) self.exportTiffAction.setShortcut('Ctrl+E') self.exportTiffAction.setStatusTip('Export HDF5 file to Tiff format') self.exportTiffAction.triggered.connect(guitools.TiffConverterThread) fileMenu.addAction(self.exportTiffAction) self.exportlastAction = QtGui.QAction('Export last recording to Tiff', self) self.exportlastAction.setEnabled(False) self.exportlastAction.setShortcut('Ctrl+L') self.exportlastAction.setStatusTip('Export last recording to Tiff ' + 'format') fileMenu.addAction(self.exportlastAction) fileMenu.addSeparator() exitAction = QtGui.QAction(QtGui.QIcon('exit.png'), '&Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(QtGui.QApplication.closeAllWindows) fileMenu.addAction(exitAction) # Potentially remove all this? self.presetsMenu = QtGui.QComboBox() self.presetDir = datapath if not (os.path.isdir(self.presetDir)): self.presetDir = os.path.join(os.getcwd(), 'control\\Presets') for preset in os.listdir(self.presetDir): self.presetsMenu.addItem(preset) self.loadPresetButton = QtGui.QPushButton('Load preset') loadPresetFunction = lambda: guitools.loadPreset(self) self.loadPresetButton.pressed.connect(loadPresetFunction) # Dock widget dockArea = DockArea() # Laser Widget laserDock = Dock("Laser Control", size=(400, 500)) self.lasers = stedlaser self.laserWidgets = LaserWidget.LaserWidget(self.lasers, self.aotf) laserDock.addWidget(self.laserWidgets) dockArea.addDock(laserDock, 'right') # SLM widget slmDock = Dock("SLM", size=(400, 300)) self.slmWidget = slmWidget.slmWidget(self.slm) slmDock.addWidget(self.slmWidget) dockArea.addDock(slmDock, "bottom", laserDock) # Widefield camera widget #widefieldDock = Dock("Widefield", size=(500, 500)) #self.widefieldWidget = widefield.WidefieldWidget(webcamWidefield) #widefieldDock.addWidget(self.widefieldWidget) #dockArea.addDock(widefieldDock, "left") # Focus lock widget focusDock = Dock("Focus lock", size=(500, 500)) self.focusWidget = focus.FocusWidget(self.scanZ, webcamFocusLock, self.imspector) focusDock.addWidget(self.focusWidget) #dockArea.addDock(focusDock, "below", widefieldDock) dockArea.addDock(focusDock, "left") # Timelapse widget timelapseDock = Dock("Timelapse", size=(500, 200)) self.timelapseWidget = timelapse.TimelapseWidget(self.imspector) timelapseDock.addWidget(self.timelapseWidget) #dockArea.addDock(timelapseDock, "top", widefieldDock) dockArea.addDock(timelapseDock, "top", focusDock) # Objective mot_corr widget motcorrDock = Dock("Glycerol motCORR", size=(500, 200)) self.MotcorrWidget = motcorr.MotcorrWidget(self.dmi8) motcorrDock.addWidget(self.MotcorrWidget) dockArea.addDock(motcorrDock, "below", timelapseDock) # XY-scanner tiling widget tilingDock = Dock("Tiling", size=(500, 200)) self.tilingWidget = tiling.TilingWidget(self.scanXY, self.focusWidget, self.imspector) tilingDock.addWidget(self.tilingWidget) dockArea.addDock(tilingDock, "below", timelapseDock) self.setWindowTitle('Tempesta - RedSTED edition') self.cwidget = QtGui.QWidget() self.setCentralWidget(self.cwidget) # Widgets' layout layout = QtGui.QGridLayout() self.cwidget.setLayout(layout) # layout.setColumnMinimumWidth(0, 100) # layout.setColumnMinimumWidth(1, 350) # layout.setColumnMinimumWidth(2, 150) # layout.setColumnMinimumWidth(3, 200) # layout.setRowMinimumHeight(0, 350) # layout.setRowMinimumHeight(1, 350) # layout.setRowMinimumHeight(2, 350) # layout.setRowMinimumHeight(3, 30) layout.addWidget(dockArea, 0, 3, 5, 1) # layout.addWidget(self.scanxyWidget,0, 2, 5, 1) # layout.setRowMinimumHeight(2, 40) # layout.setColumnMinimumWidth(2, 1000) def closeEvent(self, *args, **kwargs): """closes the different devices. Resets the NiDaq card, turns off the lasers and cuts communication with the SLM""" try: self.lvthread.terminate() except: pass self.laserWidgets.closeEvent(*args, **kwargs) self.slmWidget.closeEvent(*args, **kwargs) super().closeEvent(*args, **kwargs)
class QTApp(QtCore.QObject): ready = QtCore.pyqtSignal(bool) def __init__(self): self.app = QtWidgets.QApplication(sys.argv) self.main_window = MainWindow() self.main_window.app = self set_window_icon(self.main_window) self.device_manager = DeviceManager() self.device_manager.app = self self.device_manager.show() self.psd_window = PSDWindow() self.psd_window.app = self self.app.aboutToQuit.connect(lambda: self.app.quit()) super().__init__() def connected(self, connection, parameters, control): self.device_manager.hide() self.main_window.show(connection.host, connection.device["name"]) self.connection = connection self.control = control self.parameters = parameters self.ready.connect(self.init) self.ready.emit(True) def init(self): for instance in CustomWidget.instances: try: instance.connection_established() except: print( "the error below happend when calling connection_established of a widget. This may happen if the widget was recently destroyed." ) print_exc() self.call_listeners() self.check_for_new_version() def call_listeners(self): if (hasattr(self, "connection") and self.connection and self.connection.connected): try: self.parameters.call_listeners() except: print(colors.red | "call_listeners() failed") print_exc() QtCore.QTimer.singleShot(50, self.call_listeners) def get_widget(self, name, window=None): """Queries a widget by name.""" window = window or self.main_window return window.findChild(QtCore.QObject, name) def close(self): self.app.quit() def shutdown(self): self.control.shutdown() self.close() def open_psd_window(self): # first hiding it, then showing it brings it to foregroud if it is in # background self.psd_window.hide() self.psd_window.show() def open_device_manager(self): self.main_window.hide() self.device_manager.show() self.connection.disconnect() del self.connection def close_all_secondary_windows(self): self.psd_window.hide() def check_for_new_version(self): self.version_checker = VersionCheckerThread() self.version_checker.check_done.connect(self.new_version_available) self.version_checker.start() def new_version_available(self, new_version_available): if new_version_available: print("new version available") self.main_window.show_new_version_available() else: print("no new version available") QtCore.QTimer.singleShot(1000 * 60 * 60, self.check_for_new_version)
class larlite_manager_base(manager, QtCore.QObject): fileChanged = QtCore.pyqtSignal() eventChanged = QtCore.pyqtSignal() clusterParamsChanged = QtCore.pyqtSignal(bool) """docstring for lariat_manager""" def __init__(self, geom, file=None): super(larlite_manager_base, self).__init__(geom, file) manager.__init__(self, geom, file) QtCore.QObject.__init__(self) # For the larlite manager, need both the ana_processor and # the storage manager self._process = fmwk.ana_processor() self._mgr = fmwk.storage_manager() self._keyTable = dict() self._drawnClasses = dict() if file != None: self.setInputFiles(file) self._n_entries = 0 # Toggle whether or not to draw wires: self._drawWires = False self._drawParams = False self._drawTruth = False self._wireDrawer = None self._truthDrawer = None # Lariat has special meanings to event/spill/run self._spill = 0 def pingFile(self, file): """ this function opens the file and determines what is available to draw """ # This function opens the file to see # what data products are available # Open the file f = TFile(file) # Use the larlite_id_tree to find out how many entries are in the file: self._n_entries += f.larlite_id_tree.GetEntries() # prepare a dictionary of data products lookUpTable = dict() # Loop over the keys (list of trees) for key in f.GetListOfKeys(): # keys are dataproduct_producer_tree # Make sure the ttrees being looked at are larlite trees if "_" not in key.GetName(): # For now, just skip anything that doesn't have "_" continue name = key.GetName().replace("_tree", "") # Find the last remaining underscore: product = name.split("_")[0] producerName = "_".join(name.split("_")[1:]) thisKeyList = key.GetName().split('_') # gets three items in thisKeyList, which is a list # [dataProduct, producer, 'tree'] (don't care about 'tree') # check if the data product is in the dict: if product in lookUpTable: # extend the list: lookUpTable[product] += (producerName, ) else: lookUpTable.update({product: (producerName, )}) self._keyTable.update(lookUpTable) def setInputFile(self, file): f = [ file, ] self.setInputFiles(f) def setInputFiles(self, files): # reset the storage manager and process self._mgr.reset() self._process.reset() if files == None: return for file in files: # First, check that the file exists: try: if not os.path.exists(file): print "ERROR: requested file does not exist." continue except Exception, e: print e return # Next, verify it is a root file: if not file.endswith(".root"): print "ERROR: must supply a root file." continue # Finally, ping the file to see what is available to draw self.pingFile(file) if len(self._keyTable) > 0: self._hasFile = True # add this file to the storage manager here self._mgr.add_in_filename(file) self._mgr.set_io_mode(fmwk.storage_manager.kREAD) # setup the processor in the same way self._process.add_input_file(file) self._process.set_io_mode(fmwk.storage_manager.kREAD) # Open the manager self._mgr.open() self._lastProcessed = -1 self.goToEvent(0) self.fileChanged.emit()
class TaskThread(QtCore.QThread): taskFinished = QtCore.pyqtSignal() def run(self): self.taskFinished.emit()
class KeyPressWindow(pg.GraphicsLayoutWidget): sigKeyPress = QtCore.pyqtSignal(object) def keyPressEvent(self, ev): self.scene().keyPressEvent(ev) self.sigKeyPress.emit(ev)