Flowchart fixes: better job managing / saving / restoring 'muli' state of terminals

This commit is contained in:
Luke Campagnola 2012-06-21 22:02:19 -04:00
parent d1fdbadd19
commit 5b6f77be58
5 changed files with 40 additions and 65 deletions

View File

@ -71,7 +71,8 @@ class Flowchart(Node):
if terminals is None: if terminals is None:
terminals = {} terminals = {}
self.filePath = filePath self.filePath = filePath
Node.__init__(self, name) ## create node without terminals; we'll add these later Node.__init__(self, name, allowAddInput=True, allowAddOutput=True) ## create node without terminals; we'll add these later
self.inputWasSet = False ## flag allows detection of changes in the absence of input change. self.inputWasSet = False ## flag allows detection of changes in the absence of input change.
self._nodes = {} self._nodes = {}
@ -457,7 +458,7 @@ class Flowchart(Node):
state = Node.saveState(self) state = Node.saveState(self)
state['nodes'] = [] state['nodes'] = []
state['connects'] = [] state['connects'] = []
state['terminals'] = self.saveTerminals() #state['terminals'] = self.saveTerminals()
for name, node in self._nodes.items(): for name, node in self._nodes.items():
cls = type(node) cls = type(node)
@ -486,7 +487,8 @@ class Flowchart(Node):
nodes.sort(lambda a, b: cmp(a['pos'][0], b['pos'][0])) nodes.sort(lambda a, b: cmp(a['pos'][0], b['pos'][0]))
for n in nodes: for n in nodes:
if n['name'] in self._nodes: if n['name'] in self._nodes:
self._nodes[n['name']].moveBy(*n['pos']) #self._nodes[n['name']].graphicsItem().moveBy(*n['pos'])
self._nodes[n['name']].restoreState(n['state'])
continue continue
try: try:
node = self.createNode(n['class'], name=n['name']) node = self.createNode(n['class'], name=n['name'])
@ -498,7 +500,7 @@ class Flowchart(Node):
self.inputNode.restoreState(state.get('inputNode', {})) self.inputNode.restoreState(state.get('inputNode', {}))
self.outputNode.restoreState(state.get('outputNode', {})) self.outputNode.restoreState(state.get('outputNode', {}))
self.restoreTerminals(state['terminals']) #self.restoreTerminals(state['terminals'])
for n1, t1, n2, t2 in state['connects']: for n1, t1, n2, t2 in state['connects']:
try: try:
self.connectTerminals(self._nodes[n1][t1], self._nodes[n2][t2]) self.connectTerminals(self._nodes[n1][t1], self._nodes[n2][t2])

View File

