Minor updates and bug fixes:

- fixed handling of foreground colors in AxisItem
  - fixed rare crash caused in AxisItem 
  - fixed improper propagation of key events from SpinBox
  - many others
This commit is contained in:
Luke Campagnola 2012-08-31 17:18:06 -04:00
parent bb48f1cb36
commit 0402d08604
18 changed files with 101 additions and 39 deletions

View File

@ -182,7 +182,7 @@ def plot(*args, **kargs):
#if len(args)+len(kargs) > 0:
#w.plot(*args, **kargs)
pwArgList = ['title', 'label', 'name', 'left', 'right', 'top', 'bottom']
pwArgList = ['title', 'labels', 'name', 'left', 'right', 'top', 'bottom']
pwArgs = {}
dataArgs = {}
for k in kargs:

View File

@ -122,7 +122,7 @@ params = [
]
## Create tree of Parameter objects
p = Parameter(name='params', type='group', children=params)
p = Parameter.create(name='params', type='group', children=params)
## If anything changes in the tree, print a message
def change(param, changes):

View File

@ -160,7 +160,10 @@ class Flowchart(Node):
Node.addTerminal(self, term.name(), io=io, renamable=term.isRenamable(), removable=term.isRemovable(), multiable=term.isMultiable())
def internalTerminalRemoved(self, node, term):
Node.removeTerminal(self, term.name())
try:
Node.removeTerminal(self, term.name())
except KeyError:
pass
def terminalRenamed(self, term, oldName):
newName = term.name()

View File

@ -294,6 +294,8 @@ class Node(QtCore.QObject):
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)

View File

@ -85,6 +85,14 @@ class Terminal:
#if c.isInput():
#c.inputChanged(self)
self.recolor()
def setOpts(self, **opts):
self._renamable = opts.get('renamable', self._renamable)
self._removable = opts.get('removable', self._removable)
self._multiable = opts.get('multiable', self._multiable)
if 'multi' in opts:
self.setMultiValue(opts['multi'])
def connected(self, term):
"""Called whenever this terminal has been connected to another. (note--this function is called on both terminals)"""

View File

@ -235,6 +235,9 @@ class EvalNode(Node):
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:", self.name()
raise
return output
def saveState(self):
@ -282,7 +285,7 @@ class ColumnJoinNode(Node):
def addInput(self):
#print "ColumnJoinNode.addInput called."
term = Node.addInput(self, 'input', renamable=True, removable=True)
term = Node.addInput(self, 'input', renamable=True, removable=True, multiable=True)
#print "Node.addInput returned. term:", term
item = QtGui.QTreeWidgetItem([term.name()])
item.term = term
@ -323,6 +326,14 @@ class ColumnJoinNode(Node):
def restoreState(self, state):
Node.restoreState(self, state)
inputs = self.inputs()
## Node.restoreState should have created all of the terminals we need
## However: to maintain support for some older flowchart files, we need
## to manually add any terminals that were not taken care of.
for name in [n for n in state['order'] if n not in inputs]:
Node.addInput(self, name, renamable=True, removable=True, multiable=True)
inputs = self.inputs()
order = [name for name in state['order'] if name in inputs]
for name in inputs:
if name not in order:
@ -343,4 +354,4 @@ class ColumnJoinNode(Node):
item.setText(0, term.name())
self.update()

View File

@ -184,13 +184,16 @@ class HistogramDetrend(CtrlNode):
nodeName = 'HistogramDetrend'
uiTemplate = [
('windowSize', 'intSpin', {'value': 500, 'min': 10, 'max': 1000000, 'suffix': 'pts'}),
('numBins', 'intSpin', {'value': 50, 'min': 3, 'max': 1000000})
('numBins', 'intSpin', {'value': 50, 'min': 3, 'max': 1000000}),
('offsetOnly', 'check', {'checked': False}),
]
def processData(self, data):
ws = self.ctrls['windowSize'].value()
bn = self.ctrls['numBins'].value()
return functions.histogramDetrend(data, window=ws, bins=bn)
s = self.stateGroup.state()
#ws = self.ctrls['windowSize'].value()
#bn = self.ctrls['numBins'].value()
#offset = self.ctrls['offsetOnly'].checked()
return functions.histogramDetrend(data, window=s['windowSize'], bins=s['numBins'], offsetOnly=s['offsetOnly'])

View File

