PlotNode control widget now displays combo box to let user select plots to connect to

Flowchart example updated to use this feature.
This commit is contained in:
Luke Campagnola 2013-12-27 21:07:03 -05:00
parent 2c2135a49f
commit 4886270b53
3 changed files with 57 additions and 38 deletions

View File

@ -58,11 +58,15 @@ fc.setInput(dataIn=data)
## populate the flowchart with a basic set of processing nodes. ## populate the flowchart with a basic set of processing nodes.
## (usually we let the user do this) ## (usually we let the user do this)
plotList = {'Top Plot': pw1, 'Bottom Plot': pw2}
pw1Node = fc.createNode('PlotWidget', pos=(0, -150)) pw1Node = fc.createNode('PlotWidget', pos=(0, -150))
pw1Node.setPlotList(plotList)
pw1Node.setPlot(pw1) pw1Node.setPlot(pw1)
pw2Node = fc.createNode('PlotWidget', pos=(150, -150)) pw2Node = fc.createNode('PlotWidget', pos=(150, -150))
pw2Node.setPlot(pw2) pw2Node.setPlot(pw2)
pw2Node.setPlotList(plotList)
fNode = fc.createNode('GaussianFilter', pos=(0, 0)) fNode = fc.createNode('GaussianFilter', pos=(0, 0))
fNode.ctrls['sigma'].setValue(5) fNode.ctrls['sigma'].setValue(5)

View File

@ -4,7 +4,7 @@ import weakref
from ...Qt import QtCore, QtGui from ...Qt import QtCore, QtGui
from ...graphicsItems.ScatterPlotItem import ScatterPlotItem from ...graphicsItems.ScatterPlotItem import ScatterPlotItem
from ...graphicsItems.PlotCurveItem import PlotCurveItem from ...graphicsItems.PlotCurveItem import PlotCurveItem
from ... import PlotDataItem from ... import PlotDataItem, ComboBox
from .common import * from .common import *
import numpy as np import numpy as np
@ -16,7 +16,9 @@ class PlotWidgetNode(Node):
def __init__(self, name): def __init__(self, name):
Node.__init__(self, name, terminals={'In': {'io': 'in', 'multi': True}}) Node.__init__(self, name, terminals={'In': {'io': 'in', 'multi': True}})
self.plot = None self.plot = None # currently selected plot
self.plots = {} # list of available plots user may select from
self.ui = None
self.items = {} self.items = {}
def disconnected(self, localTerm, remoteTerm): def disconnected(self, localTerm, remoteTerm):
@ -26,16 +28,27 @@ class PlotWidgetNode(Node):
def setPlot(self, plot): def setPlot(self, plot):
#print "======set plot" #print "======set plot"
if plot == self.plot:
return
# clear data from previous plot
if self.plot is not None:
for vid in list(self.items.keys()):
self.plot.removeItem(self.items[vid])
del self.items[vid]
self.plot = plot self.plot = plot
self.updateUi()
self.update()
self.sigPlotChanged.emit(self) self.sigPlotChanged.emit(self)
def getPlot(self): def getPlot(self):
return self.plot return self.plot
def process(self, In, display=True): def process(self, In, display=True):
if display: if display and self.plot is not None:
#self.plot.clearPlots()
items = set() items = set()
# Add all new input items to selected plot
for name, vals in In.items(): for name, vals in In.items():
if vals is None: if vals is None:
continue continue
@ -45,14 +58,13 @@ class PlotWidgetNode(Node):
for val in vals: for val in vals:
vid = id(val) vid = id(val)
if vid in self.items and self.items[vid].scene() is self.plot.scene(): if vid in self.items and self.items[vid].scene() is self.plot.scene():
# Item is already added to the correct scene
# possible bug: what if two plots occupy the same scene? (should
# rarely be a problem because items are removed from a plot before
# switching).
items.add(vid) items.add(vid)
else: else:
#if isinstance(val, PlotCurveItem): # Add the item to the plot, or generate a new item if needed.
#self.plot.addItem(val)
#item = val
#if isinstance(val, ScatterPlotItem):
#self.plot.addItem(val)
#item = val
if isinstance(val, QtGui.QGraphicsItem): if isinstance(val, QtGui.QGraphicsItem):
self.plot.addItem(val) self.plot.addItem(val)
item = val item = val
@ -60,21 +72,47 @@ class PlotWidgetNode(Node):
item = self.plot.plot(val) item = self.plot.plot(val)
self.items[vid] = item self.items[vid] = item
items.add(vid) items.add(vid)
# Any left-over items that did not appear in the input must be removed
for vid in list(self.items.keys()): for vid in list(self.items.keys()):
if vid not in items: if vid not in items:
#print "remove", self.items[vid]
self.plot.removeItem(self.items[vid]) self.plot.removeItem(self.items[vid])
del self.items[vid] del self.items[vid]
def processBypassed(self, args): def processBypassed(self, args):
if self.plot is None:
return
for item in list(self.items.values()): for item in list(self.items.values()):
self.plot.removeItem(item) self.plot.removeItem(item)
self.items = {} self.items = {}
#def setInput(self, **args): def ctrlWidget(self):
#for k in args: if self.ui is None:
#self.plot.plot(args[k]) self.ui = ComboBox()
self.ui.currentIndexChanged.connect(self.plotSelected)
self.updateUi()
return self.ui
def plotSelected(self, index):
self.setPlot(self.ui.value())
def setPlotList(self, plots):
"""
Specify the set of plots (PlotWidget or PlotItem) that the user may
select from.
*plots* must be a dictionary of {name: plot} pairs.
"""
self.plots = plots
self.updateUi()
def updateUi(self):
# sets list and automatically preserves previous selection
self.ui.setItems(self.plots)
try:
self.ui.setValue(self.plot)
except ValueError:
pass
class CanvasNode(Node): class CanvasNode(Node):

View File

@ -95,7 +95,6 @@ class PlotItem(GraphicsWidget):
lastFileDir = None lastFileDir = None
managers = {}
def __init__(self, parent=None, name=None, labels=None, title=None, viewBox=None, axisItems=None, enableMenu=True, **kargs): def __init__(self, parent=None, name=None, labels=None, title=None, viewBox=None, axisItems=None, enableMenu=True, **kargs):
""" """
@ -369,28 +368,6 @@ class PlotItem(GraphicsWidget):
self.scene().removeItem(self.vb) self.scene().removeItem(self.vb)
self.vb = None self.vb = None
## causes invalid index errors:
#for i in range(self.layout.count()):
#self.layout.removeAt(i)
#for p in self.proxies:
#try:
#p.setWidget(None)
#except RuntimeError:
#break
#self.scene().removeItem(p)
#self.proxies = []
#self.menuAction.releaseWidget(self.menuAction.defaultWidget())
#self.menuAction.setParent(None)
#self.menuAction = None
#if self.manager is not None:
#self.manager.sigWidgetListChanged.disconnect(self.updatePlotList)
#self.manager.removeWidget(self.name)
#else:
#print "no manager"
def registerPlot(self, name): ## for backward compatibility def registerPlot(self, name): ## for backward compatibility
self.vb.register(name) self.vb.register(name)