@ -1,16 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from pyqtgraph.Qt import QtCore, QtGui from pyqtgraph.Qt import QtCore, QtGui
#from PySide import QtCore, QtGui
from pyqtgraph.graphicsItems.GraphicsObject import GraphicsObject from pyqtgraph.graphicsItems.GraphicsObject import GraphicsObject
import pyqtgraph.functions as fn import pyqtgraph.functions as fn
from .Terminal import * from .Terminal import *
from collections import OrderedDict from collections import OrderedDict
from pyqtgraph.debug import * from pyqtgraph.debug import *
import numpy as np import numpy as np
#from pyqtgraph.ObjectWorkaround import QObjectWorkaround
from .eq import * from .eq import *
#TETRACYCLINE = True
def strDict(d): def strDict(d):
return dict([(str(k), v) for k, v in d.items()]) return dict([(str(k), v) for k, v in d.items()])
@ -32,8 +29,8 @@ class Node(QtCore.QObject):
self.bypassButton = None ## this will be set by the flowchart ctrl widget.. self.bypassButton = None ## this will be set by the flowchart ctrl widget..
self._graphicsItem = None self._graphicsItem = None
self.terminals = OrderedDict() self.terminals = OrderedDict()
self._inputs = {} self._inputs = OrderedDict()
self._outputs = {} self._outputs = OrderedDict()
self._allowAddInput = allowAddInput ## flags to allow the user to add/remove terminals self._allowAddInput = allowAddInput ## flags to allow the user to add/remove terminals
self._allowAddOutput = allowAddOutput self._allowAddOutput = allowAddOutput
self._allowRemove = allowRemove self._allowRemove = allowRemove
@ -85,24 +82,16 @@ class Node(QtCore.QObject):
def terminalRenamed(self, term, oldName): def terminalRenamed(self, term, oldName):
"""Called after a terminal has been renamed""" """Called after a terminal has been renamed"""
newName = term.name() newName = term.name()
#print "node", self, "handling rename..", newName, oldName
for d in [self.terminals, self._inputs, self._outputs]: for d in [self.terminals, self._inputs, self._outputs]:
if oldName not in d: if oldName not in d:
continue continue
#print " got one"
d[newName] = d[oldName] d[newName] = d[oldName]
del d[oldName] del d[oldName]
self.graphicsItem().updateTerminals() self.graphicsItem().updateTerminals()
#self.emit(QtCore.SIGNAL('terminalRenamed'), term, oldName)
self.sigTerminalRenamed.emit(term, oldName) self.sigTerminalRenamed.emit(term, oldName)
def addTerminal(self, name, **opts): def addTerminal(self, name, **opts):
#print "Node.addTerminal called. name:", name, "opts:", opts
#global TETRACYCLINE
#print "TETRACYCLINE: ", TETRACYCLINE
#if TETRACYCLINE:
#print "Creating Terminal..."
name = self.nextTerminalName(name) name = self.nextTerminalName(name)
term = Terminal(self, name, **opts) term = Terminal(self, name, **opts)
self.terminals[name] = term self.terminals[name] = term
@ -278,12 +267,20 @@ class Node(QtCore.QObject):
def saveState(self): def saveState(self):
pos = self.graphicsItem().pos() pos = self.graphicsItem().pos()
return {'pos': (pos.x(), pos.y()), 'bypass': self.isBypassed()} state = {'pos': (pos.x(), pos.y()), 'bypass': self.isBypassed()}
termsEditable = self._allowAddInput | self._allowAddOutput
for term in self._inputs.values() + self._outputs.values():
termsEditable |= term._renamable | term._removable | term._multiable
if termsEditable:
state['terminals'] = self.saveTerminals()
return state
def restoreState(self, state): def restoreState(self, state):
pos = state.get('pos', (0,0)) pos = state.get('pos', (0,0))
self.graphicsItem().setPos(*pos) self.graphicsItem().setPos(*pos)
self.bypass(state.get('bypass', False)) self.bypass(state.get('bypass', False))
if 'terminals' in state:
self.restoreTerminals(state['terminals'])
def saveTerminals(self): def saveTerminals(self):
terms = OrderedDict() terms = OrderedDict()
@ -309,8 +306,8 @@ class Node(QtCore.QObject):
for t in self.terminals.values(): for t in self.terminals.values():
t.close() t.close()
self.terminals = OrderedDict() self.terminals = OrderedDict()
self._inputs = {} self._inputs = OrderedDict()
self._outputs = {} self._outputs = OrderedDict()
def close(self): def close(self):
"""Cleans up after the node--removes terminals, graphicsItem, widget""" """Cleans up after the node--removes terminals, graphicsItem, widget"""
@ -493,10 +490,6 @@ class NodeGraphicsItem(GraphicsObject):
self.hovered = False self.hovered = False
self.update() self.update()
#def mouseReleaseEvent(self, ev):
#ret = QtGui.QGraphicsItem.mouseReleaseEvent(self, ev)
#return ret
def keyPressEvent(self, ev): def keyPressEvent(self, ev):
if ev.key() == QtCore.Qt.Key_Delete or ev.key() == QtCore.Qt.Key_Backspace: if ev.key() == QtCore.Qt.Key_Delete or ev.key() == QtCore.Qt.Key_Backspace:
ev.accept() ev.accept()
@ -513,14 +506,9 @@ class NodeGraphicsItem(GraphicsObject):
return GraphicsObject.itemChange(self, change, val) return GraphicsObject.itemChange(self, change, val)
#def contextMenuEvent(self, ev):
#ev.accept()
#self.menu.popup(ev.screenPos())
def getMenu(self): def getMenu(self):
return self.menu return self.menu
def getContextMenus(self, event): def getContextMenus(self, event):
return [self.menu] return [self.menu]
@ -548,25 +536,3 @@ class NodeGraphicsItem(GraphicsObject):
def addOutputFromMenu(self): ## called when add output is clicked in context menu def addOutputFromMenu(self): ## called when add output is clicked in context menu
self.node.addOutput(renamable=True, removable=True, multiable=False) self.node.addOutput(renamable=True, removable=True, multiable=False)
#def menuTriggered(self, action):
##print "node.menuTriggered called. action:", action
#act = str(action.text())
#if act == "Add input":
#self.node.addInput()
#self.updateActionMenu()
#elif act == "Add output":
#self.node.addOutput()
#self.updateActionMenu()
#elif act == "Remove node":
#self.node.close()
#else: ## only other option is to remove a terminal
#self.node.removeTerminal(act)
#self.terminalMenu.removeAction(action)
#def updateActionMenu(self):
#for t in self.node.terminals:
#if t not in [str(a.text()) for a in self.terminalMenu.actions()]:
#self.terminalMenu.addAction(t)
#for a in self.terminalMenu.actions():
#if str(a.text()) not in self.node.terminals:
#self.terminalMenu.removeAction(a)

