merged updates from acq4
This commit is contained in:
parent
21dff0525a
commit
2a27687fb2
@ -97,6 +97,6 @@ Miscellaneous Functions
|
|||||||
|
|
||||||
.. autofunction:: pyqtgraph.systemInfo
|
.. autofunction:: pyqtgraph.systemInfo
|
||||||
|
|
||||||
|
.. autofunction:: pyqtgraph.exit
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ CONFIG_OPTIONS = {
|
|||||||
'editorCommand': None, ## command used to invoke code editor from ConsoleWidgets
|
'editorCommand': None, ## command used to invoke code editor from ConsoleWidgets
|
||||||
'useWeave': True, ## Use weave to speed up some operations, if it is available
|
'useWeave': True, ## Use weave to speed up some operations, if it is available
|
||||||
'weaveDebug': False, ## Print full error message if weave compile fails
|
'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 .colormap import *
|
||||||
from .ptime import time
|
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
|
import atexit
|
||||||
def cleanup():
|
def cleanup():
|
||||||
|
if not getConfigOption('exitCleanup'):
|
||||||
|
return
|
||||||
|
|
||||||
ViewBox.quit() ## tell ViewBox that it doesn't need to deregister views anymore.
|
ViewBox.quit() ## tell ViewBox that it doesn't need to deregister views anymore.
|
||||||
|
|
||||||
## Workaround for Qt exit crash:
|
## Workaround for Qt exit crash:
|
||||||
@ -212,6 +224,38 @@ def cleanup():
|
|||||||
atexit.register(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
|
## Convenience functions for command-line use
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ class ConsoleWidget(QtGui.QWidget):
|
|||||||
|
|
||||||
|
|
||||||
def execMulti(self, nextLine):
|
def execMulti(self, nextLine):
|
||||||
self.stdout.write(nextLine+"\n")
|
#self.stdout.write(nextLine+"\n")
|
||||||
if nextLine.strip() != '':
|
if nextLine.strip() != '':
|
||||||
self.multiline += "\n" + nextLine
|
self.multiline += "\n" + nextLine
|
||||||
return
|
return
|
||||||
@ -372,4 +372,4 @@ class ConsoleWidget(QtGui.QWidget):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -521,6 +521,8 @@ class ConnectionItem(GraphicsObject):
|
|||||||
self.target = target
|
self.target = target
|
||||||
self.length = 0
|
self.length = 0
|
||||||
self.hovered = False
|
self.hovered = False
|
||||||
|
self.path = None
|
||||||
|
self.shapePath = None
|
||||||
#self.line = QtGui.QGraphicsLineItem(self)
|
#self.line = QtGui.QGraphicsLineItem(self)
|
||||||
self.source.getViewBox().addItem(self)
|
self.source.getViewBox().addItem(self)
|
||||||
self.updateLine()
|
self.updateLine()
|
||||||
@ -544,13 +546,18 @@ class ConnectionItem(GraphicsObject):
|
|||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
self.prepareGeometryChange()
|
self.prepareGeometryChange()
|
||||||
self.resetTransform()
|
|
||||||
ang = (stop-start).angle(Point(0, 1))
|
self.path = QtGui.QPainterPath()
|
||||||
if ang is None:
|
self.path.moveTo(start)
|
||||||
ang = 0
|
self.path.cubicTo(Point(stop.x(), start.y()), Point(start.x(), stop.y()), Point(stop.x(), stop.y()))
|
||||||
self.rotate(ang)
|
self.shapePath = None
|
||||||
self.setPos(start)
|
#self.resetTransform()
|
||||||
self.length = (start-stop).length()
|
#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.update()
|
||||||
#self.line.setLine(start.x(), start.y(), stop.x(), stop.y())
|
#self.line.setLine(start.x(), start.y(), stop.x(), stop.y())
|
||||||
|
|
||||||
@ -582,12 +589,23 @@ class ConnectionItem(GraphicsObject):
|
|||||||
|
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
#return self.line.boundingRect()
|
return self.shape().boundingRect()
|
||||||
px = self.pixelWidth()
|
##return self.line.boundingRect()
|
||||||
return QtCore.QRectF(-5*px, 0, 10*px, self.length)
|
#px = self.pixelWidth()
|
||||||
|
#return QtCore.QRectF(-5*px, 0, 10*px, self.length)
|
||||||
|
def viewRangeChanged(self):
|
||||||
|
self.shapePath = None
|
||||||
|
self.prepareGeometryChange()
|
||||||
|
|
||||||
#def shape(self):
|
def shape(self):
|
||||||
#return self.line.shape()
|
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):
|
def paint(self, p, *args):
|
||||||
if self.isSelected():
|
if self.isSelected():
|
||||||
@ -598,4 +616,6 @@ class ConnectionItem(GraphicsObject):
|
|||||||
else:
|
else:
|
||||||
p.setPen(fn.mkPen(100, 100, 250, width=1))
|
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])
|
xr = item.dataBounds(0, frac=frac[0], orthoRange=orthoRange[0])
|
||||||
yr = item.dataBounds(1, frac=frac[1], orthoRange=orthoRange[1])
|
yr = item.dataBounds(1, frac=frac[1], orthoRange=orthoRange[1])
|
||||||
pxPad = 0 if not hasattr(item, 'pixelPadding') else item.pixelPadding()
|
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
|
useX = False
|
||||||
xr = (0,0)
|
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
|
useY = False
|
||||||
yr = (0,0)
|
yr = (0,0)
|
||||||
|
|
||||||
|
@ -169,6 +169,13 @@ class EnumColorMapItem(ptree.types.GroupParameter):
|
|||||||
self.fieldName = name
|
self.fieldName = name
|
||||||
vals = opts.get('values', [])
|
vals = opts.get('values', [])
|
||||||
childs = [{'name': v, 'type': 'color'} for v in vals]
|
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,
|
ptree.types.GroupParameter.__init__(self,
|
||||||
name=name, autoIncrementName=True, removable=True, renamable=True,
|
name=name, autoIncrementName=True, removable=True, renamable=True,
|
||||||
children=[
|
children=[
|
||||||
@ -191,8 +198,7 @@ class EnumColorMapItem(ptree.types.GroupParameter):
|
|||||||
colors[:] = default
|
colors[:] = default
|
||||||
|
|
||||||
for v in self.param('Values'):
|
for v in self.param('Values'):
|
||||||
n = v.name()
|
mask = data == v.maskValue
|
||||||
mask = data == n
|
|
||||||
c = np.array(fn.colorTuple(v.value())) / 255.
|
c = np.array(fn.colorTuple(v.value())) / 255.
|
||||||
colors[mask] = c
|
colors[mask] = c
|
||||||
#scaled = np.clip((data-self['Min']) / (self['Max']-self['Min']), 0, 1)
|
#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):
|
def generateMask(self, data):
|
||||||
vals = data[self.fieldName]
|
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):
|
class EnumFilterItem(ptree.types.SimpleParameter):
|
||||||
def __init__(self, name, opts):
|
def __init__(self, name, opts):
|
||||||
self.fieldName = name
|
self.fieldName = name
|
||||||
vals = opts.get('values', [])
|
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,
|
ptree.types.SimpleParameter.__init__(self,
|
||||||
name=name, autoIncrementName=True, type='bool', value=True, removable=True, renamable=True,
|
name=name, autoIncrementName=True, type='bool', value=True, removable=True, renamable=True,
|
||||||
children=childs)
|
children=childs)
|
||||||
@ -110,6 +114,6 @@ class EnumFilterItem(ptree.types.SimpleParameter):
|
|||||||
for c in self:
|
for c in self:
|
||||||
if c.value() is True:
|
if c.value() is True:
|
||||||
continue
|
continue
|
||||||
key = c.name()
|
key = c.maskValue
|
||||||
mask &= vals != key
|
mask &= vals != key
|
||||||
return mask
|
return mask
|
||||||
|
Loading…
Reference in New Issue
Block a user