def loadLibrary(reloadLibs=False, libPath=None): """Import all Node subclasses found within files in the library module.""" global NODE_LIST, NODE_TREE if libPath is None: libPath = os.path.dirname(os.path.abspath(__file__)) if reloadLibs: reload.reloadAll(libPath) for f in os.listdir(libPath): pathName, ext = os.path.splitext(f) if ext != '.py' or '__init__' in pathName: continue try: #print "importing from", f mod = __import__(pathName, globals(), locals()) except: printExc("Error loading flowchart library %s:" % pathName) continue nodes = [] for n in dir(mod): o = getattr(mod, n) if isNodeClass(o): #print " ", str(o) registerNodeType(o, [(pathName, )], override=reloadLibs)
def sendClickEvent(self, ev): ## if we are in mid-drag, click events may only go to the dragged item. if self.dragItem is not None and hasattr(self.dragItem, 'mouseClickEvent'): ev.currentItem = self.dragItem self.dragItem.mouseClickEvent(ev) ## otherwise, search near the cursor else: if self.lastHoverEvent is not None: acceptedItem = self.lastHoverEvent.clickItems().get(ev.button(), None) else: acceptedItem = None if acceptedItem is not None: ev.currentItem = acceptedItem try: acceptedItem.mouseClickEvent(ev) except: debug.printExc("Error sending click event:") else: for item in self.itemsNearEvent(ev): if hasattr(item, 'mouseClickEvent'): ev.currentItem = item try: item.mouseClickEvent(ev) except: debug.printExc("Error sending click event:") if ev.isAccepted(): break if not ev.isAccepted() and ev.button() is QtCore.Qt.RightButton: #print "GraphicsScene emitting sigSceneContextMenu" self.sigMouseClicked.emit(ev) ev.accept() return ev.isAccepted()
def loadLibrary(reloadLibs=False, libPath=None): """Import all Node subclasses found within files in the library module.""" global NODE_LIST, NODE_TREE if libPath is None: libPath = os.path.dirname(os.path.abspath(__file__)) if reloadLibs: reload.reloadAll(libPath) for f in os.listdir(libPath): pathName, ext = os.path.splitext(f) if ext != '.py' or '__init__' in pathName: continue try: #print "importing from", f mod = __import__(pathName, globals(), locals()) except: printExc("Error loading flowchart library %s:" % pathName) continue nodes = [] for n in dir(mod): o = getattr(mod, n) if isNodeClass(o): #print " ", str(o) registerNodeType(o, [(pathName,)], override=reloadLibs)
def restoreTransform(self, tr): try: #self.userTranslate = pg.Point(tr['trans']) #self.userRotate = tr['rot'] self.userTransform = pg.Transform(tr) self.updateTransform() self.selectBoxFromUser() ## move select box to match self.sigTransformChanged.emit(self) self.sigTransformChangeFinished.emit(self) except: #self.userTranslate = pg.Point([0,0]) #self.userRotate = 0 self.userTransform = pg.Transform() debug.printExc("Failed to load transform:")
def restoreTransform(self, tr): try: #self.userTranslate = pg.Point(tr['trans']) #self.userRotate = tr['rot'] self.userTransform = pg.SRTTransform(tr) self.updateTransform() self.selectBoxFromUser() ## move select box to match self.sigTransformChanged.emit(self) self.sigTransformChangeFinished.emit(self) except: #self.userTranslate = pg.Point([0,0]) #self.userRotate = 0 self.userTransform = pg.SRTTransform() debug.printExc("Failed to load transform:")
def __call__(self, y, *args, **kwargs): if self.func is None: self.func = self.set_func() x = np.arange(0, y.size, 1) try: best_vals, covar = optimize.curve_fit(self.func, x, y, p0=self.p0) return self.func(x, *best_vals) except RuntimeError: printExc() return np.array([])
def restoreTerminals(self, state): for name in list(self.terminals.keys()): if name not in state: self.removeTerminal(name) for name, opts in state.items(): if name in self.terminals: term = self[name] term.setOpts(**opts) continue try: # opts = strDict(opts) self.addTerminal(name, **opts) except Exception: printExc("Error restoring terminal %s (%s):" % (str(name), str(opts)))
def sendHoverEvents(self, ev, exitOnly=False): ## if exitOnly, then just inform all previously hovered items that the mouse has left. if exitOnly: acceptable = False items = [] event = HoverEvent(None, acceptable) else: acceptable = int( ev.buttons() ) == 0 ## if we are in mid-drag, do not allow items to accept the hover event. event = HoverEvent(ev, acceptable) items = self.itemsNearEvent(event, hoverable=True) self.sigMouseHover.emit(items) prevItems = list(self.hoverItems.keys()) for item in items: if hasattr(item, 'hoverEvent'): event.currentItem = item if item not in self.hoverItems: self.hoverItems[item] = None event.enter = True else: prevItems.remove(item) event.enter = False try: item.hoverEvent(event) except: debug.printExc("Error sending hover event:") event.enter = False event.exit = True for item in prevItems: event.currentItem = item try: item.hoverEvent(event) except: debug.printExc("Error sending hover exit event:") finally: del self.hoverItems[item] if hasattr(ev, 'buttons') and int(ev.buttons()) == 0: self.lastHoverEvent = event ## save this so we can ask about accepted events later.
def applyClicked(self): loaded = False for mod, nodes in self.modules.items(): for node in nodes: try: self.library.addNodeType(node, [(mod.__name__, )]) loaded = True except Exception as e: printExc(e) if not loaded: return self.ctrl.ui.clear_model(self.ctrl.ui.node_tree) self.ctrl.ui.create_model(self.ctrl.ui.node_tree, self.library.getLabelTree(rebuild=True)) self.sigApplyClicked.emit()
def sendHoverEvents(self, ev, exitOnly=False): ## if exitOnly, then just inform all previously hovered items that the mouse has left. if exitOnly: acceptable=False items = [] event = HoverEvent(None, acceptable) else: acceptable = int(ev.buttons()) == 0 ## if we are in mid-drag, do not allow items to accept the hover event. event = HoverEvent(ev, acceptable) items = self.itemsNearEvent(event, hoverable=True) self.sigMouseHover.emit(items) prevItems = list(self.hoverItems.keys()) for item in items: if hasattr(item, 'hoverEvent'): event.currentItem = item if item not in self.hoverItems: self.hoverItems[item] = None event.enter = True else: prevItems.remove(item) event.enter = False try: item.hoverEvent(event) except: debug.printExc("Error sending hover event:") event.enter = False event.exit = True for item in prevItems: event.currentItem = item try: item.hoverEvent(event) except: debug.printExc("Error sending hover exit event:") finally: del self.hoverItems[item] if hasattr(ev, 'buttons') and int(ev.buttons()) == 0: self.lastHoverEvent = event ## save this so we can ask about accepted events later.
def drawItemTree(self, item=None, useItemNames=False): if item is None: items = [x for x in self.items if x.parentItem() is None] else: items = item.childItems() items.append(item) items.sort(key=lambda a: a.depthValue()) for i in items: if not i.visible(): continue if i is item: try: glPushAttrib(GL_ALL_ATTRIB_BITS) if useItemNames: glLoadName(i._id) self._itemNames[i._id] = i i.paint() except: from pyqtgraph import debug debug.printExc() msg = "Error while drawing item %s." % str(item) ver = glGetString(GL_VERSION) if ver is not None: ver = ver.split()[0] if int(ver.split(b'.')[0]) < 2: print(msg + " The original exception is printed above; however, pyqtgraph requires OpenGL version 2.0 or greater for many of its 3D features and your OpenGL version is %s. Installing updated display drivers may resolve this issue." % ver) else: print(msg) finally: glPopAttrib() else: glMatrixMode(GL_MODELVIEW) glPushMatrix() try: tr = i.transform() a = np.array(tr.copyDataTo()).reshape((4,4)) glMultMatrixf(a.transpose()) self.drawItemTree(i, useItemNames=useItemNames) finally: glMatrixMode(GL_MODELVIEW) glPopMatrix()
def sendClickEvent(self, ev): ## if we are in mid-drag, click events may only go to the dragged item. if self.dragItem is not None and hasattr(self.dragItem, 'mouseClickEvent'): ev.currentItem = self.dragItem self.dragItem.mouseClickEvent(ev) ## otherwise, search near the cursor else: if self.lastHoverEvent is not None: acceptedItem = self.lastHoverEvent.clickItems().get( ev.button(), None) else: acceptedItem = None if acceptedItem is not None: ev.currentItem = acceptedItem try: acceptedItem.mouseClickEvent(ev) except: debug.printExc("Error sending click event:") else: for item in self.itemsNearEvent(ev): if not item.isVisible() or not item.isEnabled(): continue if hasattr(item, 'mouseClickEvent'): ev.currentItem = item try: item.mouseClickEvent(ev) except: debug.printExc("Error sending click event:") if ev.isAccepted(): if int(item.flags() & item.ItemIsFocusable) > 0: item.setFocus(QtCore.Qt.MouseFocusReason) break #if not ev.isAccepted() and ev.button() is QtCore.Qt.RightButton: #print "GraphicsScene emitting sigSceneContextMenu" #self.sigMouseClicked.emit(ev) #ev.accept() self.sigMouseClicked.emit(ev) return ev.isAccepted()
def restoreState(self, state, clear=False): self.blockSignals(True) try: if clear: self.clear() Node.restoreState(self, state) nodes = state['nodes'] #nodes.sort(lambda a, b: cmp(a['pos'][0], b['pos'][0])) nodes.sort(key=lambda a: a['pos'][0]) for n in nodes: if n['name'] in self._nodes: #self._nodes[n['name']].graphicsItem().moveBy(*n['pos']) self._nodes[n['name']].restoreState(n['state']) continue try: node = self.createNode(n['class'], name=n['name']) node.restoreState(n['state']) except: printExc("Error creating node %s: (continuing anyway)" % n['name']) #node.graphicsItem().moveBy(*n['pos']) self.inputNode.restoreState(state.get('inputNode', {})) self.outputNode.restoreState(state.get('outputNode', {})) #self.restoreTerminals(state['terminals']) for n1, t1, n2, t2 in state['connects']: try: self.connectTerminals(self._nodes[n1][t1], self._nodes[n2][t2]) except: print(self._nodes[n1].terminals) print(self._nodes[n2].terminals) printExc("Error connecting terminals %s.%s - %s.%s:" % (n1, t1, n2, t2)) finally: self.blockSignals(False) self.sigChartLoaded.emit() self.outputChanged() self.sigStateChanged.emit()
def restoreState(self, state, clear=False): self.blockSignals(True) try: if clear: self.clear() Node.restoreState(self, state) nodes = state['nodes'] nodes.sort(lambda a, b: cmp(a['pos'][0], b['pos'][0])) for n in nodes: if n['name'] in self._nodes: #self._nodes[n['name']].graphicsItem().moveBy(*n['pos']) self._nodes[n['name']].restoreState(n['state']) continue try: node = self.createNode(n['class'], name=n['name']) node.restoreState(n['state']) except: printExc("Error creating node %s: (continuing anyway)" % n['name']) #node.graphicsItem().moveBy(*n['pos']) self.inputNode.restoreState(state.get('inputNode', {})) self.outputNode.restoreState(state.get('outputNode', {})) #self.restoreTerminals(state['terminals']) for n1, t1, n2, t2 in state['connects']: try: self.connectTerminals(self._nodes[n1][t1], self._nodes[n2][t2]) except: print(self._nodes[n1].terminals) print(self._nodes[n2].terminals) printExc("Error connecting terminals %s.%s - %s.%s:" % (n1, t1, n2, t2)) finally: self.blockSignals(False) self.sigChartLoaded.emit() self.outputChanged() self.sigStateChanged.emit()
def sendClickEvent(self, ev): ## if we are in mid-drag, click events may only go to the dragged item. if self.dragItem is not None and hasattr(self.dragItem, "mouseClickEvent"): ev.currentItem = self.dragItem self.dragItem.mouseClickEvent(ev) ## otherwise, search near the cursor else: if self.lastHoverEvent is not None: acceptedItem = self.lastHoverEvent.clickItems().get(ev.button(), None) else: acceptedItem = None if acceptedItem is not None: ev.currentItem = acceptedItem try: acceptedItem.mouseClickEvent(ev) except: debug.printExc("Error sending click event:") else: for item in self.itemsNearEvent(ev): if not item.isVisible() or not item.isEnabled(): continue if hasattr(item, "mouseClickEvent"): ev.currentItem = item try: item.mouseClickEvent(ev) except: debug.printExc("Error sending click event:") if ev.isAccepted(): if int(item.flags() & item.ItemIsFocusable) > 0: item.setFocus(QtCore.Qt.MouseFocusReason) break # if not ev.isAccepted() and ev.button() is QtCore.Qt.RightButton: # print "GraphicsScene emitting sigSceneContextMenu" # self.sigMouseClicked.emit(ev) # ev.accept() self.sigMouseClicked.emit(ev) return ev.isAccepted()
def sendDragEvent(self, ev, init=False, final=False): ## Send a MouseDragEvent to the current dragItem or to ## items near the beginning of the drag event = MouseDragEvent(ev, self.clickEvents[0], self.lastDrag, start=init, finish=final) #print "dragEvent: init=", init, 'final=', final, 'self.dragItem=', self.dragItem if init and self.dragItem is None: if self.lastHoverEvent is not None: acceptedItem = self.lastHoverEvent.dragItems().get( event.button(), None) else: acceptedItem = None if acceptedItem is not None: #print "Drag -> pre-selected item:", acceptedItem self.dragItem = acceptedItem event.currentItem = self.dragItem try: self.dragItem.mouseDragEvent(event) except: debug.printExc("Error sending drag event:") else: #print "drag -> new item" for item in self.itemsNearEvent(event): #print "check item:", item if not item.isVisible() or not item.isEnabled(): continue if hasattr(item, 'mouseDragEvent'): event.currentItem = item try: item.mouseDragEvent(event) except: debug.printExc("Error sending drag event:") if event.isAccepted(): #print " --> accepted" self.dragItem = item if int(item.flags() & item.ItemIsFocusable) > 0: item.setFocus(QtCore.Qt.MouseFocusReason) break elif self.dragItem is not None: event.currentItem = self.dragItem try: self.dragItem.mouseDragEvent(event) except: debug.printExc("Error sending hover exit event:") self.lastDrag = event return event.isAccepted()
def sendDragEvent(self, ev, init=False, final=False): ## Send a MouseDragEvent to the current dragItem or to ## items near the beginning of the drag event = MouseDragEvent(ev, self.clickEvents[0], self.lastDrag, start=init, finish=final) #print "dragEvent: init=", init, 'final=', final, 'self.dragItem=', self.dragItem if init and self.dragItem is None: if self.lastHoverEvent is not None: acceptedItem = self.lastHoverEvent.dragItems().get(event.button(), None) else: acceptedItem = None if acceptedItem is not None: #print "Drag -> pre-selected item:", acceptedItem self.dragItem = acceptedItem event.currentItem = self.dragItem try: self.dragItem.mouseDragEvent(event) except: debug.printExc("Error sending drag event:") else: #print "drag -> new item" for item in self.itemsNearEvent(event): #print "check item:", item if not item.isVisible() or not item.isEnabled(): continue if hasattr(item, 'mouseDragEvent'): event.currentItem = item try: item.mouseDragEvent(event) except: debug.printExc("Error sending drag event:") if event.isAccepted(): #print " --> accepted" self.dragItem = item if int(item.flags() & item.ItemIsFocusable) > 0: item.setFocus(QtCore.Qt.MouseFocusReason) break elif self.dragItem is not None: event.currentItem = self.dragItem try: self.dragItem.mouseDragEvent(event) except: debug.printExc("Error sending hover exit event:") self.lastDrag = event return event.isAccepted()
def restoreState(self, state): """ Restore the state of this flowchart from a previous call to `saveState()`. """ self.blockSignals(True) try: if 'source_configuration' in state: src_cfg = state['source_configuration'] self.widget().sourceConfigure.restoreState(src_cfg) if src_cfg['files']: self.widget().sourceConfigure.applyClicked() if 'library' in state: lib_cfg = state['library'] self.widget().libraryEditor.restoreState(lib_cfg) self.widget().libraryEditor.applyClicked() if 'viewbox' in state: self.viewBox.restoreState(state['viewbox']) nodes = state['nodes'] nodes.sort(key=lambda a: a['state']['pos'][0]) for n in nodes: if n['class'] == 'SourceNode': try: ttype = eval(n['state']['terminals']['Out']['ttype']) n['state']['terminals']['Out']['ttype'] = ttype node = SourceNode(name=n['name'], terminals=n['state']['terminals']) self.addNode(node=node) except Exception: printExc( "Error creating node %s: (continuing anyway)" % n['name']) else: try: node = self.createNode(n['class'], name=n['name']) except Exception: printExc( "Error creating node %s: (continuing anyway)" % n['name']) node.restoreState(n['state']) if hasattr(node, "display"): node.display(topics=None, terms=None, addr=None, win=None) if hasattr(node.widget, 'restoreState') and 'widget' in n['state']: node.widget.restoreState(n['state']['widget']) connections = {} with tempfile.NamedTemporaryFile(mode='w') as type_file: type_file.write("from mypy_extensions import TypedDict\n") type_file.write("from typing import *\n") type_file.write("import numbers\n") type_file.write("import amitypes\n") type_file.write("T = TypeVar('T')\n\n") nodes = self.nodes(data='node') for n1, t1, n2, t2 in state['connects']: try: node1 = nodes[n1] term1 = node1[t1] node2 = nodes[n2] term2 = node2[t2] self.connectTerminals(term1, term2, type_file) if term1.isInput() or term1.isCondition: in_name = node1.name() + '_' + term1.name() in_name = in_name.replace('.', '_') out_name = node2.name() + '_' + term2.name() out_name = out_name.replace('.', '_') else: in_name = node2.name() + '_' + term2.name() in_name = in_name.replace('.', '_') out_name = node1.name() + '_' + term1.name() out_name = out_name.replace('.', '_') connections[(in_name, out_name)] = (term1, term2) except Exception: print(node1.terminals) print(node2.terminals) printExc("Error connecting terminals %s.%s - %s.%s:" % (n1, t1, n2, t2)) type_file.flush() status = subprocess.run( ["mypy", "--follow-imports", "silent", type_file.name], capture_output=True, text=True) if status.returncode != 0: lines = status.stdout.split('\n')[:-1] for line in lines: m = re.search(r"\"+(\w+)\"+", line) if m: m = m.group().replace('"', '') for i in connections: if i[0] == m: term1, term2 = connections[i] term1.disconnectFrom(term2) break elif i[1] == m: term1, term2 = connections[i] term1.disconnectFrom(term2) break finally: self.blockSignals(False) for name, node in self.nodes(data='node'): self.sigNodeChanged.emit(node)
async def applyClicked(self, build_views=True): graph_nodes = [] disconnectedNodes = [] displays = set() msg = QtWidgets.QMessageBox(parent=self) msg.setText("Failed to submit graph! See status.") if self.chart.deleted_nodes: await self.graphCommHandler.remove(self.chart.deleted_nodes) self.chart.deleted_nodes = [] # detect if the manager has no graph (e.g. from a purge on failure) if await self.graphCommHandler.graphVersion == 0: # mark all the nodes as changed to force a resubmit of the whole graph for name, gnode in self.chart._graph.nodes().items(): gnode = gnode['node'] gnode.changed = True # reset reference counting on views await self.features.reset() outputs = [n for n, d in self.chart._graph.out_degree() if d == 0] changed_nodes = set() failed_nodes = set() seen = set() for name, gnode in self.chart._graph.nodes().items(): gnode = gnode['node'] if not gnode.enabled(): continue if not gnode.hasInput(): disconnectedNodes.append(gnode) continue elif gnode.exception: gnode.clearException() gnode.recolor() if gnode.changed and gnode not in changed_nodes: changed_nodes.add(gnode) if not hasattr(gnode, 'to_operation'): if gnode.isSource() and gnode.viewable() and gnode.viewed: displays.add(gnode) elif gnode.exportable(): displays.add(gnode) continue for output in outputs: paths = list( nx.algorithms.all_simple_paths(self.chart._graph, name, output)) if not paths: paths = [[output]] for path in paths: for gnode in path: gnode = self.chart._graph.nodes[gnode] node = gnode['node'] if hasattr(node, 'to_operation') and node not in seen: try: nodes = node.to_operation( inputs=node.input_vars(), conditions=node.condition_vars()) except Exception: self.chartWidget.updateStatus( f"{node.name()} error!", color='red') printExc( f"{node.name()} raised exception! See console for stacktrace." ) node.setException(True) failed_nodes.add(node) continue seen.add(node) if type(nodes) is list: graph_nodes.extend(nodes) else: graph_nodes.append(nodes) if (node.viewable() or node.buffered()) and node.viewed: displays.add(node) if disconnectedNodes: for node in disconnectedNodes: self.chartWidget.updateStatus(f"{node.name()} disconnected!", color='red') node.setException(True) msg.exec() return if failed_nodes: self.chartWidget.updateStatus("failed to submit graph", color='red') msg.exec() return if graph_nodes: await self.graphCommHandler.add(graph_nodes) node_names = ', '.join( set(map(lambda node: node.parent, graph_nodes))) self.chartWidget.updateStatus(f"Submitted {node_names}") node_names = ', '.join(set(map(lambda node: node.name(), displays))) if displays and build_views: self.chartWidget.updateStatus(f"Redisplaying {node_names}") await self.chartWidget.build_views(displays, export=True, redisplay=True) for node in changed_nodes: node.changed = False self.metadata = await self.graphCommHandler.metadata self.ui.setPendingClear() version = str(await self.graphCommHandler.graphVersion) state = self.chart.saveState() state = json.dumps(state, indent=2, separators=(',', ': '), sort_keys=True, cls=amitypes.TypeEncoder) self.graph_info.labels(self.chart.hutch, self.graph_name).info({ 'graph': state, 'version': version })