@ -196,8 +196,10 @@ def adaptiveDetrend(data, x=None, threshold=3.0):
return d4
def histogramDetrend(data, window=500, bins=50, threshold=3.0):
"""Linear detrend. Works by finding the most common value at the beginning and end of a trace, excluding outliers."""
def histogramDetrend(data, window=500, bins=50, threshold=3.0, offsetOnly=False):
"""Linear detrend. Works by finding the most common value at the beginning and end of a trace, excluding outliers.
If offsetOnly is True, then only the offset from the beginning of the trace is subtracted.
"""
d1 = data.view(np.ndarray)
d2 = [d1[:window], d1[-window:]]
@ -211,8 +213,11 @@ def histogramDetrend(data, window=500, bins=50, threshold=3.0):
ind = np.argmax(y)
v[i] = 0.5 * (x[ind] + x[ind+1])
base = np.linspace(v[0], v[1], len(data))
d3 = data.view(np.ndarray) - base
if offsetOnly:
d3 = data.view(np.ndarray) - v[0]
else:
base = np.linspace(v[0], v[1], len(data))
d3 = data.view(np.ndarray) - base
if (hasattr(data, 'implements') and data.implements('MetaArray')):
return MetaArray(d3, info=data.infoCopy())

View File

@ -261,7 +261,7 @@ def mkPen(*args, **kargs):
if isinstance(arg, dict):
return mkPen(**arg)
if isinstance(arg, QtGui.QPen):
return arg
return QtGui.QPen(arg) ## return a copy of this pen
elif arg is None:
style = QtCore.Qt.NoPen
else:

View File

@ -56,7 +56,7 @@ class AxisItem(GraphicsWidget):
self.labelText = ''
self.labelUnits = ''
self.labelUnitPrefix=''
self.labelStyle = {'color': '#CCC'}
self.labelStyle = {}
self.logMode = False
self.textHeight = 18
@ -167,7 +167,7 @@ class AxisItem(GraphicsWidget):
s = asUnicode('%s %s') % (self.labelText, units)
style = ';'.join(['%s: "%s"' % (k, self.labelStyle[k]) for k in self.labelStyle])
style = ';'.join(['%s: %s' % (k, self.labelStyle[k]) for k in self.labelStyle])
return asUnicode("<span style='%s'>%s</span>") % (style, s)
@ -192,7 +192,7 @@ class AxisItem(GraphicsWidget):
def pen(self):
if self._pen is None:
return fn.mkPen(pg.getConfigOption('foreground'))
return self._pen
return pg.mkPen(self._pen)
def setPen(self, pen):
"""
@ -202,6 +202,10 @@ class AxisItem(GraphicsWidget):
"""
self._pen = pen
self.picture = None
if pen is None:
pen = pg.getConfigOption('foreground')
self.labelStyle['color'] = '#' + pg.colorStr(pg.mkPen(pen).color())[:6]
self.setLabel()
self.update()
def setScale(self, scale=None):
@ -299,8 +303,8 @@ class AxisItem(GraphicsWidget):
self.drawPicture(painter)
finally:
painter.end()
p.setRenderHint(p.Antialiasing, False)
p.setRenderHint(p.TextAntialiasing, True)
#p.setRenderHint(p.Antialiasing, False) ## Sometimes we get a segfault here ???
#p.setRenderHint(p.TextAntialiasing, True)
self.picture.play(p)

View File

@ -47,6 +47,8 @@ class GradientLegend(UIGraphicsItem):
UIGraphicsItem.paint(self, p, opt, widget)
rect = self.boundingRect() ## Boundaries of visible area in scene coords.
unit = self.pixelSize() ## Size of one view pixel in scene coords.
if unit[0] is None:
return
## determine max width of all labels
labelWidth = 0

View File

@ -1017,7 +1017,7 @@ class PlotItem(GraphicsWidget):
(ie, use 'V' instead of 'mV'; 'm' will be added automatically)
============= =================================================================
"""
self.getScale(axis).setLabel(text=text, units=units, **args)
self.getAxis(axis).setLabel(text=text, units=units, **args)
def showLabel(self, axis, show=True):
"""

View File

