def make_sequential_flowchart(clsList, inputData=None): nNodes = len(clsList) nodelib = fclib.NodeLibrary() for cls in clsList: cls.debug = True nodelib.addNodeType(cls, [('Basic')]) fc = Flowchart(terminals={ 'dataIn': { 'io': 'in' }, 'dataOut': { 'io': 'out' } }) fc.library = nodelib nodes = [] for cls in clsList: nodes.append(fc.createNode(cls.nodeName)) fc.connectTerminals(fc['dataIn'], nodes[0]['dataIn']) for i in range(nNodes - 1): fc.connectTerminals(nodes[i]['dataOut'], nodes[i + 1]['dataIn']) fc.connectTerminals(nodes[nNodes - 1]['dataOut'], fc['dataOut']) if inputData is not None: fc.setInput(dataIn=inputData) return nodes, fc
class AppWindow(QtGui.QMainWindow, hackYourOwn.Ui_MainWindow,utilitiesClass): def __init__(self, parent=None,**kwargs): super(AppWindow, self).__init__(parent) self.setupUi(self) self.I=kwargs.get('I',None) self.setWindowTitle('pyqtgraph example: FlowchartCustomNode') ## Create an empty flowchart with a single input and output self.fc = Flowchart(terminals={ 'dataIn': {'io': 'in'}, }) self.w = self.fc.widget() self.WidgetLayout.addWidget(self.fc.widget()) self.plot1 = self.add2DPlot(self.ExperimentLayout) self.plot2 = self.add2DPlot(self.ExperimentLayout) self.curve1 = self.addCurve(self.plot1) self.curve2 = self.addCurve(self.plot2) self.curve1.setData([1,2,3],[5,6,7]) self.library = fclib.LIBRARY.copy() # start with the default node set self.library.addNodeType(PlotViewNode, [('Display',)]) self.library.addNodeType(CaptureNode, [('Acquire',)]) self.fc.setLibrary(self.library) ## Now we will programmatically add nodes to define the function of the flowchart. ## Normally, the user will do this manually or by loading a pre-generated ## flowchart file. self.cap = self.fc.createNode('Capture', pos=(0, 0)) self.cap.setI(self.I) self.v1Node = self.fc.createNode('PlotView', pos=(0, -150)) self.v1Node.setView(self.curve1) self.v2Node = self.fc.createNode('PlotView', pos=(150, -150)) self.v2Node.setView(self.curve2) self.fc.connectTerminals(self.fc['dataIn'], self.cap['dataIn']) self.fc.connectTerminals(self.cap['dataOut'], self.v1Node['data']) #self.fc.connectTerminals(self.fc['dataIn'], self.v2Node['data']) self.fc.setInput(dataIn=True) def run(self): self.fc.setInput(dataIn=True) def __del__(self): #self.looptimer.stop() print ('bye') def closeEvent(self, event): self.finished=True
class AppWindow(QtGui.QMainWindow, hackYourOwn.Ui_MainWindow, utilitiesClass): def __init__(self, parent=None, **kwargs): super(AppWindow, self).__init__(parent) self.setupUi(self) self.I = kwargs.get('I', None) self.setWindowTitle('pyqtgraph example: FlowchartCustomNode') ## Create an empty flowchart with a single input and output self.fc = Flowchart(terminals={ 'dataIn': { 'io': 'in' }, }) self.w = self.fc.widget() self.WidgetLayout.addWidget(self.fc.widget()) self.plot1 = self.add2DPlot(self.ExperimentLayout) self.plot2 = self.add2DPlot(self.ExperimentLayout) self.curve1 = self.addCurve(self.plot1) self.curve2 = self.addCurve(self.plot2) self.curve1.setData([1, 2, 3], [5, 6, 7]) self.library = fclib.LIBRARY.copy() # start with the default node set self.library.addNodeType(PlotViewNode, [('Display', )]) self.library.addNodeType(CaptureNode, [('Acquire', )]) self.fc.setLibrary(self.library) ## Now we will programmatically add nodes to define the function of the flowchart. ## Normally, the user will do this manually or by loading a pre-generated ## flowchart file. self.cap = self.fc.createNode('Capture', pos=(0, 0)) self.cap.setI(self.I) self.v1Node = self.fc.createNode('PlotView', pos=(0, -150)) self.v1Node.setView(self.curve1) self.v2Node = self.fc.createNode('PlotView', pos=(150, -150)) self.v2Node.setView(self.curve2) self.fc.connectTerminals(self.fc['dataIn'], self.cap['dataIn']) self.fc.connectTerminals(self.cap['dataOut'], self.v1Node['data']) #self.fc.connectTerminals(self.fc['dataIn'], self.v2Node['data']) self.fc.setInput(dataIn=True) def run(self): self.fc.setInput(dataIn=True) def __del__(self): #self.looptimer.stop() print('bye') def closeEvent(self, event): self.finished = True
def __init__(self, parent=None): super(Demo, self).__init__() self.setWindowTitle("Fourier Transformation") self.showFullScreen() self.layout = QtGui.QGridLayout() self.setLayout(self.layout) fc = Flowchart(terminals={ 'dataIn': { 'io': 'in' }, 'dataOut': { 'io': 'out' } }) self.layout.addWidget(fc.widget(), 0, 0, 2, 1) pw1 = pg.PlotWidget() pw2 = pg.PlotWidget() pw1.getPlotItem().setLabel('left', text='Amplitude') pw1.getPlotItem().setLabel('bottom', text='Time') pw2.getPlotItem().setLabel('left', text='Y(freq)') pw2.getPlotItem().setLabel('bottom', text='F(Hz)') self.layout.addWidget(pw1, 0, 1) self.layout.addWidget(pw2, 1, 1) sampling_rate = 150.0 sampling_interval = 1.0 / sampling_rate # Abtastfrequenz f = (1/t) time_vector = np.arange(0, 1, sampling_interval) signal_frequency = 10 data = np.sin(2 * np.pi * signal_frequency * time_vector) print data fc.setInput(dataIn=data) pw1Node = fc.createNode('PlotWidget', pos=(0, -150)) pw1Node.setPlot(pw1) pw2Node = fc.createNode('PlotWidget', pos=(150, -150)) pw2Node.setPlot(pw2) fNode = fc.createNode('AnalyzeNode', pos=(0, 0)) fc.connectTerminals(fc['dataIn'], fNode['dataIn']) fc.connectTerminals(fc['dataIn'], pw1Node['In']) fc.connectTerminals(fNode['dataOut'], pw2Node['In']) fc.connectTerminals(fNode['dataOut'], fc['dataOut'])
def __init__(self, parent=None): super(Demo, self).__init__() self.setWindowTitle("Fourier Transformation") self.showFullScreen() self.layout = QtGui.QGridLayout() self.setLayout(self.layout) fc = Flowchart(terminals={ 'dataIn': {'io': 'in'}, 'dataOut': {'io': 'out'} }) self.layout.addWidget(fc.widget(), 0, 0, 2, 1) pw1 = pg.PlotWidget() pw2 = pg.PlotWidget() pw1.getPlotItem().setLabel('left', text='Amplitude') pw1.getPlotItem().setLabel('bottom', text='Time') pw2.getPlotItem().setLabel('left', text='Y(freq)') pw2.getPlotItem().setLabel('bottom', text='F(Hz)') self.layout.addWidget(pw1, 0, 1) self.layout.addWidget(pw2, 1, 1) sampling_rate = 150.0 sampling_interval = 1.0 / sampling_rate; # Abtastfrequenz f = (1/t) time_vector = np.arange(0, 1, sampling_interval) signal_frequency = 10 data = np.sin(2 * np.pi * signal_frequency * time_vector) print data fc.setInput(dataIn=data) pw1Node = fc.createNode('PlotWidget', pos=(0, -150)) pw1Node.setPlot(pw1) pw2Node = fc.createNode('PlotWidget', pos=(150, -150)) pw2Node.setPlot(pw2) fNode = fc.createNode('AnalyzeNode', pos=(0, 0)) fc.connectTerminals(fc['dataIn'], fNode['dataIn']) fc.connectTerminals(fc['dataIn'], pw1Node['In']) fc.connectTerminals(fNode['dataOut'], pw2Node['In']) fc.connectTerminals(fNode['dataOut'], fc['dataOut'])
def init_filters(self): ## Create flowchart, define input/output terminals fc = Flowchart(terminals={ 'dataIn': { 'io': 'in' }, 'dataOut': { 'io': 'out' } }) ## Add flowchart control panel to the main window self.filter_d.layout.addWidget(fc.widget(), 0, 0, 2, 1) ## Add two plot widgets pw1 = pg.PlotWidget() pw2 = pg.PlotWidget() self.filter_d.layout.addWidget(pw1, 0, 1) self.filter_d.layout.addWidget(pw2, 1, 1) ## generate signal data to pass through the flowchart data = np.random.normal(size=1000) data[200:300] += 1 data += np.sin(np.linspace(0, 100, 1000)) data = metaarray.MetaArray(data, info=[{ 'name': 'Time', 'values': np.linspace(0, 1.0, len(data)) }, {}]) ## Feed data into the input terminal of the flowchart fc.setInput(dataIn=data) ## populate the flowchart with a basic set of processing nodes. ## (usually we let the user do this) plotList = {'Top Plot': pw1, 'Bottom Plot': pw2} pw1Node = fc.createNode('PlotWidget', pos=(0, -150)) pw1Node.setPlotList(plotList) pw1Node.setPlot(pw1) pw2Node = fc.createNode('PlotWidget', pos=(150, -150)) pw2Node.setPlot(pw2) pw2Node.setPlotList(plotList) fNode = fc.createNode('GaussianFilter', pos=(0, 0)) fNode.ctrls['sigma'].setValue(5) fc.connectTerminals(fc['dataIn'], fNode['In']) fc.connectTerminals(fc['dataIn'], pw1Node['In']) fc.connectTerminals(fNode['Out'], pw2Node['In']) fc.connectTerminals(fNode['Out'], fc['dataOut'])
def cli(dataset, flowchart): app = QtGui.QApplication.instance( ) # retrieves the ipython qt application if any if app is None: app = QtGui.QApplication([]) # create one if standalone execution fc = Flowchart(library=LIBRARY, terminals={'dataIn': {'io': 'in'}}) win = pyviViewerWindow(fc) fc.setInput(dataIn=dataset) if flowchart: fc_state = configfile.readConfigFile(flowchart) fc.restoreState(fc_state, clear=False) fc.viewBox.autoRange() import sys if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): app.exec_() app.deleteLater() sys.exit()
layout.addWidget(v1, 0, 1) layout.addWidget(v2, 1, 1) win.show() ## generate random input data data = np.random.normal(size=(100,100)) data = 25 * pg.gaussianFilter(data, (5,5)) data += np.random.normal(size=(100,100)) data[40:60, 40:60] += 15.0 data[30:50, 30:50] += 15.0 #data += np.sin(np.linspace(0, 100, 1000)) #data = metaarray.MetaArray(data, info=[{'name': 'Time', 'values': np.linspace(0, 1.0, len(data))}, {}]) ## Set the raw data as the input value to the flowchart fc.setInput(dataIn=data) ## At this point, we need some custom Node classes since those provided in the library ## are not sufficient. Each node will define a set of input/output terminals, a ## processing function, and optionally a control widget (to be displayed in the ## flowchart control panel) class ImageViewNode(Node): """Node that displays image data in an ImageView widget""" nodeName = 'ImageView' def __init__(self, name): self.view = None ## Initialize node with only a single input terminal Node.__init__(self, name, terminals={'data': {'io':'in'}})
fc.connectTerminals(fc.dataIn, n1.A) fc.connectTerminals(fc.dataIn, n1.B) fc.connectTerminals(fc.dataIn, n2.A) fc.connectTerminals(n1.Out, n4.A) fc.connectTerminals(n1.Out, n2.B) fc.connectTerminals(n2.Out, n3.In) fc.connectTerminals(n3.Out, n4.B) fc.connectTerminals(n4.Out, fc.dataOut) def process(**kargs): return fc.process(**kargs) print process(dataIn=7) fc.setInput(dataIn=3) s = fc.saveState() fc.clear() fc.restoreState(s) fc.setInput(dataIn=3) #f.NodeMod.TETRACYCLINE = False if sys.flags.interactive == 0: app.exec_()
## and color control. v1 = pg.ImageView() v2 = pg.ImageView() layout.addWidget(v1, 0, 1) layout.addWidget(v2, 1, 1) win.show() import cv2 def loadcv(pth,mode=-1,shape=None): im = cv2.imread(pth,mode) if shape: im = cv2.resize(im,shape) return im ## Set the raw data as the input value to the flowchart fc.setInput(dataIn=loadcv(r"/mnt/4E443F99443F82AF/Dropbox/PYTHON/RRtoolbox/tests/im1_3.png",mode=0,shape=(300,300))) ## At this point, we need some custom Node classes since those provided in the library ## are not sufficient. Each node will define a set of input/output terminals, a ## processing function, and optionally a control widget (to be displayed in the ## flowchart control panel) class ImageViewNode(Node): """Node that displays image data in an ImageView widget""" nodeName = 'ImageView' def __init__(self, name): self.view = None ## Initialize node with only a single input terminal Node.__init__(self, name, terminals={'data': {'io':'in'}},allowAddInput=False,allowAddOutput=False,allowRemove=False)
class Demo(QtGui.QWidget): def __init__(self, parent=None): super(Demo, self).__init__() self.setWindowTitle("Plotting the Wiimote") self.showFullScreen() self.layout = QtGui.QGridLayout() self.setLayout(self.layout) self.flowchart = Flowchart(terminals={ 'xDataIn': {'io': 'in'}, 'yDataIn': {'io': 'in'}, 'zDataIn': {'io': 'in'}, 'xDataOut': {'io': 'out'}, 'yDataOut': {'io': 'out'}, 'zDataOut': {'io': 'out'} }) self.layout.addWidget(self.flowchart.widget(), 0, 0, 3, 1) fclib.registerNodeType(WiimoteNode, [('Display',)]) self.wii_node = self.flowchart.createNode('Wiimote', pos=(0, 0)) self.axes = ['x', 'y', 'z'] # positions for all nodes; order: # raw_node xpos, raw_node ypos, filtered_node xpos, filtered_node ypos, # filter_node xpos, filter_node ypos self.positions = { 'x': [-450, -350, -300, -350, -375, -150], 'y': [-150, -350, 0, -350, -75, -150], 'z': [150, -350, 300, -350, 225, -150], } # create, style, config and connect the elements for every axis for axis in self.axes: index = self.axes.index(axis) plot_raw = pyqtgraph.PlotWidget() plot_filtered = pyqtgraph.PlotWidget() # add widget for this axis in next row self.layout.addWidget(plot_filtered, index, 2, 1, 2) self.configPlotItems(axis, plot_raw, plot_filtered) self.createNodes(axis, plot_raw, plot_filtered) self.connectNodes(axis) pyqtgraph.setConfigOptions(antialias=True) self.flowchart.setInput(xDataIn=0) self.flowchart.setInput(yDataIn=0) self.flowchart.setInput(zDataIn=0) # create raw, filter and filtered node def createNodes(self, axis, plot_raw, plot_filtered): # create filtered node self.plot_filtered_node = self.flowchart.createNode( 'PlotWidget', pos=( self.positions[axis][2], self.positions[axis][3])) self.plot_filtered_node.setPlot(plot_filtered) # create gaussian filter self.filter_node = self.flowchart.createNode( 'GaussianFilter', pos=( self.positions[axis][4], self.positions[axis][5])) self.filter_node.ctrls['sigma'].setValue(5) # connect nodes: flowchart -> wiinode -> plot_raw + filter_node # -> filtered_node def connectNodes(self, axis): self.flowchart.connectTerminals( self.flowchart[axis + 'DataIn'], self.wii_node[axis + 'DataIn']) self.flowchart.connectTerminals( self.wii_node[axis + 'DataOut'], self.filter_node['In']) self.flowchart.connectTerminals( self.filter_node['Out'], self.plot_filtered_node['In']) #self.flowchart.connectTerminals( # self.filter_node['Out'], self.flowchart[axis + 'DataOut']) # config plot items def configPlotItems(self, axis, plot_raw, plot_filtered): plot_raw.getPlotItem().setTitle("The " + axis + " Accelerometer") plot_raw.getPlotItem().setMenuEnabled(False) plot_raw.getPlotItem().setClipToView(False) plot_raw.getPlotItem().hideAxis('bottom') plot_raw.getPlotItem().showGrid(x=True, y=True, alpha=0.5) plot_filtered.getPlotItem().setTitle( "The " + axis + " Accelerometer - Filtered") plot_filtered.getPlotItem().setMenuEnabled(False) plot_filtered.getPlotItem().setClipToView(False) plot_filtered.getPlotItem().hideAxis('bottom') plot_filtered.getPlotItem().showGrid(x=True, y=True, alpha=0.5) def updateValues(self, x, y, z): self.flowchart.setInput(xDataIn=x) self.flowchart.setInput(yDataIn=y) self.flowchart.setInput(zDataIn=z) pyqtgraph.QtGui.QApplication.processEvents() def keyPressEvent(self, ev): if ev.key() == QtCore.Qt.Key_Escape: self.close()
class Demo(QtGui.QWidget): def __init__(self, parent=None): super(Demo, self).__init__() self.setWindowTitle("Plotting the Wiimote") self.showFullScreen() self.layout = QtGui.QGridLayout() self.setLayout(self.layout) self.flowchart = Flowchart( terminals={ 'xDataIn': { 'io': 'in' }, 'yDataIn': { 'io': 'in' }, 'zDataIn': { 'io': 'in' }, 'xDataOut': { 'io': 'out' }, 'yDataOut': { 'io': 'out' }, 'zDataOut': { 'io': 'out' } }) self.layout.addWidget(self.flowchart.widget(), 0, 0, 3, 1) fclib.registerNodeType(WiimoteNode, [('Display', )]) self.wii_node = self.flowchart.createNode('Wiimote', pos=(0, 0)) self.axes = ['x', 'y', 'z'] # positions for all nodes; order: # raw_node xpos, raw_node ypos, filtered_node xpos, filtered_node ypos, # filter_node xpos, filter_node ypos self.positions = { 'x': [-450, -350, -300, -350, -375, -150], 'y': [-150, -350, 0, -350, -75, -150], 'z': [150, -350, 300, -350, 225, -150], } # create, style, config and connect the elements for every axis for axis in self.axes: index = self.axes.index(axis) plot_raw = pyqtgraph.PlotWidget() plot_filtered = pyqtgraph.PlotWidget() # add widget for this axis in next row self.layout.addWidget(plot_filtered, index, 2, 1, 2) self.configPlotItems(axis, plot_raw, plot_filtered) self.createNodes(axis, plot_raw, plot_filtered) self.connectNodes(axis) pyqtgraph.setConfigOptions(antialias=True) self.flowchart.setInput(xDataIn=0) self.flowchart.setInput(yDataIn=0) self.flowchart.setInput(zDataIn=0) # create raw, filter and filtered node def createNodes(self, axis, plot_raw, plot_filtered): # create filtered node self.plot_filtered_node = self.flowchart.createNode( 'PlotWidget', pos=(self.positions[axis][2], self.positions[axis][3])) self.plot_filtered_node.setPlot(plot_filtered) # create gaussian filter self.filter_node = self.flowchart.createNode( 'GaussianFilter', pos=(self.positions[axis][4], self.positions[axis][5])) self.filter_node.ctrls['sigma'].setValue(5) # connect nodes: flowchart -> wiinode -> plot_raw + filter_node # -> filtered_node def connectNodes(self, axis): self.flowchart.connectTerminals(self.flowchart[axis + 'DataIn'], self.wii_node[axis + 'DataIn']) self.flowchart.connectTerminals(self.wii_node[axis + 'DataOut'], self.filter_node['In']) self.flowchart.connectTerminals(self.filter_node['Out'], self.plot_filtered_node['In']) #self.flowchart.connectTerminals( # self.filter_node['Out'], self.flowchart[axis + 'DataOut']) # config plot items def configPlotItems(self, axis, plot_raw, plot_filtered): plot_raw.getPlotItem().setTitle("The " + axis + " Accelerometer") plot_raw.getPlotItem().setMenuEnabled(False) plot_raw.getPlotItem().setClipToView(False) plot_raw.getPlotItem().hideAxis('bottom') plot_raw.getPlotItem().showGrid(x=True, y=True, alpha=0.5) plot_filtered.getPlotItem().setTitle("The " + axis + " Accelerometer - Filtered") plot_filtered.getPlotItem().setMenuEnabled(False) plot_filtered.getPlotItem().setClipToView(False) plot_filtered.getPlotItem().hideAxis('bottom') plot_filtered.getPlotItem().showGrid(x=True, y=True, alpha=0.5) def updateValues(self, x, y, z): self.flowchart.setInput(xDataIn=x) self.flowchart.setInput(yDataIn=y) self.flowchart.setInput(zDataIn=z) pyqtgraph.QtGui.QApplication.processEvents() def keyPressEvent(self, ev): if ev.key() == QtCore.Qt.Key_Escape: self.close()
pw2 = pg.PlotWidget() layout.addWidget(pw1, 0, 1) layout.addWidget(pw2, 1, 1) win.show() ## generate signal data to pass through the flowchart data = np.random.normal(size=1000) data[200:300] += 1 data += np.sin(np.linspace(0, 100, 1000)) data2 = -data data = metaarray.MetaArray(data, info=[{'name': 'Time', 'values': np.linspace(0, 1.0, len(data))}, {}]) data2 = metaarray.MetaArray(data2, info=[{'name': 'Time', 'values': np.linspace(0, 1.0, len(data2))}, {}]) ## Feed data into the input terminal of the flowchart fc.setInput(dataIn1=data) data = np.random.normal(size=1000) data[200:300] += 1 data += np.sin(np.linspace(0, 100, 1000)) data2 = -data data = metaarray.MetaArray(data, info=[{'name': 'Time', 'values': np.linspace(0, 1.0, len(data))}, {}]) data2 = metaarray.MetaArray(data2, info=[{'name': 'Time', 'values': np.linspace(0, 1.0, len(data2))}, {}]) fc.setInput(dataIn2=data) data = np.random.normal(size=1000) data[200:300] += 1 data += np.sin(np.linspace(0, 100, 1000)) data2 = -data data = metaarray.MetaArray(data, info=[{'name': 'Time', 'values': np.linspace(0, 1.0, len(data))}, {}]) data2 = metaarray.MetaArray(data2, info=[{'name': 'Time', 'values': np.linspace(0, 1.0, len(data2))}, {}])
class FlowchartCalibrateWindow: def __init__(self): """ Flowchart inside new window for system calibration """ # Graphics window self.win = QtGui.QMainWindow() self.win.setWindowTitle('System Calibration Flowchart') # Dock Area dockArea = DockArea() # Central widget self.win.setCentralWidget(dockArea) # Window Docks fcWidgetDock = Dock('Flowchart Widget', size=(1, 1), hideTitle=True) displayDock = Dock('Measurement and Calibration', size=(1, 1)) plotDocks = [Dock('Plot {}'.format(i), size=(1, 1)) for i in range(4)] dockArea.addDock(fcWidgetDock, 'left') dockArea.addDock(displayDock, 'right', fcWidgetDock) dockArea.addDock(plotDocks[0], 'top', displayDock) dockArea.addDock(plotDocks[1], 'right', plotDocks[0]) dockArea.addDock(plotDocks[2], 'top', displayDock) dockArea.addDock(plotDocks[3], 'right', plotDocks[2]) # Window size self.win.resize(800, 600) # Flowchart self.fc = Flowchart(terminals={ 'dipImgIn': { 'io': 'in' }, 'CalibConstOut': { 'io': 'out' }, }) # row, column, rowspan, colspan fcWidgetDock.addWidget(self.fc.widget()) # Plot widgets self.plt_widg = [FlowchartPlotWidget() for _ in range(len(plotDocks))] [ plotDocks[i].addWidget(self.plt_widg[i]) for i in range(len(plotDocks)) ] # Graphics layout for displays displayLayout = pg.GraphicsLayoutWidget(border='w') displayDock.addWidget(displayLayout) # Display widgets self.disp_widg = [] self.disp_widg.append( displayLayout.addLabel('', colspan=2, justify='left')) displayLayout.nextRow() self.disp_widg.append( displayLayout.addLabel('', colspan=2, justify='left')) # Flowchart library copy - custom nodes available to user self.fc_library = fclib.LIBRARY.copy() [ self.fc_library.addNodeType(nd, [('dipImage', 'Display')]) for nd in (FlowchartPlotNode, MeasurementDisplayNode, CalibDisplayNode, ORingMeasurementDisplayNode) ] # Filter nodes [ self.fc_library.addNodeType(nd, [('dipImage', 'Filters')]) for nd in (GaussianConvolutionNode, GradientNode, GradientMagnitudeNode, GradientDirectionNode, EdgeObjectsRemoveNode, KuwaharaNode, BilateralFilterNode) ] # Binary Filter nodes [ self.fc_library.addNodeType(nd, [('dipImage', 'Binary')]) for nd in (BinaryClosingNode, BinaryOpeningNode, BinaryErosionNode, BinaryDilationNode, BinaryAreaClosingNode, BinaryAreaOpeningNode, BinaryPropagationNode, FillHolesNode) ] # Segmentation nodes [ self.fc_library.addNodeType(nd, [('dipImage', 'Segmentation')]) for nd in (ThresholdNode, RangeThresholdNode, MinimaNode, MaximaNode, WatershedNode, SeededWatershedNode, CannyNode, SegmentORingNode) ] # Morphological nodes [ self.fc_library.addNodeType(nd, [('dipImage', 'Morphological')]) for nd in (DilationNode, ErosionNode, OpeningNode, ClosingNode) ] # Image nodes [ self.fc_library.addNodeType(nd, [('dipImage', 'Image')]) for nd in (ConvertNode, FillNode, LabelNode, SetPixelSizeNode) ] # Arithmetics nodes [ self.fc_library.addNodeType(nd, [('dipImage', 'Arithmetics')]) for nd in (InvertNode, ApplyMaskNode, CreateMaskNode, OperatorPlusNode) ] # Measurement nodes [ self.fc_library.addNodeType(nd, [('dipImage', 'Measurement')]) for nd in (MeasureNode, WorkingDistanceCorrectionNode, CombineMeasurementNode) ] self.fc.setLibrary(self.fc_library) # Plot nodes and Widget connection plt_nodes_x = (-20 + x * 120 for x in range(len(self.plt_widg))) plt_nodes = [ self.fc.createNode('FlowchartPlot', pos=(x, -60)) for x in plt_nodes_x ] [ nd.set_fcPlotWidget(widg) for nd, widg in zip(plt_nodes, self.plt_widg) ] # Connecting plot and display widgets with nodes self.fc.sigFileLoaded.connect(self.setFlowchartPlotWidgets) self.fc.sigFileLoaded.connect(self.setDisplayWidgets) self.fc.sigChartChanged.connect(self.setFlowchartPlotWidgets) self.fc.sigChartChanged.connect(self.setDisplayWidgets) def setFlowchartPlotWidgets(self): """ Connect Flowchart plot widgets with nodes after loading fc file """ nd_list = [] for name, node in self.fc.nodes().items(): if isinstance(node, FlowchartPlotNode): nd_list.append(node) [nd.set_fcPlotWidget(widg) for nd, widg in zip(nd_list, self.plt_widg)] def setDisplayWidgets(self): """ Connect Display widgets with nodes """ for name, node in self.fc.nodes().items(): if isinstance(node, MeasurementDisplayNode): node.setDisplayWidget(self.disp_widg[0]) if isinstance(node, CalibDisplayNode): node.setDisplayWidget(self.disp_widg[1]) def setInput(self, dip_img): """ Set Flowchart input """ self.fc.setInput(dipImgIn=dip_img) def fc_process(self, dip_img): """ Process data with display=False (speed increase) """ return self.fc.process(dipImgIn=dip_img)['CalibConstOut'] def output(self): """ Process data through flowchart with display=True and return output """ return self.fc.output()['CalibConstOut'] def show(self): self.win.show() def close(self): self.win.hide()
data[200:300] += 1 data += np.sin(np.linspace(0, 100, 1000)) data2 = -data data = metaarray.MetaArray(data, info=[{ 'name': 'Time', 'values': np.linspace(0, 1.0, len(data)) }, {}]) data2 = metaarray.MetaArray(data2, info=[{ 'name': 'Time', 'values': np.linspace(0, 1.0, len(data2)) }, {}]) ## Feed data into the input terminal of the flowchart fc.setInput(dataIn1=data) data = np.random.normal(size=1000) data[200:300] += 1 data += np.sin(np.linspace(0, 100, 1000)) data2 = -data data = metaarray.MetaArray(data, info=[{ 'name': 'Time', 'values': np.linspace(0, 1.0, len(data)) }, {}]) data2 = metaarray.MetaArray(data2, info=[{ 'name': 'Time', 'values': np.linspace(0, 1.0, len(data2)) }, {}])
def autoplot(makeUI: bool = True, log: bool = False, inputData: Union[None, DataDictBase] = None): """ Sets up a simple flowchart consisting of a data selector, an xy-axes selector, and creates a GUI together with an autoplot widget. returns the flowchart object and the dialog widget """ nodelib = fclib.NodeLibrary() nodelib.addNodeType(DataSelector, [('Basic')]) nodelib.addNodeType(DataGridder, [('Basic')]) nodelib.addNodeType(XYAxesSelector, [('Basic')]) nodelib.addNodeType(PlotNode, [('Plot')]) fc = Flowchart(terminals={ 'dataIn': { 'io': 'in' }, 'dataOut': { 'io': 'out' } }) fc.library = nodelib datasel = fc.createNode('DataSelector') grid = fc.createNode('Gridder') xysel = fc.createNode('XYAxesSelector') plot = fc.createNode('Plot') fc.connectTerminals(fc['dataIn'], datasel['dataIn']) fc.connectTerminals(datasel['dataOut'], grid['dataIn']) fc.connectTerminals(grid['dataOut'], xysel['dataIn']) fc.connectTerminals(xysel['dataOut'], fc['dataOut']) fc.connectTerminals(xysel['dataOut'], plot['dataIn']) # Setting up the GUI window area = DockArea() layout = QtGui.QVBoxLayout() layout.addWidget(area) win = QtGui.QDialog() win.setLayout(layout) win.setWindowTitle('Plottr | Autoplot') # data selector dataselDock = Dock('Data Selector', size=(250, 100)) dataselDock.addWidget(datasel.ui) area.addDock(dataselDock) # grid gridDock = Dock('Grid', size=(250, 80)) gridDock.addWidget(grid.ui) area.addDock(gridDock, 'bottom') # xy selector xyselDock = Dock('XY Axes Selector', size=(250, 100)) xyselDock.addWidget(xysel.ui) area.addDock(xyselDock, 'bottom') # log if log: logDock = Dock('Log', size=(250, 100)) logDock.addWidget(plottrlog.setupLogging(makeDialog=False)) area.addDock(logDock, 'bottom', xyselDock) # plot widget plotWidget = AutoPlot() plot.setPlotWidget(plotWidget) plotDock = Dock('Plot', size=(500, 300)) plotDock.addWidget(plotWidget) area.addDock(plotDock, 'right') win.show() if inputData is not None: fc.setInput(dataIn=inputData) return fc, win
class ModelWindow(QtWidgets.QMainWindow, Ui_ModelWindow): #模型界面对应的类 def __init__(self): super(ModelWindow, self).__init__() self.setupUi(self) self.global_id = 0 #每个层对应的唯一ID,用于基于DAG图的校验和代码生成 self.nodes = dict() #所有层的信息 self.id_name = dict() #ID-名字映射 self.name_id = dict() #名字-ID映射 self.net = nx.DiGraph() #图,节点为层的ID self.library = fclib.LIBRARY.copy() self.library.addNodeType(CovNode, [('CovNode', )]) self.library.addNodeType(PoolNode, [('PoolNode', )]) self.library.addNodeType(LinearNode, [('LinearNode', )]) self.library.addNodeType(ConcatNode, [('ConcatNode', )]) self.library.addNodeType(Concat1dNode, [('Concat1dNode', )]) self.library.addNodeType(SoftmaxNode, [('SoftmaxNode', )]) self.library.addNodeType(LogSoftmaxNode, [('LogSoftmaxNode', )]) self.library.addNodeType(BachNorm1dNode, [('BachNorm1dNode', )]) self.library.addNodeType(BachNorm2dNode, [('BachNorm2dNode', )]) self.library.addNodeType(AddNode, [('ResAddNode', )]) self.library.addNodeType(IdentityNode, [('IdentityNode', )]) self.type_name = { 2: 'Cov2d', 3: 'Pool2d', 4: 'Linear', 5: 'Softmax', 6: 'LogSoftmax', 7: 'BachNorm1d', 8: 'BachNorm2d', 9: 'Res_Add', 10: 'Concat2d', 11: 'Concat1d', 12: 'Identity' } self.fc = Flowchart() #模型可视化的流程图,对应FlowChart按钮 self.fc.setLibrary(self.library) #引入FCNodes.py中定义的Node self.outputs = list() #模型所有输出 w = self.fc.widget() self.fc_inputs = dict() #self.fc流程图的输入 main_widget = QWidget() main_layout = QGridLayout() main_widget.setLayout(main_layout) self.detail = QTreeWidget() self.detail.setColumnCount(2) self.detail.setHeaderLabels(["属性", "值"]) self.root = QTreeWidgetItem(self.detail) self.root.setText(0, "所有属性") main_layout.addWidget(self.fc.widget(), 0, 0, 1, 2) main_layout.addWidget(self.detail, 0, 2) self.setCentralWidget(main_widget) def add_layer(self): #用于弹出“层-新建”动作对应的层操作界面 self.addlayer_window = AddLayerWindow() self.addlayer_window.datasignal.connect(self.accept_layer) self.addlayer_window.show() def modifiey_layer(self): #用于弹出“层-更改”动作对应的层操作界面 self.addlayer_window = AddLayerWindow() self.addlayer_window.datasignal.connect(self.accept_layer) self.addlayer_window.layertype.addItem("恒等层(Identity)") self.addlayer_window.show() def clear(self): #对应“层-清除”,清除当前模型 self.fc.clear() self.id_name = dict() self.name_id = dict() self.nodes = dict() self.net = nx.DiGraph() self.fc.clear() self.fc_inputs = dict() self.global_id = 0 self.outputs = list() self.detail.clear() self.detail.setColumnCount(2) self.detail.setHeaderLabels(["属性", "值"]) self.root = QTreeWidgetItem(self.detail) self.root.setText(0, "所有属性") def to_train(self): #对应“功能-训练”动作,跳转到训练界面 self.train_window = TrainWindow() self.train_window.show() def to_test(self): #对应“功能-测试”动作,跳转到测试界面 self.test_window = TestWindow() self.test_window.show() def accept_layer(self, data): #接收层操作界面中信号的槽函数,接收层操作界面传来的数据并显示在该界面上 reset_flag = False if not data['type'] in [1, 12]: #对输入层和恒等层不检查输入 inputs = data['input'].split(";") data['input'] = list() for i in range(len(inputs)): #判断连接是否合法 try: name = inputs[i] layer = self.name_id[name] if data['type'] == 3 and (self.nodes[inputs[i]]['type'] not in [2, 8, 9, 10]): QMessageBox.warning(self, "错误", "输入:{}层类型不合法".format(inputs[i])) return 0 elif (data['type'] in [ 5, 6, 7, 11 ]) and (self.nodes[inputs[i]]['type'] not in [4, 7, 11]): QMessageBox.warning(self, "错误", "输入:{}层类型不合法".format(inputs[i])) return 0 elif (data['type'] in [2, 8, 10]) and (self.nodes[inputs[i]]['type'] not in [1, 2, 3, 8, 9, 10]): QMessageBox.warning(self, "错误", "输入:{}层类型不合法".format(inputs[i])) return 0 data['input'].append(layer) #将input中的层名替换为对应的ID except: QMessageBox.warning(self, "错误", "输入来自未生成的层:{}".format(inputs[i])) return 0 else: data['input'] = list() if data['type'] == 9: #残差连接层判断两个输入size是否相同 layer_id = data['input'][0] cur_size = self.nodes[self.id_name[layer_id]]['para']['out_size'] for layer_id in data['input']: layer = self.nodes[self.id_name[layer_id]] if layer['para']['out_size'] != cur_size: QMessageBox.warning(self, "错误", "输入尺寸不匹配") return 0 if data['name'] in self.name_id.keys(): #替换同名层的情形 id = self.name_id[data['name']] for input_id in data['input']: if input_id >= id: QMessageBox.warning(self, "错误", "输入来自后继层") return 0 if data['type'] == 12: data['para']['former_type'] = self.nodes[data['name']]['type'] if len(data['input']) == 0: data['input'].append(self.nodes[data['name']]['input'][0]) self.net.remove_node(id) self.net.add_node(id) for i in data['input']: self.net.add_edge(i, id) self.fc.removeNode(self.fc.nodes()[data['name']]) data['ID'] = id reset_flag = True else: #新建层 data['ID'] = self.global_id self.name_id[data['name']] = self.global_id self.id_name[self.global_id] = data['name'] self.net.add_node(self.global_id) for i in data['input']: self.net.add_edge(i, self.global_id) self.global_id += 1 self.nodes[data['name']] = data if data['type'] == 1: #输入层对应的流程图操作 self.fc.addInput(data['name']) self.fc_inputs[data['name']] = data['para']['out_size'] self.fc.setInput(**self.fc_inputs) elif data['type'] in [9, 10, 11]: #concat2D、concat1D和残差连接层的流程图操作 node = self.fc.createNode( self.type_name[data['type']], name=data['name'], pos=(data['input'][0] * 120, (data['ID'] - data['input'][0]) * 150 - 500)) node.setPara(data['para']) node.setView(self.root) for i in data['input']: in_name = self.id_name[i] in_size = self.nodes[in_name]['para']['out_size'] node.addInput(in_name) if self.nodes[in_name]['type'] == 1: self.fc.connectTerminals(self.fc[in_name], node[in_name]) else: self.fc.connectTerminals( self.fc.nodes()[in_name]['dataOut'], node[in_name]) if data['isoutput']: self.fc.addOutput(data['name']) self.fc.connectTerminals(node['dataOut'], self.fc[data['name']]) else: #其他层的流程图操作 node = self.fc.createNode( self.type_name[data['type']], name=data['name'], pos=(data['input'][0] * 120, (data['ID'] - data['input'][0]) * 150 - 500)) node.setPara(data['para']) node.setView(self.root) if self.nodes[self.id_name[data['input'][0]]]['type'] == 1: self.fc.connectTerminals( self.fc[self.id_name[data['input'][0]]], node['dataIn']) else: self.fc.connectTerminals( self.fc.nodes()[self.id_name[data['input'][0]]]['dataOut'], node['dataIn']) if data['isoutput']: self.fc.addOutput(data['name']) self.fc.connectTerminals(node['dataOut'], self.fc[data['name']]) if data['isoutput']: #添加流程图输出 self.outputs.append(data['ID']) if reset_flag: #对替换的层恢复后向的连接 for everynode in self.nodes.values(): if data['ID'] in everynode['input']: out_terminal = node.outputs()['dataOut'] if everynode['type'] in [9, 10, 11]: in_terminal = self.fc.nodes()[ everynode['name']].inputs()[data['name']] else: in_terminal = self.fc.nodes()[ everynode['name']].inputs()['dataIn'] self.fc.connectTerminals(in_terminal, out_terminal) self.net.add_edge(data['ID'], everynode['ID']) def export_file(self): #导出pytorch脚本 filename, _ = QFileDialog.getSaveFileName(self, '导出模型', 'C:\\', 'Python Files (*.py)') if filename is None or filename == "": return 0 filedir, filename_text = os.path.split(filename) filename_text = filename_text.split(".")[0] if self.check() == 0: QMessageBox.warning(self, "错误", "出现size<=0或模型没有输出") return 0 sort = list(nx.topological_sort(self.net)) content = list() for id in sort: content.append(self.nodes[self.id_name[id]]) with open(filedir + '/' + filename_text + ".json", 'w') as f1: json.dump(content, f1) with open(filename, 'w') as f: space = " " f.write( 'import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n' ) f.write("class Net(nn.Module):\n") f.write(space + "def __init__(self):\n") f.write(space * 2 + "super(Net, self).__init__()\n") #一下为__init__函数 for id in sort: name = self.id_name[id] layer = self.nodes[name] if layer['type'] == 2: f.write(space * 2 + "self." + layer['name'] + " = nn.Conv2d(") f.write(str(layer['para']['in_size'][0])+","+str(layer['para']['outchannels'])+","\ +str(layer['para']['kernel'])) for k, v in layer['para'].items(): if k in [ 'stride', 'padding', 'dilation', 'bias', 'padding_mode' ] and v is not None: f.write("," + k + "=" + str(v)) f.write(")\n") elif layer['type'] == 12: f.write(space * 2 + "self.{} = nn.Identity()\n".format(name)) elif layer['type'] == 3: if layer['para']['type'] == "max": f.write(space * 2 + "self." + layer['name'] + " = nn.MaxPool2d(") f.write(str(layer['para']['kernel'])) for k, v in layer['para'].items(): if k in ['stride', 'padding'] and v is not None: f.write("," + k + "=" + str(v)) elif layer['para']['type'] == "average": f.write(space * 2 + "self." + layer['name'] + " = nn.AvgPool2d(") f.write(str(layer['para']['kernel'])) for k, v in layer['para'].items(): if k in ['stride', 'padding'] and v is not None: f.write("," + k + "=" + str(v)) else: f.write(space * 2 + "self." + layer['name'] + " = nn.LPPool2d(") f.write(str(layer['para']['power']) + ",") f.write(str(layer['para']['kernel'])) for k, v in layer['para'].items(): if k == 'stride' and v is not None: f.write("," + k + "=" + str(v)) f.write(")\n") elif layer['type'] == 4: f.write(space * 2 + "self." + layer['name'] + " = nn.Linear(") f.write(str(layer['para']['in_size']) + ",") f.write(str(layer['para']['out_features']) + ",") f.write("bias=" + str(layer['para']['bias'])) f.write(")\n") elif layer['type'] == 7: f.write(space * 2 + "self." + layer['name'] + " = nn.BatchNorm1d(") f.write(str(layer['para']['in_size']) + ",") f.write("eps=" + str(layer['para']['eps']) + ",") f.write("momentum=" + str(layer['para']['momentum']) + ",") f.write("affine=" + str(layer['para']['affine']) + ",") f.write("track_running_stats=" + str(layer['para']['track_running_stats']) + ")\n") elif layer['type'] == 8: f.write(space * 2 + "self." + layer['name'] + " = nn.BatchNorm2d(") f.write(str(layer['para']['in_size'][0]) + ",") f.write("eps=" + str(layer['para']['eps']) + ",") f.write("momentum=" + str(layer['para']['momentum']) + ",") f.write("affine=" + str(layer['para']['affine']) + ",") f.write("track_running_stats=" + str(layer['para']['track_running_stats']) + ")\n") #以下为forward函数 f.write(space + "def forward(self") for input in self.fc_inputs.keys(): f.write("," + input) f.write("):\n") return_layers = list() for layer_id in sort: layer = self.nodes[self.id_name[layer_id]] if layer['type'] == 2 or layer['type'] == 4: f.write(space * 2 + layer['name'] + " = ") if layer['type'] == 4: input_name = self.id_name[layer['input'][0]] inner_str = "self.{0}({1}.view({1}.size()[0], -1))".format( layer['name'], input_name) else: inner_str = "self." + layer[ 'name'] + "(" + self.id_name[layer['input'] [0]] + ")" if layer['para']['activate'] != "None": if layer['para']['activate'] in ['tanh', 'sigmoid']: tmp = "torch." + layer['para'][ 'activate'] + "({})".format(inner_str) else: tmp = "F." + layer['para'][ 'activate'] + "({})".format(inner_str) inner_str = tmp if layer['para']['dropout']: tmp = "F.dropout({}, p=".format(inner_str) + str( layer['para']['dropout_radio']) + ")" inner_str = tmp f.write(inner_str) f.write("\n") elif layer['type'] in [3, 7, 8]: f.write( space * 2 + layer['name'] + " = self.{}({})\n".format( layer['name'], self.id_name[layer['input'][0]])) elif layer['type'] == 5: f.write(space * 2 + layer['name'] + " = F.softmax({}, dim=1)\n".format(self.id_name[ layer['input'][0]])) elif layer['type'] == 6: f.write(space * 2 + layer['name'] + " = F.log_softmax({}, dim=1)\n".format( self.id_name[layer['input'][0]])) elif layer['type'] == 9: f.write(space * 2 + layer['name'] + " = ") for i in range(len(layer['input']) - 1): f.write(self.id_name[layer['input'][i]] + "+") f.write(self.id_name[layer['input'][len(layer['input']) - 1]] + "\n") elif layer['type'] == 10: layers_to_cat = list() for input_id in layer['input']: input_name = self.id_name[input_id] input_layer = self.nodes[input_name] layers_to_cat.append(input_name) pad_up, pad_down, pad_left, pad_right = 0, 0, 0, 0 if input_layer['para']['out_size'][1] != layer['para'][ 'out_size'][1]: rest = (layer['para']['out_size'][1] - input_layer['para']['out_size'][1]) / 2 if rest != int(rest): pad_up, pad_down = int(rest), int(rest) + 1 else: pad_up, pad_down = int(rest), int(rest) if input_layer['para']['out_size'][2] != layer['para'][ 'out_size'][2]: rest = (layer['para']['out_size'][2] - input_layer['para']['out_size'][2]) / 2 if rest != int(rest): pad_left, pad_right = int(rest), int(rest) + 1 else: pad_left, pad_right = int(rest), int(rest) pad = (pad_left, pad_right, pad_up, pad_down) f.write(space*2+input_name+" = F.pad({}, ({}, {}, {}, {}))\n".format(input_name,\ pad_left, pad_right, pad_up, pad_down)) f.write(space * 2 + layer['name'] + " = torch.cat([{}], 1)\n".format(",".join( layers_to_cat))) elif layer['type'] == 11: layers_to_cat = list() for input_id in layer['input']: input_name = self.id_name[input_id] layers_to_cat.append(input_name) f.write(space * 2 + layer['name'] + " = torch.cat([{}], 1)\n".format(",".join( layers_to_cat))) elif layer['type'] == 12: f.write( space * 2 + layer['name'] + " = self.{}({})\n".format( layer['name'], self.id_name[layer['input'][0]])) if layer['isoutput']: return_layers.append(layer['name']) if len(return_layers) > 1: f.write(space * 2 + "return {}\n".format(",".join(return_layers))) else: f.write(space * 2 + "return {}".format(return_layers[0])) def check(self): #基于DAG的校验 if len(self.outputs) == 0: QMessageBox.warning(self, "错误", "模型没有输出") return 0 for item in self.nodes.values(): if type(item['para']['out_size']) is int: if item['para']['out_size'] <= 0: QMessageBox.warning(self, "错误", "{}层输出尺寸为负数或0".format(item['name'])) return 0 else: for size in item['para']['out_size']: if size <= 0: QMessageBox.warning( self, "错误", "{}层输出尺寸为负数或0".format(item['name'])) return 0 def import_file(self): #导入json文件重建模型 filename, _ = QFileDialog.getOpenFileName(self, '导入模型', 'C:\\', 'JSON Files (*.json)') if filename is None or filename == "": return 0 d_json = json.load(open(filename, 'r')) self.id_name = dict() self.name_id = dict() self.nodes = dict() self.net = nx.DiGraph() self.fc.clear() self.fc_inputs = dict() self.global_id = 0 self.outputs = list() self.detail.clear() self.detail.setColumnCount(2) self.detail.setHeaderLabels(["属性", "值"]) self.root = QTreeWidgetItem(self.detail) self.root.setText(0, "所有属性") for data in d_json: self.id_name[data['ID']] = data['name'] self.name_id[data['name']] = data['ID'] self.nodes[data['name']] = data self.net.add_node(data['ID']) for i in data['input']: self.net.add_edge(i, data['ID']) if data['type'] == 1: if not data['name'] in self.fc.inputs().keys(): self.fc.addInput(data['name']) self.fc_inputs[data['name']] = data['para']['out_size'] self.fc.setInput(**self.fc_inputs) elif data['type'] in [9, 10, 11]: node = self.fc.createNode( self.type_name[data['type']], name=data['name'], pos=(data['input'][0] * 120, (data['ID'] - data['input'][0]) * 150 - 500)) node.setPara(data['para']) node.setView(self.root) for i in data['input']: in_name = self.id_name[i] in_size = self.nodes[in_name]['para']['out_size'] node.addInput(in_name) if self.nodes[in_name]['type'] == 1: self.fc.connectTerminals(self.fc[in_name], node[in_name]) else: self.fc.connectTerminals( self.fc.nodes()[in_name]['dataOut'], node[in_name]) if data['isoutput']: if not data['name'] in self.fc.outputs().keys(): self.fc.addOutput(data['name']) self.fc.connectTerminals(node['dataOut'], self.fc[data['name']]) else: node = self.fc.createNode( self.type_name[data['type']], name=data['name'], pos=(data['input'][0] * 120, (data['ID'] - data['input'][0]) * 150 - 500)) node.setPara(data['para']) node.setView(self.root) if self.nodes[self.id_name[data['input'][0]]]['type'] == 1: self.fc.connectTerminals( self.fc[self.id_name[data['input'][0]]], node['dataIn']) else: self.fc.connectTerminals( self.fc.nodes()[self.id_name[data['input'][0]]] ['dataOut'], node['dataIn']) if data['isoutput']: if not data['name'] in self.fc.outputs().keys(): self.fc.addOutput(data['name']) self.fc.connectTerminals(node['dataOut'], self.fc[data['name']]) if data['isoutput']: self.outputs.append(data['ID'])
class AppWindow(QtGui.QMainWindow, hackYourOwn.Ui_MainWindow, utilitiesClass): def __init__(self, parent=None, **kwargs): super(AppWindow, self).__init__(parent) self.setupUi(self) print(self.utils) self.I = kwargs.get('I', None) self.I.set_sine1(5000) self.I.configure_trigger(0, 'CH1', 0) self.setWindowTitle('pyqtgraph example: FlowchartCustomNode') ## Create an empty flowchart with a single input and output self.fc = Flowchart(terminals={ 'In': { 'io': 'in' }, 'dataOut': { 'io': 'out' }, }) self.w = self.fc.widget() self.ExperimentLayout.addWidget(self.w.chartWidget.view) #self.WidgetLayout.addWidget(self.w.chartWidget.selInfo) ###############MODIFY INPUT NODE############################# self.inp = addWidget( self.fc.inputNode.graphicsItem(), 'input', func=self.fc.setInput, nameFunc=self.fc.inputNode.graphicsItem().nameItem.setPlainText) ############### CREATE USER LIBRARY ############################# self.library = fclib.LIBRARY.copy() # start with the default node set #add our custom nodes to the library self.library.addNodeType(self.PlotViewNode, [('Display', )]) for a in [ self.CaptureNode1, self.CaptureNode2, self.DACNode, self.VoltNode, self.GainNode ]: a.I = self.I self.library.addNodeType(self.ArrayNode, [('Data', )]) self.library.addNodeType(self.ArrayNode2D, [('Data', )]) self.library.addNodeType(self.CaptureNode1, [('Acquire', )]) self.library.addNodeType(self.CaptureNode2, [('Acquire', )]) self.library.addNodeType(self.VoltNode, [('Acquire', )]) self.library.addNodeType(self.DACNode, [('Outputs', )]) self.library.addNodeType(self.MyEvalNode, [('Outputs', )]) self.library.addNodeType(self.GainNode, [('Configure', )]) self.library.addNodeType(self.ConstantNode, [('Configure', )]) self.fc.setLibrary(self.library) ############# LIBRARY HAS BEEN POPULATED. NOW BUILD THE MENU ############### self.menu = self.buildMenu(self.w.chartWidget) self.menu.setMinimumHeight(150) self.WidgetLayout.addWidget(self.menu) self.WidgetLayout.addWidget(self.w) self.w.ui.showChartBtn.setParent(None) self.w.ui.reloadBtn.setParent(None) ############# NEXT UP : add ui elements ############### self.plot = self.add2DPlot(self.ExperimentLayout) self.plot.addLegend() self.PlotViewNode.plot = self.plot ## Now we will programmatically add nodes to define the function of the flowchart. ## Normally, the user will do this manually or by loading a pre-generated ## flowchart file. self.cap = self.fc.createNode('Capture1', pos=(0, 0)) self.v1Node = self.fc.createNode('2D Curve', pos=(200, -70)) self.v2Node = self.fc.createNode('2D Curve', pos=(200, 70)) self.fc.connectTerminals(self.fc['In'], self.cap['In']) self.fc.connectTerminals(self.cap['time'], self.v1Node['X']) self.fc.connectTerminals(self.cap['voltage'], self.v1Node['Y']) self.setStyleSheet("") def setInterconnects(self, val): if val: shape = 'cubic' else: shape = 'line' for a in self.fc.listConnections(): for x in a[1]._graphicsItem.getViewBox().allChildren(): if isinstance(x, pg.flowchart.TerminalGraphicsItem): for y in x.term.connections().items(): y[1].setStyle(shape=shape) def runOnce(self): self.fc.setInput(In=True) def buildMenu(self, CW): def buildSubMenu(node, rootMenu, subMenus): for section, node in node.items(): menu = QtGui.QMenu(section) rootMenu.addMenu(menu) if isinstance(node, OrderedDict): buildSubMenu(node, menu, subMenus) subMenus.append(menu) else: act = rootMenu.addAction(section) act.nodeType = section act.pos = None class PermanentMenu(QtGui.QMenu): def hideEvent(self, event): self.show() menu = PermanentMenu() self.subMenus = [] buildSubMenu(CW.chart.library.getNodeTree(), menu, self.subMenus) menu.triggered.connect(CW.nodeMenuTriggered) CW.menuPos = QtCore.QPoint(100, 150) return menu #self.v3Node = self.fc.createNode('PlotView', pos=(300, -150)) #self.v3Node.setView(self.curve1) #self.fc.connectTerminals(self.cap['dataOut'], self.v1Node['data']) def __del__(self): #self.looptimer.stop() print('bye') def closeEvent(self, event): self.finished = True self.fc._widget.chartWidget.close() ################################################################################################ #######################--------Display Function calls start here------------#################### ################################################################################################ class PlotViewNode(Node, utilitiesClass): """Node that displays plot data in an Plotwidget""" nodeName = '2D Curve' def __init__(self, name): self.view = None Node.__init__(self, name, terminals=OrderedDict([('X', dict(io='in')), ('Y', dict(io='in')), ('dY', dict(io='in', optional=True))])) self.txt = addWidget(self.graphicsItem(), 'plotText') self.curveName = self._name self.curve = self.addCurve( self.plot, self.curveName ) #self.plot is set by the parent prior to initialization self.txt.curve = self.curve self.sigRenamed.connect(self.renamed) def renamed(self, node, oldName): print('renamed from ', oldName, ' to ', self._name) self.renameLegendItem(self.plot.plotItem.legend, oldName, self._name) def process(self, X, Y, dY): if X is not None and Y is not None: if len(X) == len(Y): self.txt.setText('length=%d\nx: %s\ny: [%s]...' % (len(X), str(X[:20]), " ".join( format(a, ".1f") for a in Y[:20]))) try: if dY is not None and self.plot is not None: self.plot.setYRange(dY[0], dY[1]) except Exception as e: print(e) self.curve.setData(X, Y) return self.curve.setData([]) ################################################################################################ #######################--------Container Function calls start here------------################## ################################################################################################ class ArrayNode(CtrlNode): nodeName = '1 Column Array' uiTemplate = [] def __init__(self, name): self.A = [] terminals = {'In': dict(io='in'), 'ArrayOut': dict(io='out')} CtrlNode.__init__(self, name, terminals=terminals) self.container = addWidget(self.graphicsItem(), 'array', func=self.clear) def clear(self): self.A = [] self.container.label.setText('Empty') def process(self, In, display=False): try: self.A.append(float(In)) self.container.label.setText('size:%d' % len(self.A)) except Exception as e: print(e) return {'ArrayOut': np.array(self.A)} class ArrayNode2D(CtrlNode): nodeName = '2 Column Array' uiTemplate = [] def __init__(self, name): self.A = [] self.B = [] terminals = { 'In1': dict(io='in'), 'In2': dict(io='in'), 'ArrayOut1': dict(io='out'), 'ArrayOut2': dict(io='out') } CtrlNode.__init__(self, name, terminals=terminals) self.container = addWidget(self.graphicsItem(), 'array', func=self.clear) def clear(self): self.A = [] self.B = [] self.container.label.setText('Empty') def process(self, In1, In2, display=False): try: self.A.append(float(In1)) self.B.append(float(In2)) self.container.label.setText('size:%d' % len(self.A)) except Exception as e: print(e) return { 'ArrayOut1': np.array(self.A), 'ArrayOut2': np.array(self.B) } ################################################################################################ #######################--------Input Function calls start here------------###################### ################################################################################################ class CaptureNode1(CtrlNode): nodeName = 'Capture1' uiTemplate = [ ('samples', 'spin', { 'value': 1000, 'dec': False, 'step': 10, 'minStep': 1, 'bounds': [0, 10000] }), ('timegap', 'spin', { 'value': 1, 'dec': False, 'step': 10, 'minStep': 1, 'bounds': [0, 100] }), ] def __init__(self, name): terminals = OrderedDict([('In', dict(io='in')), ('time', dict(io='out')), ('voltage', dict(io='out')), ('dV', dict(io='out'))]) CtrlNode.__init__(self, name, terminals=terminals) self.comboBox = addWidget(self.graphicsItem(), 'combo', items=self.I.allAnalogChannels) def process(self, In, display=False): try: x, y = self.I.capture1(self.comboBox.currentText(), int(self.ctrls['samples'].value()), int(self.ctrls['timegap'].value())) return { 'time': x, 'voltage': y, 'dV': self.I.achans[0].get_Y_range() } except Exception as e: print(e) return {'time': None, 'voltage': None} class CaptureNode2(CtrlNode): nodeName = 'Capture2' uiTemplate = [ ('samples', 'spin', { 'value': 1000, 'dec': False, 'step': 10, 'minStep': 1, 'bounds': [0, 5000] }), ('timegap', 'spin', { 'value': 1, 'dec': False, 'step': 10, 'minStep': 1, 'bounds': [0, 100] }), ] def __init__(self, name): terminals = OrderedDict([('In', dict(io='in')), ('time', dict(io='out')), ('V_CH1', dict(io='out')), ('V_CH2', dict(io='out'))]) CtrlNode.__init__(self, name, terminals=terminals) self.comboBox = addWidget(self.graphicsItem(), 'combo', items=self.I.allAnalogChannels) def process(self, In, display=False): try: x, y1, y2 = self.I.capture2(self.ctrls['samples'].value(), self.ctrls['timegap'].value(), self.comboBox.currentText()) return {'time': x, 'V_CH1': y1, 'V_CH2': y2} except Exception as e: print(e) return {'time': None, 'V_CH1': None, 'V_CH2': None} class VoltNode(CtrlNode): nodeName = 'AnalogIn' uiTemplate = [ ('channel', 'combo', { 'values': ['CH1', 'CH2', 'CH3', 'AN8', 'SEN', 'CAP'] }), ] def __init__(self, name): terminals = {'trig': dict(io='in'), 'V_out': dict(io='out')} CtrlNode.__init__(self, name, terminals=terminals) def process(self, trig, display=False): if trig != None: try: val = self.I.get_voltage( self.ctrls['channel'].currentText()) return {'V_out': val} except Exception as e: print(e) return {'V_out': None} ################################################################################################ #######################-----------Options and settings start here------------################### ################################################################################################ class GainNode(CtrlNode, utilitiesClass): nodeName = 'AnalogGain' def __init__(self, name): terminals = {} CtrlNode.__init__(self, name, terminals=terminals) self.graphicsItem().nameItem.setPlainText('') self.wg = self.gainIcon(FUNC=self.I.set_gain) self.comboBox = addWidget(self.graphicsItem(), 'generic', self.wg) def process(self, display=False): pass #return {'Y_CH1':self.I.achans['CH1'].get_Y_range(),'Y_CH2':self.I.achans['CH2'].get_Y_range()} class ConstantNode(CtrlNode): nodeName = 'Constant' def __init__(self, name): terminals = {'value': {'io': 'out', 'multiable': True}} CtrlNode.__init__(self, name, terminals=terminals) def process(self, display=False): return {'value': [-4, 4]} ################################################################################################ #######################----------Output Function calls start here------------################### ################################################################################################ class DACNode(CtrlNode): nodeName = 'PVx' uiTemplate = [ ('channel', 'combo', { 'values': ['PV1', 'PV2', 'PV3'] }), ] def __init__(self, name): terminals = {'V_in': dict(io='in'), 'V_out': dict(io='out')} CtrlNode.__init__(self, name, terminals=terminals) self.label = addWidget(self.graphicsItem(), 'label', units='V') def process(self, V_in, display=False): if V_in: try: val = self.I.DAC.setVoltage( self.ctrls['channel'].currentText(), V_in) self.label.setValue(val) return {'V_out': val} except Exception as e: print(e) return {'V_out': None} class MyEvalNode(Node): """Return the output of a string evaluated/executed by the python interpreter. The string may be either an expression or a python script, and inputs are accessed as the name of the terminal. For expressions, a single value may be evaluated for a single output, or a dict for multiple outputs. For a script, the text will be executed as the body of a function.""" nodeName = 'MyPythonEval' def __init__(self, name): Node.__init__(self, name, terminals={ 'input': { 'io': 'in', 'renamable': True, 'multiable': True }, 'output': { 'io': 'out', 'renamable': True, 'multiable': True }, }, allowAddInput=True, allowAddOutput=True) self.ui = QtGui.QWidget() self.layout = QtGui.QGridLayout() self.text = QtGui.QTextEdit() self.text.setTabStopWidth(30) self.text.setPlainText( "# Access inputs as args['input_name']\nreturn {'output': None} ## one key per output terminal" ) self.layout.addWidget(self.text, 1, 0, 1, 2) self.ui.setLayout(self.layout) #QtCore.QObject.connect(self.addInBtn, QtCore.SIGNAL('clicked()'), self.addInput) #self.addInBtn.clicked.connect(self.addInput) #QtCore.QObject.connect(self.addOutBtn, QtCore.SIGNAL('clicked()'), self.addOutput) #self.addOutBtn.clicked.connect(self.addOutput) self.text.focusOutEvent = self.focusOutEvent self.lastText = None def focusOutEvent(self, ev): text = str(self.text.toPlainText()) if text != self.lastText: self.lastText = text self.update() return QtGui.QTextEdit.focusOutEvent(self.text, ev) def process(self, display=True, **args): l = locals() l.update(args) ## try eval first, then exec try: text = str(self.text.toPlainText()).replace('\n', ' ') output = eval(text, globals(), l) except SyntaxError: fn = "def fn(**args):\n" run = "\noutput=fn(**args)\n" text = fn + "\n".join([ " " + l for l in str(self.text.toPlainText()).split('\n') ]) + run exec(text) except: print("Error processing node: %s" % self.name()) raise return output def saveState(self): state = Node.saveState(self) state['text'] = str(self.text.toPlainText()) return state def restoreState(self, state): Node.restoreState(self, state) self.text.clear() self.text.insertPlainText(state['text']) self.restoreTerminals(state['terminals']) self.update()
## Add two plot widgets pw1 = pg.PlotWidget() pw2 = pg.PlotWidget() layout.addWidget(pw1, 0, 1) layout.addWidget(pw2, 1, 1) win.show() ## generate signal data to pass through the flowchart data = np.random.normal(size=1000) data[200:300] += 1 data += np.sin(np.linspace(0, 100, 1000)) data = metaarray.MetaArray(data, info=[{'name': 'Time', 'values': np.linspace(0, 1.0, len(data))}, {}]) ## Feed data into the input terminal of the flowchart fc.setInput(dataIn=data) ## populate the flowchart with a basic set of processing nodes. ## (usually we let the user do this) plotList = {'Top Plot': pw1, 'Bottom Plot': pw2} pw1Node = fc.createNode('PlotWidget', pos=(0, -150)) pw1Node.setPlotList(plotList) pw1Node.setPlot(pw1) pw2Node = fc.createNode('PlotWidget', pos=(150, -150)) pw2Node.setPlot(pw2) pw2Node.setPlotList(plotList) fNode = fc.createNode('GaussianFilter', pos=(0, 0)) fNode.ctrls['sigma'].setValue(5)
def __init__(self, data_In=None, dataB_In=None, *args, **kwargs): super().__init__() # data_In will be Adata if data_In == None: print("Please load data") # For testing, create noise data data_In = [] for i in range(50): dat = np.random.normal(size=1024) dat[200:300] += 1 dat += np.sin(np.linspace(0, 100, 1024)) data_In.append(dat) data_In = np.array(data_In) self.ui = Ui_BackgroundSubtraction() self.ui.setupUi(self) # Change plot labels, because I was too lazy to create a new widget pw1 = self.ui.View_Orig pw1.plt.setLabel('bottom', 'Magnetic Field', units='T') # X-Axis pw1.plt.setLabel('left', "Amplitude (Arb. Units)", units='') # Y-Axis pw2 = self.ui.View_Mod pw2.plt.setLabel('bottom', 'Magnetic Field', units='T') # X-Axis pw2.plt.setLabel('left', "Amplitude (Arb. Units)", units='') # Y-Axis pw3 = self.ui.View_Colour # Create Flowchart with two IO Nodes fc = Flowchart(terminals={ 'dataIn': { 'io': 'in' }, 'dataOut': { 'io': 'out' } }) w = fc.widget() self.ui.gridLayout.addWidget(w) # Create metaarray using data_In and some information #data = metaarray.MetaArray(data_In, info=[{'name': 'Amplitude data'}, {}]) fc.setInput(dataIn=data_In) #Set data to Input Node ## If we want to make our custom node available only to this flowchart, ## then instead of registering the node type globally, we can create a new ## NodeLibrary: library = fclib.LIBRARY.copy() # start with the default node set # Add the node to two locations in the menu to demonstrate # that we can create arbitrary menu structures library.addNodeType(SavGol_Smooth, [('FMR', 'Filter')]) library.addNodeType(SavGol_Smooth_2D, [('FMR', 'Filter')]) library.addNodeType(FMR_Subtract_Average, [('FMR', 'Filter')]) library.addNodeType(FMR_Subtract_Average_Colour, [('FMR', 'Filter')]) library.addNodeType(Measurement_Select, [('FMR', 'Data')]) library.addNodeType(Average_Ang_Dep, [('FMR', 'Data')]) library.addNodeType(ImageViewNode, [('Display', )]) fc.setLibrary(library) plotList = {'Top Plot': pw1.plt, 'Bottom Plot': pw2.plt} pw1Node = fc.createNode('PlotWidget', pos=(0, -150)) pw1Node.setPlotList(plotList) pw1Node.setPlot(pw1.plt) pw2Node = fc.createNode('PlotWidget', pos=(150, -150)) pw2Node.setPlot(pw2.plt) pw2Node.setPlotList(plotList) pw3Node = fc.createNode('ImageView', pos=(300, -150)) pw3Node.setView(pw3.img) fNode = fc.createNode('Spectrum select', pos=(0, 0)) fc.connectTerminals( fc['dataIn'], fNode['dataIn'] ) # Use this Slice node to select the measurement that you want to smooth aka axis fc.connectTerminals(fNode['dataOut'], pw1Node['In']) fc.connectTerminals(fNode['dataOut'], pw2Node['In']) fc.connectTerminals(fNode['dataOut'], fc['dataOut'])