merged updates from acq4
This commit is contained in:
parent
21dff0525a
commit
2a27687fb2
@ -97,6 +97,6 @@ Miscellaneous Functions
|
||||
|
||||
.. autofunction:: pyqtgraph.systemInfo
|
||||
|
||||
|
||||
.. autofunction:: pyqtgraph.exit
|
||||
|
||||
|
||||
|
@ -54,6 +54,7 @@ CONFIG_OPTIONS = {
|
||||
'editorCommand': None, ## command used to invoke code editor from ConsoleWidgets
|
||||
'useWeave': True, ## Use weave to speed up some operations, if it is available
|
||||
'weaveDebug': False, ## Print full error message if weave compile fails
|
||||
'exitCleanup': True, ## Attempt to work around some exit crash bugs in PyQt and PySide
|
||||
}
|
||||
|
||||
|
||||
@ -190,9 +191,20 @@ from .SignalProxy import *
|
||||
from .colormap import *
|
||||
from .ptime import time
|
||||
|
||||
##############################################################
|
||||
## PyQt and PySide both are prone to crashing on exit.
|
||||
## There are two general approaches to dealing with this:
|
||||
## 1. Install atexit handlers that assist in tearing down to avoid crashes.
|
||||
## This helps, but is never perfect.
|
||||
## 2. Terminate the process before python starts tearing down
|
||||
## This is potentially dangerous
|
||||
|
||||
## Attempts to work around exit crashes:
|
||||
import atexit
|
||||
def cleanup():
|
||||
if not getConfigOption('exitCleanup'):
|
||||
return
|
||||
|
||||
ViewBox.quit() ## tell ViewBox that it doesn't need to deregister views anymore.
|
||||
|
||||
## Workaround for Qt exit crash:
|
||||
@ -212,6 +224,38 @@ def cleanup():
|
||||
atexit.register(cleanup)
|
||||
|
||||
|
||||
## Optional function for exiting immediately (with some manual teardown)
|
||||
def exit():
|
||||
"""
|
||||
Causes python to exit without garbage-collecting any objects, and thus avoids
|
||||
calling object destructor methods. This is a sledgehammer workaround for
|
||||
a variety of bugs in PyQt and Pyside that cause crashes on exit.
|
||||
|
||||
This function does the following in an attempt to 'safely' terminate
|
||||
the process:
|
||||
|
||||
* Invoke atexit callbacks
|
||||
* Close all open file handles
|
||||
* os._exit()
|
||||
|
||||
Note: there is some potential for causing damage with this function if you
|
||||
are using objects that _require_ their destructors to be called (for example,
|
||||
to properly terminate log files, disconnect from devices, etc). Situations
|
||||
like this are probably quite rare, but use at your own risk.
|
||||
"""
|
||||
|
||||
## first disable our own cleanup function; won't be needing it.
|
||||
setConfigOptions(exitCleanup=False)
|
||||
|
||||
## invoke atexit callbacks
|
||||
atexit._run_exitfuncs()
|
||||
|
||||
## close file handles
|
||||
os.closerange(3, 4096) ## just guessing on the maximum descriptor count..
|
||||
|
||||
os._exit(os.EX_OK)
|
||||
|
||||
|
||||
|
||||
## Convenience functions for command-line use
|
||||
|
||||
|
@ -169,7 +169,7 @@ class ConsoleWidget(QtGui.QWidget):
|
||||
|
||||
|
||||
def execMulti(self, nextLine):
|
||||
self.stdout.write(nextLine+"\n")
|
||||
#self.stdout.write(nextLine+"\n")
|
||||
if nextLine.strip() != '':
|
||||
self.multiline += "\n" + nextLine
|
||||
return
|
||||
|
@ -521,6 +521,8 @@ class ConnectionItem(GraphicsObject):
|
||||
self.target = target
|
||||
self.length = 0
|
||||
self.hovered = False
|
||||
self.path = None
|
||||
self.shapePath = None
|
||||
#self.line = QtGui.QGraphicsLineItem(self)
|
||||
self.source.getViewBox().addItem(self)
|
||||
self.updateLine()
|
||||
@ -544,13 +546,18 @@ class ConnectionItem(GraphicsObject):
|
||||
else:
|
||||
return
|
||||
self.prepareGeometryChange()
|
||||
self.resetTransform()
|
||||
ang = (stop-start).angle(Point(0, 1))
|
||||
if ang is None:
|
||||
ang = 0
|
||||
self.rotate(ang)
|
||||
self.setPos(start)
|
||||
self.length = (start-stop).length()
|
||||
|
||||
self.path = QtGui.QPainterPath()
|
||||
self.path.moveTo(start)
|
||||
self.path.cubicTo(Point(stop.x(), start.y()), Point(start.x(), stop.y()), Point(stop.x(), stop.y()))
|
||||
self.shapePath = None
|
||||
#self.resetTransform()
|
||||
#ang = (stop-start).angle(Point(0, 1))
|
||||
#if ang is None:
|
||||
#ang = 0
|
||||
#self.rotate(ang)
|
||||
#self.setPos(start)
|
||||
#self.length = (start-stop).length()
|
||||
self.update()
|
||||
#self.line.setLine(start.x(), start.y(), stop.x(), stop.y())
|
||||
|
||||
@ -582,12 +589,23 @@ class ConnectionItem(GraphicsObject):
|
||||
|
||||
|
||||
def boundingRect(self):
|
||||
#return self.line.boundingRect()
|
||||
px = self.pixelWidth()
|
||||
return QtCore.QRectF(-5*px, 0, 10*px, self.length)
|
||||
return self.shape().boundingRect()
|
||||
##return self.line.boundingRect()
|
||||
#px = self.pixelWidth()
|
||||
#return QtCore.QRectF(-5*px, 0, 10*px, self.length)
|
||||
def viewRangeChanged(self):
|
||||
self.shapePath = None
|
||||
self.prepareGeometryChange()
|
||||
|
||||
#def shape(self):
|
||||
#return self.line.shape()
|
||||
def shape(self):
|
||||
if self.shapePath is None:
|
||||
if self.path is None:
|
||||
return QtGui.QPainterPath()
|
||||
stroker = QtGui.QPainterPathStroker()
|
||||
px = self.pixelWidth()
|
||||
stroker.setWidth(px*8)
|
||||
self.shapePath = stroker.createStroke(self.path)
|
||||
return self.shapePath
|
||||
|
||||
def paint(self, p, *args):
|
||||
if self.isSelected():
|
||||
@ -598,4 +616,6 @@ class ConnectionItem(GraphicsObject):
|
||||
else:
|
||||
p.setPen(fn.mkPen(100, 100, 250, width=1))
|
||||
|
||||
p.drawLine(0, 0, 0, self.length)
|
||||
#p.drawLine(0, 0, 0, self.length)
|
||||
|
||||
p.drawPath(self.path)
|
||||
|
@ -1046,10 +1046,10 @@ class ViewBox(GraphicsWidget):
|
||||
xr = item.dataBounds(0, frac=frac[0], orthoRange=orthoRange[0])
|
||||
yr = item.dataBounds(1, frac=frac[1], orthoRange=orthoRange[1])
|
||||
pxPad = 0 if not hasattr(item, 'pixelPadding') else item.pixelPadding()
|
||||
if xr is None or xr == (None, None):
|
||||
if xr is None or (xr[0] is None and xr[1] is None):
|
||||
useX = False
|
||||
xr = (0,0)
|
||||
if yr is None or yr == (None, None):
|
||||
if yr is None or (yr[0] is None and yr[1] is None):
|
||||
useY = False
|
||||
yr = (0,0)
|
||||
|
||||
|
@ -169,6 +169,13 @@ class EnumColorMapItem(ptree.types.GroupParameter):
|
||||
self.fieldName = name
|
||||
vals = opts.get('values', [])
|
||||
childs = [{'name': v, 'type': 'color'} for v in vals]
|
||||
|
||||
childs = []
|
||||
for v in vals:
|
||||
ch = ptree.Parameter.create(name=str(v), type='color')
|
||||
ch.maskValue = v
|
||||
childs.append(ch)
|
||||
|
||||
ptree.types.GroupParameter.__init__(self,
|
||||
name=name, autoIncrementName=True, removable=True, renamable=True,
|
||||
children=[
|
||||
@ -191,8 +198,7 @@ class EnumColorMapItem(ptree.types.GroupParameter):
|
||||
colors[:] = default
|
||||
|
||||
for v in self.param('Values'):
|
||||
n = v.name()
|
||||
mask = data == n
|
||||
mask = data == v.maskValue
|
||||
c = np.array(fn.colorTuple(v.value())) / 255.
|
||||
colors[mask] = c
|
||||
#scaled = np.clip((data-self['Min']) / (self['Max']-self['Min']), 0, 1)
|
||||
|
@ -92,14 +92,18 @@ class RangeFilterItem(ptree.types.SimpleParameter):
|
||||
|
||||
def generateMask(self, data):
|
||||
vals = data[self.fieldName]
|
||||
return (vals >= mn) & (vals < mx) ## Use inclusive minimum and non-inclusive maximum. This makes it easier to create non-overlapping selections
|
||||
return (vals >= self['Min']) & (vals < self['Max']) ## Use inclusive minimum and non-inclusive maximum. This makes it easier to create non-overlapping selections
|
||||
|
||||
|
||||
class EnumFilterItem(ptree.types.SimpleParameter):
|
||||
def __init__(self, name, opts):
|
||||
self.fieldName = name
|
||||
vals = opts.get('values', [])
|
||||
childs = [{'name': v, 'type': 'bool', 'value': True} for v in vals]
|
||||
childs = []
|
||||
for v in vals:
|
||||
ch = ptree.Parameter.create(name=str(v), type='bool', value=True)
|
||||
ch.maskValue = v
|
||||
childs.append(ch)
|
||||
ptree.types.SimpleParameter.__init__(self,
|
||||
name=name, autoIncrementName=True, type='bool', value=True, removable=True, renamable=True,
|
||||
children=childs)
|
||||
@ -110,6 +114,6 @@ class EnumFilterItem(ptree.types.SimpleParameter):
|
||||
for c in self:
|
||||
if c.value() is True:
|
||||
continue
|
||||
key = c.name()
|
||||
key = c.maskValue
|
||||
mask &= vals != key
|
||||
return mask
|
||||
|
Loading…
Reference in New Issue
Block a user