@ -71,7 +71,6 @@ class ScatterPlotItem(GraphicsObject):
#sigPointClicked = QtCore.Signal(object, object)
sigClicked = QtCore.Signal(object, object) ## self, points
sigPlotChanged = QtCore.Signal(object)
def __init__(self, *args, **kargs):
"""
Accepts the same arguments as setData()
@ -231,6 +230,9 @@ class ScatterPlotItem(GraphicsObject):
self.generateSpotItems()
self.sigPlotChanged.emit(self)
def getData(self):
return self.data['x'], self.data['y']
def setPoints(self, *args, **kargs):
##Deprecated; use setData

View File

@ -310,6 +310,12 @@ class Parameter(QtCore.QObject):
"""
return not self.opts.get('readonly', False)
def setWritable(self, writable=True):
self.setOpts(readonly=not writable)
def setReadonly(self, readonly=True):
self.setOpts(readonly=readonly)
def setOpts(self, **opts):
"""
Set any arbitrary options on this parameter.

View File

@ -26,6 +26,7 @@ class ParameterItem(QtGui.QTreeWidgetItem):
param.sigLimitsChanged.connect(self.limitsChanged)
param.sigDefaultChanged.connect(self.defaultChanged)
param.sigOptionsChanged.connect(self.optsChanged)
param.sigParentChanged.connect(self.parentChanged)
opts = param.opts
@ -93,6 +94,10 @@ class ParameterItem(QtGui.QTreeWidgetItem):
self.takeChild(i)
break
def parentChanged(self, param, parent):
## called when the parameter's parent has changed.
pass
def contextMenuEvent(self, ev):
if not self.param.opts.get('removable', False) and not self.param.opts.get('renamable', False):
return

View File

@ -290,23 +290,7 @@ class GroupParameterItem(ParameterItem):
"""
def __init__(self, param, depth):
ParameterItem.__init__(self, param, depth)
if depth == 0:
for c in [0,1]:
self.setBackground(c, QtGui.QBrush(QtGui.QColor(100,100,100)))
self.setForeground(c, QtGui.QBrush(QtGui.QColor(220,220,255)))
font = self.font(c)
font.setBold(True)
font.setPointSize(font.pointSize()+1)
self.setFont(c, font)
self.setSizeHint(0, QtCore.QSize(0, 25))
else:
for c in [0,1]:
self.setBackground(c, QtGui.QBrush(QtGui.QColor(220,220,220)))
font = self.font(c)
font.setBold(True)
#font.setPointSize(font.pointSize()+1)
self.setFont(c, font)
self.setSizeHint(0, QtCore.QSize(0, 20))
self.updateDepth(depth)
self.addItem = None
if 'addText' in param.opts:
@ -331,6 +315,27 @@ class GroupParameterItem(ParameterItem):
self.addItem.setFlags(QtCore.Qt.ItemIsEnabled)
ParameterItem.addChild(self, self.addItem)
def updateDepth(self, depth):
## Change item's appearance based on its depth in the tree
## This allows highest-level groups to be displayed more prominently.
if depth == 0:
for c in [0,1]:
self.setBackground(c, QtGui.QBrush(QtGui.QColor(100,100,100)))
self.setForeground(c, QtGui.QBrush(QtGui.QColor(220,220,255)))
font = self.font(c)
font.setBold(True)
font.setPointSize(font.pointSize()+1)
self.setFont(c, font)
self.setSizeHint(0, QtCore.QSize(0, 25))
else:
for c in [0,1]:
self.setBackground(c, QtGui.QBrush(QtGui.QColor(220,220,220)))
font = self.font(c)
font.setBold(True)
#font.setPointSize(font.pointSize()+1)
self.setFont(c, font)
self.setSizeHint(0, QtCore.QSize(0, 20))
def addClicked(self):
"""Called when "add new" button is clicked
The parameter MUST have an 'addNew' method defined.

View File

@ -90,4 +90,4 @@ class CheckTable(QtGui.QWidget):
rowNum = self.rowNames.index(r[0])
for i in range(1, len(r)):
self.rowWidgets[rowNum][i].setChecked(r[i])

View File

@ -127,6 +127,12 @@ class SpinBox(QtGui.QAbstractSpinBox):
self.editingFinished.connect(self.editingFinishedEvent)
self.proxy = SignalProxy(self.sigValueChanging, slot=self.delayedChange)
def event(self, ev):
ret = QtGui.QAbstractSpinBox.event(self, ev)
if ev.type() == QtCore.QEvent.KeyPress and ev.key() == QtCore.Qt.Key_Return:
ret = True ## For some reason, spinbox pretends to ignore return key press
return ret
##lots of config options, just gonna stuff 'em all in here rather than do the get/set crap.
def setOpts(self, **opts):
"""