View File

@ -70,6 +70,8 @@ class Terminal:
return return
self._value = val self._value = val
else: else:
if not isinstance(self._value, dict):
self._value = {}
if val is not None: if val is not None:
self._value.update(val) self._value.update(val)
@ -132,9 +134,14 @@ class Terminal:
def isMultiValue(self): def isMultiValue(self):
return self._multi return self._multi
def setMultiValue(self, b): def setMultiValue(self, multi):
"""Set whether this is a multi-value terminal.""" """Set whether this is a multi-value terminal."""
self._multi = b self._multi = multi
if not multi and len(self.inputTerminals()) > 1:
self.disconnectAll()
for term in self.inputTerminals():
self.inputChanged(term)
def isOutput(self): def isOutput(self):
return self._io == 'out' return self._io == 'out'
@ -407,6 +414,8 @@ class TerminalGraphicsItem(GraphicsObject):
multiAct = QtGui.QAction("Multi-value", self.menu) multiAct = QtGui.QAction("Multi-value", self.menu)
multiAct.setCheckable(True) multiAct.setCheckable(True)
multiAct.setChecked(self.term.isMultiValue()) multiAct.setChecked(self.term.isMultiValue())
multiAct.setEnabled(self.term.isMultiable())
multiAct.triggered.connect(self.toggleMulti) multiAct.triggered.connect(self.toggleMulti)
self.menu.addAction(multiAct) self.menu.addAction(multiAct)
self.menu.multiAct = multiAct self.menu.multiAct = multiAct

View File

@ -240,7 +240,7 @@ class EvalNode(Node):
def saveState(self): def saveState(self):
state = Node.saveState(self) state = Node.saveState(self)
state['text'] = str(self.text.toPlainText()) state['text'] = str(self.text.toPlainText())
state['terminals'] = self.saveTerminals() #state['terminals'] = self.saveTerminals()
return state return state
def restoreState(self, state): def restoreState(self, state):
@ -282,7 +282,7 @@ class ColumnJoinNode(Node):
def addInput(self): def addInput(self):
#print "ColumnJoinNode.addInput called." #print "ColumnJoinNode.addInput called."
term = Node.addInput(self, 'input', renamable=True) term = Node.addInput(self, 'input', renamable=True, removable=True)
#print "Node.addInput returned. term:", term #print "Node.addInput returned. term:", term
item = QtGui.QTreeWidgetItem([term.name()]) item = QtGui.QTreeWidgetItem([term.name()])
item.term = term item.term = term
@ -322,16 +322,14 @@ class ColumnJoinNode(Node):
def restoreState(self, state): def restoreState(self, state):
Node.restoreState(self, state) Node.restoreState(self, state)
inputs = [inp.name() for inp in self.inputs()] inputs = self.inputs()
order = [name for name in state['order'] if name in inputs]
for name in inputs: for name in inputs:
if name not in state['order']: if name not in order:
self.removeTerminal(name) order.append(name)
for name in state['order']:
if name not in inputs:
Node.addInput(self, name, renamable=True)
self.tree.clear() self.tree.clear()
for name in state['order']: for name in order:
term = self[name] term = self[name]
item = QtGui.QTreeWidgetItem([name]) item = QtGui.QTreeWidgetItem([name])
item.term = term item.term = term

View File

@ -153,7 +153,7 @@ def denoise(data, radius=2, threshold=4):
r2 = radius * 2 r2 = radius * 2
d1 = data.view(np.ndarray) d1 = data.view(np.ndarray)
d2 = data[radius:] - data[:-radius] #a derivative d2 = d1[radius:] - d1[:-radius] #a derivative
#d3 = data[r2:] - data[:-r2] #d3 = data[r2:] - data[:-r2]
#d4 = d2 - d3 #d4 = d2 - d3
stdev = d2.std() stdev = d2.std()