Updates merged in from ACQ4:
- converted most old-style signals into new-style for PySide compatibility (beware: API changes) - removed ObjectWorkaround, now just using QGraphicsWidget - performance enhancements, particularly in ROI.getArrayRegion - numerous bugfixes
This commit is contained in:
parent
397a1c8a66
commit
7629bca34d
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt4 import QtGui, QtCore
|
||||||
|
import weakref
|
||||||
|
|
||||||
class TickSlider(QtGui.QGraphicsView):
|
class TickSlider(QtGui.QGraphicsView):
|
||||||
def __init__(self, parent=None, orientation='bottom', allowAdd=True, **kargs):
|
def __init__(self, parent=None, orientation='bottom', allowAdd=True, **kargs):
|
||||||
@ -161,6 +161,9 @@ class TickSlider(QtGui.QGraphicsView):
|
|||||||
|
|
||||||
|
|
||||||
class GradientWidget(TickSlider):
|
class GradientWidget(TickSlider):
|
||||||
|
|
||||||
|
sigGradientChanged = QtCore.Signal(object)
|
||||||
|
|
||||||
def __init__(self, *args, **kargs):
|
def __init__(self, *args, **kargs):
|
||||||
TickSlider.__init__(self, *args, **kargs)
|
TickSlider.__init__(self, *args, **kargs)
|
||||||
self.currentTick = None
|
self.currentTick = None
|
||||||
@ -171,8 +174,10 @@ class GradientWidget(TickSlider):
|
|||||||
self.colorDialog = QtGui.QColorDialog()
|
self.colorDialog = QtGui.QColorDialog()
|
||||||
self.colorDialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True)
|
self.colorDialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True)
|
||||||
self.colorDialog.setOption(QtGui.QColorDialog.DontUseNativeDialog, True)
|
self.colorDialog.setOption(QtGui.QColorDialog.DontUseNativeDialog, True)
|
||||||
QtCore.QObject.connect(self.colorDialog, QtCore.SIGNAL('currentColorChanged(const QColor&)'), self.currentColorChanged)
|
#QtCore.QObject.connect(self.colorDialog, QtCore.SIGNAL('currentColorChanged(const QColor&)'), self.currentColorChanged)
|
||||||
QtCore.QObject.connect(self.colorDialog, QtCore.SIGNAL('rejected()'), self.currentColorRejected)
|
self.colorDialog.currentColorChanged.connect(self.currentColorChanged)
|
||||||
|
#QtCore.QObject.connect(self.colorDialog, QtCore.SIGNAL('rejected()'), self.currentColorRejected)
|
||||||
|
self.colorDialog.rejected.connect(self.currentColorRejected)
|
||||||
|
|
||||||
#self.gradient = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(100,0))
|
#self.gradient = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(100,0))
|
||||||
self.scene.addItem(self.gradRect)
|
self.scene.addItem(self.gradRect)
|
||||||
@ -199,7 +204,8 @@ class GradientWidget(TickSlider):
|
|||||||
def updateGradient(self):
|
def updateGradient(self):
|
||||||
self.gradient = self.getGradient()
|
self.gradient = self.getGradient()
|
||||||
self.gradRect.setBrush(QtGui.QBrush(self.gradient))
|
self.gradRect.setBrush(QtGui.QBrush(self.gradient))
|
||||||
self.emit(QtCore.SIGNAL('gradientChanged'), self)
|
#self.emit(QtCore.SIGNAL('gradientChanged'), self)
|
||||||
|
self.sigGradientChanged.emit(self)
|
||||||
|
|
||||||
def setLength(self, newLen):
|
def setLength(self, newLen):
|
||||||
TickSlider.setLength(self, newLen)
|
TickSlider.setLength(self, newLen)
|
||||||
@ -356,7 +362,7 @@ class Tick(QtGui.QGraphicsPolygonItem):
|
|||||||
def __init__(self, view, pos, color, movable=True, scale=10):
|
def __init__(self, view, pos, color, movable=True, scale=10):
|
||||||
#QObjectWorkaround.__init__(self)
|
#QObjectWorkaround.__init__(self)
|
||||||
self.movable = movable
|
self.movable = movable
|
||||||
self.view = view
|
self.view = weakref.ref(view)
|
||||||
self.scale = scale
|
self.scale = scale
|
||||||
self.color = color
|
self.color = color
|
||||||
#self.endTick = endTick
|
#self.endTick = endTick
|
||||||
@ -385,7 +391,7 @@ class Tick(QtGui.QGraphicsPolygonItem):
|
|||||||
newPos.setY(self.pos().y())
|
newPos.setY(self.pos().y())
|
||||||
#newPos.setX(min(max(newPos.x(), 0), 100))
|
#newPos.setX(min(max(newPos.x(), 0), 100))
|
||||||
self.setPos(newPos)
|
self.setPos(newPos)
|
||||||
self.view.tickMoved(self, newPos)
|
self.view().tickMoved(self, newPos)
|
||||||
self.movedSincePress = True
|
self.movedSincePress = True
|
||||||
#self.emit(QtCore.SIGNAL('tickChanged'), self)
|
#self.emit(QtCore.SIGNAL('tickChanged'), self)
|
||||||
ev.accept()
|
ev.accept()
|
||||||
@ -405,7 +411,7 @@ class Tick(QtGui.QGraphicsPolygonItem):
|
|||||||
def mouseReleaseEvent(self, ev):
|
def mouseReleaseEvent(self, ev):
|
||||||
#print self, "release", ev.scenePos()
|
#print self, "release", ev.scenePos()
|
||||||
if not self.movedSincePress:
|
if not self.movedSincePress:
|
||||||
self.view.tickClicked(self, ev)
|
self.view().tickClicked(self, ev)
|
||||||
|
|
||||||
#if ev.button() == QtCore.Qt.LeftButton and ev.scenePos() == self.pressPos:
|
#if ev.button() == QtCore.Qt.LeftButton and ev.scenePos() == self.pressPos:
|
||||||
#color = QtGui.QColorDialog.getColor(self.color, None, "Select Color", QtGui.QColorDialog.ShowAlphaChannel)
|
#color = QtGui.QColorDialog.getColor(self.color, None, "Select Color", QtGui.QColorDialog.ShowAlphaChannel)
|
||||||
|
@ -11,9 +11,15 @@ from PyQt4 import QtCore, QtGui, QtOpenGL, QtSvg
|
|||||||
from Point import *
|
from Point import *
|
||||||
#from vector import *
|
#from vector import *
|
||||||
import sys
|
import sys
|
||||||
|
#import debug
|
||||||
|
|
||||||
class GraphicsView(QtGui.QGraphicsView):
|
class GraphicsView(QtGui.QGraphicsView):
|
||||||
|
|
||||||
|
sigRangeChanged = QtCore.Signal(object, object)
|
||||||
|
sigMouseReleased = QtCore.Signal(object)
|
||||||
|
sigSceneMouseMoved = QtCore.Signal(object)
|
||||||
|
#sigRegionChanged = QtCore.Signal(object)
|
||||||
|
|
||||||
def __init__(self, parent=None, useOpenGL=True):
|
def __init__(self, parent=None, useOpenGL=True):
|
||||||
"""Re-implementation of QGraphicsView that removes scrollbars and allows unambiguous control of the
|
"""Re-implementation of QGraphicsView that removes scrollbars and allows unambiguous control of the
|
||||||
viewed coordinate range. Also automatically creates a QGraphicsScene and a central QGraphicsWidget
|
viewed coordinate range. Also automatically creates a QGraphicsScene and a central QGraphicsWidget
|
||||||
@ -25,6 +31,7 @@ class GraphicsView(QtGui.QGraphicsView):
|
|||||||
|
|
||||||
The view can be panned using the middle mouse button and scaled using the right mouse button if
|
The view can be panned using the middle mouse button and scaled using the right mouse button if
|
||||||
enabled via enableMouse()."""
|
enabled via enableMouse()."""
|
||||||
|
self.closed = False
|
||||||
|
|
||||||
QtGui.QGraphicsView.__init__(self, parent)
|
QtGui.QGraphicsView.__init__(self, parent)
|
||||||
if 'linux' in sys.platform: ## linux has bugs in opengl implementation
|
if 'linux' in sys.platform: ## linux has bugs in opengl implementation
|
||||||
@ -42,7 +49,7 @@ class GraphicsView(QtGui.QGraphicsView):
|
|||||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
palette.setBrush(QtGui.QPalette.Disabled,QtGui.QPalette.Base,brush)
|
palette.setBrush(QtGui.QPalette.Disabled,QtGui.QPalette.Base,brush)
|
||||||
self.setPalette(palette)
|
self.setPalette(palette)
|
||||||
self.setProperty("cursor",QtCore.QVariant(QtCore.Qt.ArrowCursor))
|
#self.setProperty("cursor",QtCore.QVariant(QtCore.Qt.ArrowCursor))
|
||||||
self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||||
self.setFrameShape(QtGui.QFrame.NoFrame)
|
self.setFrameShape(QtGui.QFrame.NoFrame)
|
||||||
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||||
@ -78,6 +85,14 @@ class GraphicsView(QtGui.QGraphicsView):
|
|||||||
self.scaleCenter = False ## should scaling center around view center (True) or mouse click (False)
|
self.scaleCenter = False ## should scaling center around view center (True) or mouse click (False)
|
||||||
self.clickAccepted = False
|
self.clickAccepted = False
|
||||||
|
|
||||||
|
#def paintEvent(self, *args):
|
||||||
|
#prof = debug.Profiler('GraphicsView.paintEvent '+str(id(self)), disabled=True)
|
||||||
|
#QtGui.QGraphicsView.paintEvent(self, *args)
|
||||||
|
#prof.finish()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.closed = True
|
||||||
|
|
||||||
def useOpenGL(self, b=True):
|
def useOpenGL(self, b=True):
|
||||||
if b:
|
if b:
|
||||||
v = QtOpenGL.QGLWidget()
|
v = QtOpenGL.QGLWidget()
|
||||||
@ -112,6 +127,8 @@ class GraphicsView(QtGui.QGraphicsView):
|
|||||||
self.lastButtonReleased = None
|
self.lastButtonReleased = None
|
||||||
|
|
||||||
def resizeEvent(self, ev):
|
def resizeEvent(self, ev):
|
||||||
|
if self.closed:
|
||||||
|
return
|
||||||
if self.autoPixelRange:
|
if self.autoPixelRange:
|
||||||
self.range = QtCore.QRectF(0, 0, self.size().width(), self.size().height())
|
self.range = QtCore.QRectF(0, 0, self.size().width(), self.size().height())
|
||||||
self.setRange(self.range, padding=0, disableAutoPixel=False)
|
self.setRange(self.range, padding=0, disableAutoPixel=False)
|
||||||
@ -148,7 +165,8 @@ class GraphicsView(QtGui.QGraphicsView):
|
|||||||
#print " translate:", st
|
#print " translate:", st
|
||||||
self.setMatrix(m)
|
self.setMatrix(m)
|
||||||
self.currentScale = scale
|
self.currentScale = scale
|
||||||
self.emit(QtCore.SIGNAL('viewChanged'), self.range)
|
#self.emit(QtCore.SIGNAL('viewChanged'), self.range)
|
||||||
|
self.sigRangeChanged.emit(self, self.range)
|
||||||
|
|
||||||
if propagate:
|
if propagate:
|
||||||
for v in self.lockedViewports:
|
for v in self.lockedViewports:
|
||||||
@ -200,6 +218,16 @@ class GraphicsView(QtGui.QGraphicsView):
|
|||||||
#print "New Range:", self.range
|
#print "New Range:", self.range
|
||||||
self.centralWidget.setGeometry(self.range)
|
self.centralWidget.setGeometry(self.range)
|
||||||
self.updateMatrix(propagate)
|
self.updateMatrix(propagate)
|
||||||
|
|
||||||
|
def scaleToImage(self, image):
|
||||||
|
"""Scales such that pixels in image are the same size as screen pixels. This may result in a significant performance increase."""
|
||||||
|
pxSize = image.pixelSize()
|
||||||
|
tl = image.sceneBoundingRect().topLeft()
|
||||||
|
w = self.size().width() * pxSize[0]
|
||||||
|
h = self.size().height() * pxSize[1]
|
||||||
|
range = QtCore.QRectF(tl.x(), tl.y(), w, h)
|
||||||
|
self.setRange(range, padding=0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def lockXRange(self, v1):
|
def lockXRange(self, v1):
|
||||||
@ -299,7 +327,8 @@ class GraphicsView(QtGui.QGraphicsView):
|
|||||||
if not self.mouseEnabled:
|
if not self.mouseEnabled:
|
||||||
return
|
return
|
||||||
#self.mouseTrail.append(Point(self.mapToScene(ev.pos())))
|
#self.mouseTrail.append(Point(self.mapToScene(ev.pos())))
|
||||||
self.emit(QtCore.SIGNAL("mouseReleased"), ev)
|
#self.emit(QtCore.SIGNAL("mouseReleased"), ev)
|
||||||
|
self.sigMouseReleased.emit(ev)
|
||||||
self.lastButtonReleased = ev.button()
|
self.lastButtonReleased = ev.button()
|
||||||
return ## Everything below disabled for now..
|
return ## Everything below disabled for now..
|
||||||
|
|
||||||
@ -320,7 +349,8 @@ class GraphicsView(QtGui.QGraphicsView):
|
|||||||
QtGui.QGraphicsView.mouseMoveEvent(self, ev)
|
QtGui.QGraphicsView.mouseMoveEvent(self, ev)
|
||||||
if not self.mouseEnabled:
|
if not self.mouseEnabled:
|
||||||
return
|
return
|
||||||
self.emit(QtCore.SIGNAL("sceneMouseMoved(PyQt_PyObject)"), self.mapToScene(ev.pos()))
|
#self.emit(QtCore.SIGNAL("sceneMouseMoved(PyQt_PyObject)"), self.mapToScene(ev.pos()))
|
||||||
|
self.sigSceneMouseMoved.emit(self.mapToScene(ev.pos()))
|
||||||
#print "moved. Grabber:", self.scene().mouseGrabberItem()
|
#print "moved. Grabber:", self.scene().mouseGrabberItem()
|
||||||
|
|
||||||
|
|
||||||
@ -333,13 +363,15 @@ class GraphicsView(QtGui.QGraphicsView):
|
|||||||
#if self.yInverted:
|
#if self.yInverted:
|
||||||
#scale[0] = 1. / scale[0]
|
#scale[0] = 1. / scale[0]
|
||||||
self.scale(scale[0], scale[1], center=self.mapToScene(self.mousePressPos))
|
self.scale(scale[0], scale[1], center=self.mapToScene(self.mousePressPos))
|
||||||
self.emit(QtCore.SIGNAL('regionChanged(QRectF)'), self.range)
|
#self.emit(QtCore.SIGNAL('regionChanged(QRectF)'), self.range)
|
||||||
|
self.sigRangeChanged.emit(self, self.range)
|
||||||
|
|
||||||
elif ev.buttons() in [QtCore.Qt.MidButton, QtCore.Qt.LeftButton]: ## Allow panning by left or mid button.
|
elif ev.buttons() in [QtCore.Qt.MidButton, QtCore.Qt.LeftButton]: ## Allow panning by left or mid button.
|
||||||
tr = -delta / self.currentScale
|
tr = -delta / self.currentScale
|
||||||
|
|
||||||
self.translate(tr[0], tr[1])
|
self.translate(tr[0], tr[1])
|
||||||
self.emit(QtCore.SIGNAL('regionChanged(QRectF)'), self.range)
|
#self.emit(QtCore.SIGNAL('regionChanged(QRectF)'), self.range)
|
||||||
|
self.sigRangeChanged.emit(self, self.range)
|
||||||
|
|
||||||
#return ## Everything below disabled for now..
|
#return ## Everything below disabled for now..
|
||||||
|
|
||||||
|
63
ImageView.py
63
ImageView.py
@ -31,6 +31,9 @@ class PlotROI(ROI):
|
|||||||
|
|
||||||
|
|
||||||
class ImageView(QtGui.QWidget):
|
class ImageView(QtGui.QWidget):
|
||||||
|
|
||||||
|
sigTimeChanged = QtCore.Signal(object, object)
|
||||||
|
|
||||||
def __init__(self, parent=None, name="ImageView", *args):
|
def __init__(self, parent=None, name="ImageView", *args):
|
||||||
QtGui.QWidget.__init__(self, parent, *args)
|
QtGui.QWidget.__init__(self, parent, *args)
|
||||||
self.levelMax = 4096
|
self.levelMax = 4096
|
||||||
@ -106,25 +109,38 @@ class ImageView(QtGui.QWidget):
|
|||||||
setattr(self, fn, getattr(self.ui.graphicsView, fn))
|
setattr(self, fn, getattr(self.ui.graphicsView, fn))
|
||||||
|
|
||||||
#QtCore.QObject.connect(self.ui.timeSlider, QtCore.SIGNAL('valueChanged(int)'), self.timeChanged)
|
#QtCore.QObject.connect(self.ui.timeSlider, QtCore.SIGNAL('valueChanged(int)'), self.timeChanged)
|
||||||
self.timeLine.connect(self.timeLine, QtCore.SIGNAL('positionChanged'), self.timeLineChanged)
|
#self.timeLine.connect(self.timeLine, QtCore.SIGNAL('positionChanged'), self.timeLineChanged)
|
||||||
|
self.timeLine.sigPositionChanged.connect(self.timeLineChanged)
|
||||||
#QtCore.QObject.connect(self.ui.whiteSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateImage)
|
#QtCore.QObject.connect(self.ui.whiteSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateImage)
|
||||||
#QtCore.QObject.connect(self.ui.blackSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateImage)
|
#QtCore.QObject.connect(self.ui.blackSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateImage)
|
||||||
QtCore.QObject.connect(self.ui.gradientWidget, QtCore.SIGNAL('gradientChanged'), self.updateImage)
|
#QtCore.QObject.connect(self.ui.gradientWidget, QtCore.SIGNAL('gradientChanged'), self.updateImage)
|
||||||
QtCore.QObject.connect(self.ui.roiBtn, QtCore.SIGNAL('clicked()'), self.roiClicked)
|
self.ui.gradientWidget.sigGradientChanged.connect(self.updateImage)
|
||||||
self.roi.connect(self.roi, QtCore.SIGNAL('regionChanged'), self.roiChanged)
|
#QtCore.QObject.connect(self.ui.roiBtn, QtCore.SIGNAL('clicked()'), self.roiClicked)
|
||||||
QtCore.QObject.connect(self.ui.normBtn, QtCore.SIGNAL('toggled(bool)'), self.normToggled)
|
self.ui.roiBtn.clicked.connect(self.roiClicked)
|
||||||
QtCore.QObject.connect(self.ui.normDivideRadio, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
#self.roi.connect(self.roi, QtCore.SIGNAL('regionChanged'), self.roiChanged)
|
||||||
QtCore.QObject.connect(self.ui.normSubtractRadio, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
self.roi.sigRegionChanged.connect(self.roiChanged)
|
||||||
QtCore.QObject.connect(self.ui.normOffRadio, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
#QtCore.QObject.connect(self.ui.normBtn, QtCore.SIGNAL('toggled(bool)'), self.normToggled)
|
||||||
QtCore.QObject.connect(self.ui.normROICheck, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
self.ui.normBtn.toggled.connect(self.normToggled)
|
||||||
QtCore.QObject.connect(self.ui.normFrameCheck, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
#QtCore.QObject.connect(self.ui.normDivideRadio, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
||||||
QtCore.QObject.connect(self.ui.normTimeRangeCheck, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
self.ui.normDivideRadio.clicked.connect(self.updateNorm)
|
||||||
QtCore.QObject.connect(self.playTimer, QtCore.SIGNAL('timeout()'), self.timeout)
|
#QtCore.QObject.connect(self.ui.normSubtractRadio, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
||||||
|
self.ui.normSubtractRadio.clicked.connect(self.updateNorm)
|
||||||
|
#QtCore.QObject.connect(self.ui.normOffRadio, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
||||||
|
self.ui.normOffRadio.clicked.connect(self.updateNorm)
|
||||||
|
#QtCore.QObject.connect(self.ui.normROICheck, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
||||||
|
self.ui.normROICheck.clicked.connect(self.updateNorm)
|
||||||
|
#QtCore.QObject.connect(self.ui.normFrameCheck, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
||||||
|
self.ui.normFrameCheck.clicked.connect(self.updateNorm)
|
||||||
|
#QtCore.QObject.connect(self.ui.normTimeRangeCheck, QtCore.SIGNAL('clicked()'), self.updateNorm)
|
||||||
|
self.ui.normTimeRangeCheck.clicked.connect(self.updateNorm)
|
||||||
|
#QtCore.QObject.connect(self.playTimer, QtCore.SIGNAL('timeout()'), self.timeout)
|
||||||
|
self.playTimer.timeout.connect(self.timeout)
|
||||||
|
|
||||||
##QtCore.QObject.connect(self.ui.normStartSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateNorm)
|
##QtCore.QObject.connect(self.ui.normStartSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateNorm)
|
||||||
#QtCore.QObject.connect(self.ui.normStopSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateNorm)
|
#QtCore.QObject.connect(self.ui.normStopSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateNorm)
|
||||||
self.normProxy = proxyConnect(self.normRgn, QtCore.SIGNAL('regionChanged'), self.updateNorm)
|
self.normProxy = proxyConnect(None, self.normRgn.sigRegionChanged, self.updateNorm)
|
||||||
self.normRoi.connect(self.normRoi, QtCore.SIGNAL('regionChangeFinished'), self.updateNorm)
|
#self.normRoi.connect(self.normRoi, QtCore.SIGNAL('regionChangeFinished'), self.updateNorm)
|
||||||
|
self.normRoi.sigRegionChangeFinished.connect(self.updateNorm)
|
||||||
|
|
||||||
self.ui.roiPlot.registerPlot(self.name + '_ROI')
|
self.ui.roiPlot.registerPlot(self.name + '_ROI')
|
||||||
|
|
||||||
@ -135,11 +151,16 @@ class ImageView(QtGui.QWidget):
|
|||||||
#self.quit()
|
#self.quit()
|
||||||
#QtGui.QWidget.__dtor__(self)
|
#QtGui.QWidget.__dtor__(self)
|
||||||
|
|
||||||
def quit(self):
|
def close(self):
|
||||||
|
self.ui.graphicsView.close()
|
||||||
|
self.ui.gradientWidget.sigGradientChanged.disconnect(self.updateImage)
|
||||||
self.scene.clear()
|
self.scene.clear()
|
||||||
del self.image
|
del self.image
|
||||||
del self.imageDisp
|
del self.imageDisp
|
||||||
|
#self.image = None
|
||||||
|
#self.imageDisp = None
|
||||||
|
self.ui.roiPlot.close()
|
||||||
|
self.setParent(None)
|
||||||
|
|
||||||
def keyPressEvent(self, ev):
|
def keyPressEvent(self, ev):
|
||||||
if ev.key() == QtCore.Qt.Key_Space:
|
if ev.key() == QtCore.Qt.Key_Space:
|
||||||
@ -319,7 +340,6 @@ class ImageView(QtGui.QWidget):
|
|||||||
axes: {'t':0, 'x':1, 'y':2, 'c':3}; Dictionary indicating the interpretation for each axis.
|
axes: {'t':0, 'x':1, 'y':2, 'c':3}; Dictionary indicating the interpretation for each axis.
|
||||||
This is only needed to override the default guess.
|
This is only needed to override the default guess.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not isinstance(img, np.ndarray):
|
if not isinstance(img, np.ndarray):
|
||||||
raise Exception("Image must be specified as ndarray.")
|
raise Exception("Image must be specified as ndarray.")
|
||||||
self.image = img
|
self.image = img
|
||||||
@ -348,7 +368,7 @@ class ImageView(QtGui.QWidget):
|
|||||||
elif img.ndim == 4:
|
elif img.ndim == 4:
|
||||||
self.axes = {'t': 0, 'x': 1, 'y': 2, 'c': 3}
|
self.axes = {'t': 0, 'x': 1, 'y': 2, 'c': 3}
|
||||||
else:
|
else:
|
||||||
raise Exception("Can not interpret image with dimensions %s" % (str(img)))
|
raise Exception("Can not interpret image with dimensions %s" % (str(img.shape)))
|
||||||
elif isinstance(axes, dict):
|
elif isinstance(axes, dict):
|
||||||
self.axes = axes.copy()
|
self.axes = axes.copy()
|
||||||
elif isinstance(axes, list) or isinstance(axes, tuple):
|
elif isinstance(axes, list) or isinstance(axes, tuple):
|
||||||
@ -441,7 +461,7 @@ class ImageView(QtGui.QWidget):
|
|||||||
#else:
|
#else:
|
||||||
#norm = zeros(image.shape)
|
#norm = zeros(image.shape)
|
||||||
if div:
|
if div:
|
||||||
norm = norm.astype(float32)
|
norm = norm.astype(np.float32)
|
||||||
|
|
||||||
if self.ui.normTimeRangeCheck.isChecked() and image.ndim == 3:
|
if self.ui.normTimeRangeCheck.isChecked() and image.ndim == 3:
|
||||||
(sind, start) = self.timeIndex(self.normRgn.lines[0])
|
(sind, start) = self.timeIndex(self.normRgn.lines[0])
|
||||||
@ -464,7 +484,7 @@ class ImageView(QtGui.QWidget):
|
|||||||
|
|
||||||
if self.ui.normROICheck.isChecked() and image.ndim == 3:
|
if self.ui.normROICheck.isChecked() and image.ndim == 3:
|
||||||
n = self.normRoi.getArrayRegion(norm, self.imageItem, (1, 2)).mean(axis=1).mean(axis=1)
|
n = self.normRoi.getArrayRegion(norm, self.imageItem, (1, 2)).mean(axis=1).mean(axis=1)
|
||||||
n = n[:,newaxis,newaxis]
|
n = n[:,np.newaxis,np.newaxis]
|
||||||
#print start, end, sind, eind
|
#print start, end, sind, eind
|
||||||
if div:
|
if div:
|
||||||
norm /= n
|
norm /= n
|
||||||
@ -483,7 +503,8 @@ class ImageView(QtGui.QWidget):
|
|||||||
self.currentIndex = ind
|
self.currentIndex = ind
|
||||||
self.updateImage()
|
self.updateImage()
|
||||||
#self.timeLine.setPos(time)
|
#self.timeLine.setPos(time)
|
||||||
self.emit(QtCore.SIGNAL('timeChanged'), ind, time)
|
#self.emit(QtCore.SIGNAL('timeChanged'), ind, time)
|
||||||
|
self.sigTimeChanged.emit(ind, time)
|
||||||
|
|
||||||
def updateImage(self):
|
def updateImage(self):
|
||||||
## Redraw image on screen
|
## Redraw image on screen
|
||||||
|
@ -63,4 +63,7 @@ class MultiPlotItem(QtGui.QGraphicsWidget):
|
|||||||
else:
|
else:
|
||||||
raise Exception("Data type %s not (yet?) supported for MultiPlot." % type(data))
|
raise Exception("Data type %s not (yet?) supported for MultiPlot." % type(data))
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
for p in self.plots:
|
||||||
|
p[0].close()
|
||||||
|
|
@ -37,3 +37,7 @@ class MultiPlotWidget(GraphicsView):
|
|||||||
def restoreState(self, state):
|
def restoreState(self, state):
|
||||||
pass
|
pass
|
||||||
#return self.plotItem.restoreState(state)
|
#return self.plotItem.restoreState(state)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.mPlotItem.close()
|
||||||
|
self.setParent(None)
|
@ -1,42 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from PyQt4 import QtGui, QtCore
|
|
||||||
"""For circumventing PyQt's lack of multiple inheritance (just until PySide becomes stable)"""
|
|
||||||
|
|
||||||
|
|
||||||
class Obj(QtCore.QObject):
|
|
||||||
def event(self, ev):
|
|
||||||
self.emit(QtCore.SIGNAL('event'), ev)
|
|
||||||
return QtCore.QObject.event(self, ev)
|
|
||||||
|
|
||||||
class QObjectWorkaround:
|
|
||||||
def __init__(self):
|
|
||||||
self._qObj_ = Obj()
|
|
||||||
self.connect(QtCore.SIGNAL('event'), self.event)
|
|
||||||
def connect(self, *args):
|
|
||||||
if args[0] is self:
|
|
||||||
return QtCore.QObject.connect(self._qObj_, *args[1:])
|
|
||||||
else:
|
|
||||||
return QtCore.QObject.connect(self._qObj_, *args)
|
|
||||||
def disconnect(self, *args):
|
|
||||||
return QtCore.QObject.disconnect(self._qObj_, *args)
|
|
||||||
def emit(self, *args):
|
|
||||||
return QtCore.QObject.emit(self._qObj_, *args)
|
|
||||||
def blockSignals(self, b):
|
|
||||||
return self._qObj_.blockSignals(b)
|
|
||||||
def setProperty(self, prop, val):
|
|
||||||
return self._qObj_.setProperty(prop, val)
|
|
||||||
def property(self, prop):
|
|
||||||
return self._qObj_.property(prop)
|
|
||||||
def event(self, ev):
|
|
||||||
pass
|
|
||||||
|
|
||||||
#class QGraphicsObject(QtGui.QGraphicsItem, QObjectWorkaround):
|
|
||||||
#def __init__(self, *args):
|
|
||||||
#QtGui.QGraphicsItem.__init__(self, *args)
|
|
||||||
#QObjectWorkaround.__init__(self)
|
|
||||||
|
|
||||||
class QGraphicsObject(QtGui.QGraphicsWidget):
|
|
||||||
def shape(self):
|
|
||||||
return QtGui.QGraphicsItem.shape(self)
|
|
||||||
|
|
||||||
#QGraphicsObject = QtGui.QGraphicsObject
|
|
337
PlotItem.py
337
PlotItem.py
@ -25,6 +25,7 @@ from functions import *
|
|||||||
#tryWorkaround(QtCore, QtGui)
|
#tryWorkaround(QtCore, QtGui)
|
||||||
import weakref
|
import weakref
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
#import debug
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from WidgetGroup import *
|
from WidgetGroup import *
|
||||||
@ -40,6 +41,11 @@ except:
|
|||||||
|
|
||||||
|
|
||||||
class PlotItem(QtGui.QGraphicsWidget):
|
class PlotItem(QtGui.QGraphicsWidget):
|
||||||
|
|
||||||
|
sigYRangeChanged = QtCore.Signal(object, object)
|
||||||
|
sigXRangeChanged = QtCore.Signal(object, object)
|
||||||
|
sigRangeChanged = QtCore.Signal(object, object)
|
||||||
|
|
||||||
"""Plot graphics item that can be added to any graphics scene. Implements axis titles, scales, interactive viewbox."""
|
"""Plot graphics item that can be added to any graphics scene. Implements axis titles, scales, interactive viewbox."""
|
||||||
lastFileDir = None
|
lastFileDir = None
|
||||||
managers = {}
|
managers = {}
|
||||||
@ -60,8 +66,10 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
proxy.setWidget(b)
|
proxy.setWidget(b)
|
||||||
proxy.setAcceptHoverEvents(False)
|
proxy.setAcceptHoverEvents(False)
|
||||||
b.setStyleSheet("background-color: #000000; color: #888; font-size: 6pt")
|
b.setStyleSheet("background-color: #000000; color: #888; font-size: 6pt")
|
||||||
QtCore.QObject.connect(self.ctrlBtn, QtCore.SIGNAL('clicked()'), self.ctrlBtnClicked)
|
#QtCore.QObject.connect(self.ctrlBtn, QtCore.SIGNAL('clicked()'), self.ctrlBtnClicked)
|
||||||
QtCore.QObject.connect(self.autoBtn, QtCore.SIGNAL('clicked()'), self.enableAutoScale)
|
self.ctrlBtn.clicked.connect(self.ctrlBtnClicked)
|
||||||
|
#QtCore.QObject.connect(self.autoBtn, QtCore.SIGNAL('clicked()'), self.enableAutoScale)
|
||||||
|
self.autoBtn.clicked.connect(self.enableAutoScale)
|
||||||
|
|
||||||
|
|
||||||
self.layout = QtGui.QGraphicsGridLayout()
|
self.layout = QtGui.QGraphicsGridLayout()
|
||||||
@ -71,11 +79,15 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
self.layout.setVerticalSpacing(0)
|
self.layout.setVerticalSpacing(0)
|
||||||
|
|
||||||
self.vb = ViewBox()
|
self.vb = ViewBox()
|
||||||
QtCore.QObject.connect(self.vb, QtCore.SIGNAL('xRangeChanged'), self.xRangeChanged)
|
#QtCore.QObject.connect(self.vb, QtCore.SIGNAL('xRangeChanged'), self.xRangeChanged)
|
||||||
QtCore.QObject.connect(self.vb, QtCore.SIGNAL('yRangeChanged'), self.yRangeChanged)
|
self.vb.sigXRangeChanged.connect(self.xRangeChanged)
|
||||||
QtCore.QObject.connect(self.vb, QtCore.SIGNAL('rangeChangedManually'), self.enableManualScale)
|
#QtCore.QObject.connect(self.vb, QtCore.SIGNAL('yRangeChanged'), self.yRangeChanged)
|
||||||
|
self.vb.sigYRangeChanged.connect(self.yRangeChanged)
|
||||||
|
#QtCore.QObject.connect(self.vb, QtCore.SIGNAL('rangeChangedManually'), self.enableManualScale)
|
||||||
|
self.vb.sigRangeChangedManually.connect(self.enableManualScale)
|
||||||
|
|
||||||
QtCore.QObject.connect(self.vb, QtCore.SIGNAL('viewChanged'), self.viewChanged)
|
#QtCore.QObject.connect(self.vb, QtCore.SIGNAL('viewChanged'), self.viewChanged)
|
||||||
|
self.vb.sigRangeChanged.connect(self.viewRangeChanged)
|
||||||
|
|
||||||
self.layout.addItem(self.vb, 2, 1)
|
self.layout.addItem(self.vb, 2, 1)
|
||||||
self.alpha = 1.0
|
self.alpha = 1.0
|
||||||
@ -161,53 +173,81 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
self.setAcceptHoverEvents(True)
|
self.setAcceptHoverEvents(True)
|
||||||
|
|
||||||
## Connect control widgets
|
## Connect control widgets
|
||||||
QtCore.QObject.connect(c.xMinText, QtCore.SIGNAL('editingFinished()'), self.setManualXScale)
|
#QtCore.QObject.connect(c.xMinText, QtCore.SIGNAL('editingFinished()'), self.setManualXScale)
|
||||||
QtCore.QObject.connect(c.xMaxText, QtCore.SIGNAL('editingFinished()'), self.setManualXScale)
|
c.xMinText.editingFinished.connect(self.setManualXScale)
|
||||||
QtCore.QObject.connect(c.yMinText, QtCore.SIGNAL('editingFinished()'), self.setManualYScale)
|
#QtCore.QObject.connect(c.xMaxText, QtCore.SIGNAL('editingFinished()'), self.setManualXScale)
|
||||||
QtCore.QObject.connect(c.yMaxText, QtCore.SIGNAL('editingFinished()'), self.setManualYScale)
|
c.xMaxText.editingFinished.connect(self.setManualXScale)
|
||||||
|
#QtCore.QObject.connect(c.yMinText, QtCore.SIGNAL('editingFinished()'), self.setManualYScale)
|
||||||
|
c.yMinText.editingFinished.connect(self.setManualYScale)
|
||||||
|
#QtCore.QObject.connect(c.yMaxText, QtCore.SIGNAL('editingFinished()'), self.setManualYScale)
|
||||||
|
c.yMaxText.editingFinished.connect(self.setManualYScale)
|
||||||
|
|
||||||
QtCore.QObject.connect(c.xManualRadio, QtCore.SIGNAL('clicked()'), self.updateXScale)
|
#QtCore.QObject.connect(c.xManualRadio, QtCore.SIGNAL('clicked()'), self.updateXScale)
|
||||||
QtCore.QObject.connect(c.yManualRadio, QtCore.SIGNAL('clicked()'), self.updateYScale)
|
c.xManualRadio.clicked.connect(lambda: self.updateXScale())
|
||||||
|
#QtCore.QObject.connect(c.yManualRadio, QtCore.SIGNAL('clicked()'), self.updateYScale)
|
||||||
|
c.yManualRadio.clicked.connect(lambda: self.updateYScale())
|
||||||
|
|
||||||
QtCore.QObject.connect(c.xAutoRadio, QtCore.SIGNAL('clicked()'), self.updateXScale)
|
#QtCore.QObject.connect(c.xAutoRadio, QtCore.SIGNAL('clicked()'), self.updateXScale)
|
||||||
QtCore.QObject.connect(c.yAutoRadio, QtCore.SIGNAL('clicked()'), self.updateYScale)
|
c.xAutoRadio.clicked.connect(self.updateXScale)
|
||||||
|
#QtCore.QObject.connect(c.yAutoRadio, QtCore.SIGNAL('clicked()'), self.updateYScale)
|
||||||
|
c.yAutoRadio.clicked.connect(self.updateYScale)
|
||||||
|
|
||||||
QtCore.QObject.connect(c.xAutoPercentSpin, QtCore.SIGNAL('valueChanged(int)'), self.replot)
|
#QtCore.QObject.connect(c.xAutoPercentSpin, QtCore.SIGNAL('valueChanged(int)'), self.replot)
|
||||||
QtCore.QObject.connect(c.yAutoPercentSpin, QtCore.SIGNAL('valueChanged(int)'), self.replot)
|
c.xAutoPercentSpin.valueChanged.connect(self.replot)
|
||||||
|
#QtCore.QObject.connect(c.yAutoPercentSpin, QtCore.SIGNAL('valueChanged(int)'), self.replot)
|
||||||
|
c.yAutoPercentSpin.valueChanged.connect(self.replot)
|
||||||
|
|
||||||
#QtCore.QObject.connect(c.xLogCheck, QtCore.SIGNAL('toggled(bool)'), self.setXLog)
|
#QtCore.QObject.connect(c.xLogCheck, QtCore.SIGNAL('toggled(bool)'), self.setXLog)
|
||||||
#QtCore.QObject.connect(c.yLogCheck, QtCore.SIGNAL('toggled(bool)'), self.setYLog)
|
#QtCore.QObject.connect(c.yLogCheck, QtCore.SIGNAL('toggled(bool)'), self.setYLog)
|
||||||
|
|
||||||
QtCore.QObject.connect(c.alphaGroup, QtCore.SIGNAL('toggled(bool)'), self.updateAlpha)
|
#QtCore.QObject.connect(c.alphaGroup, QtCore.SIGNAL('toggled(bool)'), self.updateAlpha)
|
||||||
QtCore.QObject.connect(c.alphaSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateAlpha)
|
c.alphaGroup.toggled.connect(self.updateAlpha)
|
||||||
QtCore.QObject.connect(c.autoAlphaCheck, QtCore.SIGNAL('toggled(bool)'), self.updateAlpha)
|
#QtCore.QObject.connect(c.alphaSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateAlpha)
|
||||||
|
c.alphaSlider.valueChanged.connect(self.updateAlpha)
|
||||||
|
#QtCore.QObject.connect(c.autoAlphaCheck, QtCore.SIGNAL('toggled(bool)'), self.updateAlpha)
|
||||||
|
c.autoAlphaCheck.toggled.connect(self.updateAlpha)
|
||||||
|
|
||||||
QtCore.QObject.connect(c.gridGroup, QtCore.SIGNAL('toggled(bool)'), self.updateGrid)
|
#QtCore.QObject.connect(c.gridGroup, QtCore.SIGNAL('toggled(bool)'), self.updateGrid)
|
||||||
QtCore.QObject.connect(c.gridAlphaSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateGrid)
|
c.gridGroup.toggled.connect(self.updateGrid)
|
||||||
|
#QtCore.QObject.connect(c.gridAlphaSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateGrid)
|
||||||
|
c.gridAlphaSlider.valueChanged.connect(self.updateGrid)
|
||||||
|
|
||||||
QtCore.QObject.connect(c.powerSpectrumGroup, QtCore.SIGNAL('toggled(bool)'), self.updateSpectrumMode)
|
#QtCore.QObject.connect(c.powerSpectrumGroup, QtCore.SIGNAL('toggled(bool)'), self.updateSpectrumMode)
|
||||||
QtCore.QObject.connect(c.saveSvgBtn, QtCore.SIGNAL('clicked()'), self.saveSvgClicked)
|
c.powerSpectrumGroup.toggled.connect(self.updateSpectrumMode)
|
||||||
QtCore.QObject.connect(c.saveImgBtn, QtCore.SIGNAL('clicked()'), self.saveImgClicked)
|
#QtCore.QObject.connect(c.saveSvgBtn, QtCore.SIGNAL('clicked()'), self.saveSvgClicked)
|
||||||
QtCore.QObject.connect(c.saveCsvBtn, QtCore.SIGNAL('clicked()'), self.saveCsvClicked)
|
c.saveSvgBtn.clicked.connect(self.saveSvgClicked)
|
||||||
|
#QtCore.QObject.connect(c.saveImgBtn, QtCore.SIGNAL('clicked()'), self.saveImgClicked)
|
||||||
|
c.saveImgBtn.clicked.connect(self.saveImgClicked)
|
||||||
|
#QtCore.QObject.connect(c.saveCsvBtn, QtCore.SIGNAL('clicked()'), self.saveCsvClicked)
|
||||||
|
c.saveCsvBtn.clicked.connect(self.saveCsvClicked)
|
||||||
|
|
||||||
#QtCore.QObject.connect(c.gridGroup, QtCore.SIGNAL('toggled(bool)'), self.updateGrid)
|
#QtCore.QObject.connect(c.gridGroup, QtCore.SIGNAL('toggled(bool)'), self.updateGrid)
|
||||||
#QtCore.QObject.connect(c.gridAlphaSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateGrid)
|
#QtCore.QObject.connect(c.gridAlphaSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateGrid)
|
||||||
|
|
||||||
QtCore.QObject.connect(self.ctrl.xLinkCombo, QtCore.SIGNAL('currentIndexChanged(int)'), self.xLinkComboChanged)
|
#QtCore.QObject.connect(self.ctrl.xLinkCombo, QtCore.SIGNAL('currentIndexChanged(int)'), self.xLinkComboChanged)
|
||||||
QtCore.QObject.connect(self.ctrl.yLinkCombo, QtCore.SIGNAL('currentIndexChanged(int)'), self.yLinkComboChanged)
|
self.ctrl.xLinkCombo.currentIndexChanged.connect(self.xLinkComboChanged)
|
||||||
|
#QtCore.QObject.connect(self.ctrl.yLinkCombo, QtCore.SIGNAL('currentIndexChanged(int)'), self.yLinkComboChanged)
|
||||||
|
self.ctrl.yLinkCombo.currentIndexChanged.connect(self.yLinkComboChanged)
|
||||||
|
|
||||||
QtCore.QObject.connect(c.downsampleSpin, QtCore.SIGNAL('valueChanged(int)'), self.updateDownsampling)
|
#QtCore.QObject.connect(c.downsampleSpin, QtCore.SIGNAL('valueChanged(int)'), self.updateDownsampling)
|
||||||
|
c.downsampleSpin.valueChanged.connect(self.updateDownsampling)
|
||||||
|
|
||||||
QtCore.QObject.connect(self.ctrl.avgParamList, QtCore.SIGNAL('itemClicked(QListWidgetItem*)'), self.avgParamListClicked)
|
#QtCore.QObject.connect(self.ctrl.avgParamList, QtCore.SIGNAL('itemClicked(QListWidgetItem*)'), self.avgParamListClicked)
|
||||||
QtCore.QObject.connect(self.ctrl.averageGroup, QtCore.SIGNAL('toggled(bool)'), self.avgToggled)
|
self.ctrl.avgParamList.itemClicked.connect(self.avgParamListClicked)
|
||||||
|
#QtCore.QObject.connect(self.ctrl.averageGroup, QtCore.SIGNAL('toggled(bool)'), self.avgToggled)
|
||||||
|
self.ctrl.averageGroup.toggled.connect(self.avgToggled)
|
||||||
|
|
||||||
#QtCore.QObject.connect(self.ctrl.pointsGroup, QtCore.SIGNAL('toggled(bool)'), self.updatePointMode)
|
#QtCore.QObject.connect(self.ctrl.pointsGroup, QtCore.SIGNAL('toggled(bool)'), self.updatePointMode)
|
||||||
#QtCore.QObject.connect(self.ctrl.autoPointsCheck, QtCore.SIGNAL('toggled(bool)'), self.updatePointMode)
|
#QtCore.QObject.connect(self.ctrl.autoPointsCheck, QtCore.SIGNAL('toggled(bool)'), self.updatePointMode)
|
||||||
|
|
||||||
QtCore.QObject.connect(self.ctrl.maxTracesCheck, QtCore.SIGNAL('toggled(bool)'), self.updateDecimation)
|
#QtCore.QObject.connect(self.ctrl.maxTracesCheck, QtCore.SIGNAL('toggled(bool)'), self.updateDecimation)
|
||||||
QtCore.QObject.connect(self.ctrl.maxTracesSpin, QtCore.SIGNAL('valueChanged(int)'), self.updateDecimation)
|
self.ctrl.maxTracesCheck.toggled.connect(self.updateDecimation)
|
||||||
QtCore.QObject.connect(c.xMouseCheck, QtCore.SIGNAL('toggled(bool)'), self.mouseCheckChanged)
|
#QtCore.QObject.connect(self.ctrl.maxTracesSpin, QtCore.SIGNAL('valueChanged(int)'), self.updateDecimation)
|
||||||
QtCore.QObject.connect(c.yMouseCheck, QtCore.SIGNAL('toggled(bool)'), self.mouseCheckChanged)
|
self.ctrl.maxTracesSpin.valueChanged.connect(self.updateDecimation)
|
||||||
|
#QtCore.QObject.connect(c.xMouseCheck, QtCore.SIGNAL('toggled(bool)'), self.mouseCheckChanged)
|
||||||
|
c.xMouseCheck.toggled.connect(self.mouseCheckChanged)
|
||||||
|
#QtCore.QObject.connect(c.yMouseCheck, QtCore.SIGNAL('toggled(bool)'), self.mouseCheckChanged)
|
||||||
|
c.yMouseCheck.toggled.connect(self.mouseCheckChanged)
|
||||||
|
|
||||||
self.xLinkPlot = None
|
self.xLinkPlot = None
|
||||||
self.yLinkPlot = None
|
self.yLinkPlot = None
|
||||||
@ -236,9 +276,16 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
if len(kargs) > 0:
|
if len(kargs) > 0:
|
||||||
self.plot(**kargs)
|
self.plot(**kargs)
|
||||||
|
|
||||||
|
#def paint(self, *args):
|
||||||
def __del__(self):
|
#prof = debug.Profiler('PlotItem.paint', disabled=True)
|
||||||
|
#QtGui.QGraphicsWidget.paint(self, *args)
|
||||||
|
#prof.finish()
|
||||||
|
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
#print "delete", self
|
||||||
if self.manager is not None:
|
if self.manager is not None:
|
||||||
|
self.manager.sigWidgetListChanged.disconnect(self.updatePlotList)
|
||||||
self.manager.removeWidget(self.name)
|
self.manager.removeWidget(self.name)
|
||||||
|
|
||||||
def registerPlot(self, name):
|
def registerPlot(self, name):
|
||||||
@ -249,7 +296,8 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
PlotItem.managers[win] = PlotWidgetManager()
|
PlotItem.managers[win] = PlotWidgetManager()
|
||||||
self.manager = PlotItem.managers[win]
|
self.manager = PlotItem.managers[win]
|
||||||
self.manager.addWidget(self, name)
|
self.manager.addWidget(self, name)
|
||||||
QtCore.QObject.connect(self.manager, QtCore.SIGNAL('widgetListChanged'), self.updatePlotList)
|
#QtCore.QObject.connect(self.manager, QtCore.SIGNAL('widgetListChanged'), self.updatePlotList)
|
||||||
|
self.manager.sigWidgetListChanged.connect(self.updatePlotList)
|
||||||
self.updatePlotList()
|
self.updatePlotList()
|
||||||
|
|
||||||
def updatePlotList(self):
|
def updatePlotList(self):
|
||||||
@ -269,7 +317,8 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
except:
|
except:
|
||||||
import gc
|
import gc
|
||||||
refs= gc.get_referrers(self)
|
refs= gc.get_referrers(self)
|
||||||
print " error during update. Referrers are:", refs
|
print " error during update of", self
|
||||||
|
print " Referrers are:", refs
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def updateGrid(self, *args):
|
def updateGrid(self, *args):
|
||||||
@ -291,8 +340,9 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def viewChanged(self, *args):
|
def viewRangeChanged(self, vb, range):
|
||||||
self.emit(QtCore.SIGNAL('viewChanged'), *args)
|
#self.emit(QtCore.SIGNAL('viewChanged'), *args)
|
||||||
|
self.sigRangeChanged.emit(self, range)
|
||||||
|
|
||||||
def blockLink(self, b):
|
def blockLink(self, b):
|
||||||
self.linksBlocked = b
|
self.linksBlocked = b
|
||||||
@ -466,7 +516,8 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
#self.setLabel(l, unitPrefix='')
|
#self.setLabel(l, unitPrefix='')
|
||||||
#self.getScale(l).setScale(1.0)
|
#self.getScale(l).setScale(1.0)
|
||||||
|
|
||||||
self.emit(QtCore.SIGNAL('xRangeChanged'), self, range)
|
#self.emit(QtCore.SIGNAL('xRangeChanged'), self, range)
|
||||||
|
self.sigXRangeChanged.emit(self, range)
|
||||||
|
|
||||||
def yRangeChanged(self, _, range):
|
def yRangeChanged(self, _, range):
|
||||||
if any(np.isnan(range)) or any(np.isinf(range)):
|
if any(np.isnan(range)) or any(np.isinf(range)):
|
||||||
@ -484,7 +535,8 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
#else:
|
#else:
|
||||||
#self.setLabel(l, unitPrefix='')
|
#self.setLabel(l, unitPrefix='')
|
||||||
#self.getScale(l).setScale(1.0)
|
#self.getScale(l).setScale(1.0)
|
||||||
self.emit(QtCore.SIGNAL('yRangeChanged'), self, range)
|
#self.emit(QtCore.SIGNAL('yRangeChanged'), self, range)
|
||||||
|
self.sigYRangeChanged.emit(self, range)
|
||||||
|
|
||||||
|
|
||||||
def enableAutoScale(self):
|
def enableAutoScale(self):
|
||||||
@ -568,7 +620,8 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
self.curves.remove(item)
|
self.curves.remove(item)
|
||||||
self.updateDecimation()
|
self.updateDecimation()
|
||||||
self.updateParamList()
|
self.updateParamList()
|
||||||
item.connect(item, QtCore.SIGNAL('plotChanged'), self.plotChanged)
|
#item.connect(item, QtCore.SIGNAL('plotChanged'), self.plotChanged)
|
||||||
|
item.sigPlotChanged.connect(self.plotChanged)
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
for i in self.items[:]:
|
for i in self.items[:]:
|
||||||
@ -644,7 +697,8 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
if self.ctrl.averageGroup.isChecked():
|
if self.ctrl.averageGroup.isChecked():
|
||||||
self.addAvgCurve(c)
|
self.addAvgCurve(c)
|
||||||
|
|
||||||
c.connect(c, QtCore.SIGNAL('plotChanged'), self.plotChanged)
|
#c.connect(c, QtCore.SIGNAL('plotChanged'), self.plotChanged)
|
||||||
|
c.sigPlotChanged.connect(self.plotChanged)
|
||||||
self.plotChanged()
|
self.plotChanged()
|
||||||
|
|
||||||
def plotChanged(self, curve=None):
|
def plotChanged(self, curve=None):
|
||||||
@ -704,60 +758,141 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
self.paramList[p] = (i.checkState() == QtCore.Qt.Checked)
|
self.paramList[p] = (i.checkState() == QtCore.Qt.Checked)
|
||||||
#print "paramList:", self.paramList
|
#print "paramList:", self.paramList
|
||||||
|
|
||||||
|
|
||||||
|
## This is bullshit.
|
||||||
def writeSvg(self, fileName=None):
|
def writeSvg(self, fileName=None):
|
||||||
if fileName is None:
|
if fileName is None:
|
||||||
fileName = QtGui.QFileDialog.getSaveFileName()
|
fileName = QtGui.QFileDialog.getSaveFileName()
|
||||||
|
if isinstance(fileName, tuple):
|
||||||
|
raise Exception("Not implemented yet..")
|
||||||
fileName = str(fileName)
|
fileName = str(fileName)
|
||||||
PlotItem.lastFileDir = os.path.dirname(fileName)
|
PlotItem.lastFileDir = os.path.dirname(fileName)
|
||||||
|
|
||||||
self.svg = QtSvg.QSvgGenerator()
|
rect = self.vb.viewRect()
|
||||||
self.svg.setFileName(fileName)
|
xRange = rect.left(), rect.right()
|
||||||
res = 120.
|
|
||||||
#bounds = self.mapRectToScene(self.boundingRect())
|
|
||||||
view = self.scene().views()[0]
|
|
||||||
bounds = view.viewport().rect()
|
|
||||||
bounds = QtCore.QRectF(0, 0, bounds.width(), bounds.height())
|
|
||||||
|
|
||||||
self.svg.setResolution(res)
|
svg = ""
|
||||||
#self.svg.setSize(QtCore.QSize(self.size().width(), self.size().height()))
|
fh = open(fileName, 'w')
|
||||||
self.svg.setViewBox(bounds)
|
|
||||||
|
dx = max(rect.right(),0) - min(rect.left(),0)
|
||||||
|
ymn = min(rect.top(), rect.bottom())
|
||||||
|
ymx = max(rect.top(), rect.bottom())
|
||||||
|
dy = max(ymx,0) - min(ymn,0)
|
||||||
|
sx = 1.
|
||||||
|
sy = 1.
|
||||||
|
while dx*sx < 10:
|
||||||
|
sx *= 1000
|
||||||
|
while dy*sy < 10:
|
||||||
|
sy *= 1000
|
||||||
|
sy *= -1
|
||||||
|
|
||||||
|
#fh.write('<svg viewBox="%f %f %f %f">\n' % (rect.left()*sx, rect.top()*sx, rect.width()*sy, rect.height()*sy))
|
||||||
|
fh.write('<svg>\n')
|
||||||
|
fh.write('<path fill="none" stroke="#000000" stroke-opacity="0.5" stroke-width="1" d="M%f,0 L%f,0"/>\n' % (rect.left()*sx, rect.right()*sx))
|
||||||
|
fh.write('<path fill="none" stroke="#000000" stroke-opacity="0.5" stroke-width="1" d="M0,%f L0,%f"/>\n' % (rect.top()*sy, rect.bottom()*sy))
|
||||||
|
|
||||||
|
|
||||||
|
for item in self.curves:
|
||||||
|
if isinstance(item, PlotCurveItem):
|
||||||
|
color = colorStr(item.pen.color())
|
||||||
|
opacity = item.pen.color().alpha() / 255.
|
||||||
|
color = color[:6]
|
||||||
|
x, y = item.getData()
|
||||||
|
mask = (x > xRange[0]) * (x < xRange[1])
|
||||||
|
mask[:-1] += mask[1:]
|
||||||
|
m2 = mask.copy()
|
||||||
|
mask[1:] += m2[:-1]
|
||||||
|
x = x[mask]
|
||||||
|
y = y[mask]
|
||||||
|
|
||||||
|
x *= sx
|
||||||
|
y *= sy
|
||||||
|
|
||||||
|
#fh.write('<g fill="none" stroke="#%s" stroke-opacity="1" stroke-width="1">\n' % color)
|
||||||
|
fh.write('<path fill="none" stroke="#%s" stroke-opacity="%f" stroke-width="1" d="M%f,%f ' % (color, opacity, x[0], y[0]))
|
||||||
|
for i in xrange(1, len(x)):
|
||||||
|
fh.write('L%f,%f ' % (x[i], y[i]))
|
||||||
|
|
||||||
|
fh.write('"/>')
|
||||||
|
#fh.write("</g>")
|
||||||
|
for item in self.dataItems:
|
||||||
|
if isinstance(item, ScatterPlotItem):
|
||||||
|
|
||||||
|
pRect = item.boundingRect()
|
||||||
|
vRect = pRect.intersected(rect)
|
||||||
|
|
||||||
|
for point in item.points():
|
||||||
|
pos = point.pos()
|
||||||
|
if not rect.contains(pos):
|
||||||
|
continue
|
||||||
|
color = colorStr(point.brush.color())
|
||||||
|
opacity = point.brush.color().alpha() / 255.
|
||||||
|
color = color[:6]
|
||||||
|
x = pos.x() * sx
|
||||||
|
y = pos.y() * sy
|
||||||
|
|
||||||
|
fh.write('<circle cx="%f" cy="%f" r="1" fill="#%s" stroke="none" fill-opacity="%f"/>\n' % (x, y, color, opacity))
|
||||||
|
#fh.write('<path fill="none" stroke="#%s" stroke-opacity="%f" stroke-width="1" d="M%f,%f ' % (color, opacity, x[0], y[0]))
|
||||||
|
#for i in xrange(1, len(x)):
|
||||||
|
#fh.write('L%f,%f ' % (x[i], y[i]))
|
||||||
|
|
||||||
|
#fh.write('"/>')
|
||||||
|
|
||||||
|
## get list of curves, scatter plots
|
||||||
|
|
||||||
self.svg.setSize(QtCore.QSize(bounds.width(), bounds.height()))
|
|
||||||
|
|
||||||
painter = QtGui.QPainter(self.svg)
|
fh.write("</svg>\n")
|
||||||
#self.scene().render(painter, QtCore.QRectF(), view.mapToScene(bounds).boundingRect())
|
|
||||||
|
|
||||||
#items = self.scene().items()
|
|
||||||
#self.scene().views()[0].drawItems(painter, len(items), items)
|
|
||||||
|
|
||||||
#print view, type(view)
|
|
||||||
view.render(painter, bounds)
|
#def writeSvg(self, fileName=None):
|
||||||
|
#if fileName is None:
|
||||||
|
#fileName = QtGui.QFileDialog.getSaveFileName()
|
||||||
|
#fileName = str(fileName)
|
||||||
|
#PlotItem.lastFileDir = os.path.dirname(fileName)
|
||||||
|
|
||||||
painter.end()
|
#self.svg = QtSvg.QSvgGenerator()
|
||||||
|
#self.svg.setFileName(fileName)
|
||||||
|
#res = 120.
|
||||||
|
#view = self.scene().views()[0]
|
||||||
|
#bounds = view.viewport().rect()
|
||||||
|
#bounds = QtCore.QRectF(0, 0, bounds.width(), bounds.height())
|
||||||
|
|
||||||
## Workaround to set pen widths correctly
|
#self.svg.setResolution(res)
|
||||||
import re
|
#self.svg.setViewBox(bounds)
|
||||||
data = open(fileName).readlines()
|
|
||||||
for i in range(len(data)):
|
#self.svg.setSize(QtCore.QSize(bounds.width(), bounds.height()))
|
||||||
line = data[i]
|
|
||||||
m = re.match(r'(<g .*)stroke-width="1"(.*transform="matrix\(([^\)]+)\)".*)', line)
|
#painter = QtGui.QPainter(self.svg)
|
||||||
if m is not None:
|
#view.render(painter, bounds)
|
||||||
#print "Matched group:", line
|
|
||||||
g = m.groups()
|
#painter.end()
|
||||||
matrix = map(float, g[2].split(','))
|
|
||||||
#print "matrix:", matrix
|
### Workaround to set pen widths correctly
|
||||||
scale = max(abs(matrix[0]), abs(matrix[3]))
|
#import re
|
||||||
if scale == 0 or scale == 1.0:
|
#data = open(fileName).readlines()
|
||||||
continue
|
#for i in range(len(data)):
|
||||||
data[i] = g[0] + ' stroke-width="%0.2g" ' % (1.0/scale) + g[1] + '\n'
|
#line = data[i]
|
||||||
#print "old line:", line
|
#m = re.match(r'(<g .*)stroke-width="1"(.*transform="matrix\(([^\)]+)\)".*)', line)
|
||||||
#print "new line:", data[i]
|
#if m is not None:
|
||||||
open(fileName, 'w').write(''.join(data))
|
##print "Matched group:", line
|
||||||
|
#g = m.groups()
|
||||||
|
#matrix = map(float, g[2].split(','))
|
||||||
|
##print "matrix:", matrix
|
||||||
|
#scale = max(abs(matrix[0]), abs(matrix[3]))
|
||||||
|
#if scale == 0 or scale == 1.0:
|
||||||
|
#continue
|
||||||
|
#data[i] = g[0] + ' stroke-width="%0.2g" ' % (1.0/scale) + g[1] + '\n'
|
||||||
|
##print "old line:", line
|
||||||
|
##print "new line:", data[i]
|
||||||
|
#open(fileName, 'w').write(''.join(data))
|
||||||
|
|
||||||
|
|
||||||
def writeImage(self, fileName=None):
|
def writeImage(self, fileName=None):
|
||||||
if fileName is None:
|
if fileName is None:
|
||||||
fileName = QtGui.QFileDialog.getSaveFileName()
|
fileName = QtGui.QFileDialog.getSaveFileName()
|
||||||
|
if isinstance(fileName, tuple):
|
||||||
|
raise Exception("Not implemented yet..")
|
||||||
fileName = str(fileName)
|
fileName = str(fileName)
|
||||||
PlotItem.lastFileDir = os.path.dirname(fileName)
|
PlotItem.lastFileDir = os.path.dirname(fileName)
|
||||||
self.png = QtGui.QImage(int(self.size().width()), int(self.size().height()), QtGui.QImage.Format_ARGB32)
|
self.png = QtGui.QImage(int(self.size().width()), int(self.size().height()), QtGui.QImage.Format_ARGB32)
|
||||||
@ -997,7 +1132,8 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
if PlotItem.lastFileDir is not None:
|
if PlotItem.lastFileDir is not None:
|
||||||
self.fileDialog.setDirectory(PlotItem.lastFileDir)
|
self.fileDialog.setDirectory(PlotItem.lastFileDir)
|
||||||
self.fileDialog.show()
|
self.fileDialog.show()
|
||||||
QtCore.QObject.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString)'), self.writeSvg)
|
#QtCore.QObject.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString)'), self.writeSvg)
|
||||||
|
self.fileDialog.fileSelected.connect(self.writeSvg)
|
||||||
|
|
||||||
#def svgFileSelected(self, fileName):
|
#def svgFileSelected(self, fileName):
|
||||||
##PlotWidget.lastFileDir = os.path.split(fileName)[0]
|
##PlotWidget.lastFileDir = os.path.split(fileName)[0]
|
||||||
@ -1012,7 +1148,8 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
self.fileDialog.setFileMode(QtGui.QFileDialog.AnyFile)
|
self.fileDialog.setFileMode(QtGui.QFileDialog.AnyFile)
|
||||||
self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
|
self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
|
||||||
self.fileDialog.show()
|
self.fileDialog.show()
|
||||||
QtCore.QObject.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString)'), self.writeImage)
|
#QtCore.QObject.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString)'), self.writeImage)
|
||||||
|
self.fileDialog.fileSelected.connect(self.writeImage)
|
||||||
|
|
||||||
def saveCsvClicked(self):
|
def saveCsvClicked(self):
|
||||||
self.fileDialog = QtGui.QFileDialog()
|
self.fileDialog = QtGui.QFileDialog()
|
||||||
@ -1023,13 +1160,17 @@ class PlotItem(QtGui.QGraphicsWidget):
|
|||||||
self.fileDialog.setFileMode(QtGui.QFileDialog.AnyFile)
|
self.fileDialog.setFileMode(QtGui.QFileDialog.AnyFile)
|
||||||
self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
|
self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
|
||||||
self.fileDialog.show()
|
self.fileDialog.show()
|
||||||
QtCore.QObject.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString)'), self.writeCsv)
|
#QtCore.QObject.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString)'), self.writeCsv)
|
||||||
|
self.fileDialog.fileSelected.connect(self.writeCsv)
|
||||||
#def imgFileSelected(self, fileName):
|
#def imgFileSelected(self, fileName):
|
||||||
##PlotWidget.lastFileDir = os.path.split(fileName)[0]
|
##PlotWidget.lastFileDir = os.path.split(fileName)[0]
|
||||||
#self.writeImage(str(fileName))
|
#self.writeImage(str(fileName))
|
||||||
|
|
||||||
|
|
||||||
class PlotWidgetManager(QtCore.QObject):
|
class PlotWidgetManager(QtCore.QObject):
|
||||||
|
|
||||||
|
sigWidgetListChanged = QtCore.Signal(object)
|
||||||
|
|
||||||
"""Used for managing communication between PlotWidgets"""
|
"""Used for managing communication between PlotWidgets"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
QtCore.QObject.__init__(self)
|
QtCore.QObject.__init__(self)
|
||||||
@ -1037,12 +1178,14 @@ class PlotWidgetManager(QtCore.QObject):
|
|||||||
|
|
||||||
def addWidget(self, w, name):
|
def addWidget(self, w, name):
|
||||||
self.widgets[name] = w
|
self.widgets[name] = w
|
||||||
self.emit(QtCore.SIGNAL('widgetListChanged'), self.widgets.keys())
|
#self.emit(QtCore.SIGNAL('widgetListChanged'), self.widgets.keys())
|
||||||
|
self.sigWidgetListChanged.emit(self.widgets.keys())
|
||||||
|
|
||||||
def removeWidget(self, name):
|
def removeWidget(self, name):
|
||||||
if name in self.widgets:
|
if name in self.widgets:
|
||||||
del self.widgets[name]
|
del self.widgets[name]
|
||||||
self.emit(QtCore.SIGNAL('widgetListChanged'), self.widgets.keys())
|
#self.emit(QtCore.SIGNAL('widgetListChanged'), self.widgets.keys())
|
||||||
|
self.sigWidgetListChanged.emit(self.widgets.keys())
|
||||||
|
|
||||||
|
|
||||||
def listWidgets(self):
|
def listWidgets(self):
|
||||||
@ -1055,21 +1198,29 @@ class PlotWidgetManager(QtCore.QObject):
|
|||||||
return self.widgets[name]
|
return self.widgets[name]
|
||||||
|
|
||||||
def linkX(self, p1, p2):
|
def linkX(self, p1, p2):
|
||||||
QtCore.QObject.connect(p1, QtCore.SIGNAL('xRangeChanged'), p2.linkXChanged)
|
#QtCore.QObject.connect(p1, QtCore.SIGNAL('xRangeChanged'), p2.linkXChanged)
|
||||||
QtCore.QObject.connect(p2, QtCore.SIGNAL('xRangeChanged'), p1.linkXChanged)
|
p1.sigXRangeChanged.connect(p2.linkXChanged)
|
||||||
|
#QtCore.QObject.connect(p2, QtCore.SIGNAL('xRangeChanged'), p1.linkXChanged)
|
||||||
|
p2.sigXRangeChanged.connect(p1.linkXChanged)
|
||||||
p1.linkXChanged(p2)
|
p1.linkXChanged(p2)
|
||||||
#p2.setManualXScale()
|
#p2.setManualXScale()
|
||||||
|
|
||||||
def unlinkX(self, p1, p2):
|
def unlinkX(self, p1, p2):
|
||||||
QtCore.QObject.disconnect(p1, QtCore.SIGNAL('xRangeChanged'), p2.linkXChanged)
|
#QtCore.QObject.disconnect(p1, QtCore.SIGNAL('xRangeChanged'), p2.linkXChanged)
|
||||||
QtCore.QObject.disconnect(p2, QtCore.SIGNAL('xRangeChanged'), p1.linkXChanged)
|
p1.sigXRangeChanged.disconnect(p2.linkXChanged)
|
||||||
|
#QtCore.QObject.disconnect(p2, QtCore.SIGNAL('xRangeChanged'), p1.linkXChanged)
|
||||||
|
p2.sigXRangeChanged.disconnect(p1.linkXChanged)
|
||||||
|
|
||||||
def linkY(self, p1, p2):
|
def linkY(self, p1, p2):
|
||||||
QtCore.QObject.connect(p1, QtCore.SIGNAL('yRangeChanged'), p2.linkYChanged)
|
#QtCore.QObject.connect(p1, QtCore.SIGNAL('yRangeChanged'), p2.linkYChanged)
|
||||||
QtCore.QObject.connect(p2, QtCore.SIGNAL('yRangeChanged'), p1.linkYChanged)
|
p1.sigYRangeChanged.connect(p2.linkYChanged)
|
||||||
|
#QtCore.QObject.connect(p2, QtCore.SIGNAL('yRangeChanged'), p1.linkYChanged)
|
||||||
|
p2.sigYRangeChanged.connect(p1.linkYChanged)
|
||||||
p1.linkYChanged(p2)
|
p1.linkYChanged(p2)
|
||||||
#p2.setManualYScale()
|
#p2.setManualYScale()
|
||||||
|
|
||||||
def unlinkY(self, p1, p2):
|
def unlinkY(self, p1, p2):
|
||||||
QtCore.QObject.disconnect(p1, QtCore.SIGNAL('yRangeChanged'), p2.linkYChanged)
|
#QtCore.QObject.disconnect(p1, QtCore.SIGNAL('yRangeChanged'), p2.linkYChanged)
|
||||||
QtCore.QObject.disconnect(p2, QtCore.SIGNAL('yRangeChanged'), p1.linkYChanged)
|
p1.sigYRangeChanged.disconnect(p2.linkYChanged)
|
||||||
|
#QtCore.QObject.disconnect(p2, QtCore.SIGNAL('yRangeChanged'), p1.linkYChanged)
|
||||||
|
p2.sigYRangeChanged.disconnect(p1.linkYChanged)
|
||||||
|
@ -10,6 +10,9 @@ from PlotItem import *
|
|||||||
import exceptions
|
import exceptions
|
||||||
|
|
||||||
class PlotWidget(GraphicsView):
|
class PlotWidget(GraphicsView):
|
||||||
|
|
||||||
|
sigRangeChanged = QtCore.Signal(object, object)
|
||||||
|
|
||||||
"""Widget implementing a graphicsView with a single PlotItem inside."""
|
"""Widget implementing a graphicsView with a single PlotItem inside."""
|
||||||
def __init__(self, parent=None, **kargs):
|
def __init__(self, parent=None, **kargs):
|
||||||
GraphicsView.__init__(self, parent)
|
GraphicsView.__init__(self, parent)
|
||||||
@ -20,17 +23,23 @@ class PlotWidget(GraphicsView):
|
|||||||
## Explicitly wrap methods from plotItem
|
## Explicitly wrap methods from plotItem
|
||||||
for m in ['addItem', 'removeItem', 'autoRange', 'clear', 'setXRange', 'setYRange']:
|
for m in ['addItem', 'removeItem', 'autoRange', 'clear', 'setXRange', 'setYRange']:
|
||||||
setattr(self, m, getattr(self.plotItem, m))
|
setattr(self, m, getattr(self.plotItem, m))
|
||||||
QtCore.QObject.connect(self.plotItem, QtCore.SIGNAL('viewChanged'), self.viewChanged)
|
#QtCore.QObject.connect(self.plotItem, QtCore.SIGNAL('viewChanged'), self.viewChanged)
|
||||||
|
self.plotItem.sigRangeChanged.connect(self.viewRangeChanged)
|
||||||
|
|
||||||
#def __dtor__(self):
|
#def __dtor__(self):
|
||||||
##print "Called plotWidget sip destructor"
|
##print "Called plotWidget sip destructor"
|
||||||
#self.quit()
|
#self.quit()
|
||||||
|
|
||||||
|
|
||||||
def quit(self):
|
#def quit(self):
|
||||||
self.plotItem.clear()
|
|
||||||
self.scene().clear()
|
def close(self):
|
||||||
|
self.plotItem.close()
|
||||||
|
self.plotItem = None
|
||||||
|
#self.scene().clear()
|
||||||
|
#self.mPlotItem.close()
|
||||||
|
self.setParent(None)
|
||||||
|
|
||||||
def __getattr__(self, attr): ## implicitly wrap methods from plotItem
|
def __getattr__(self, attr): ## implicitly wrap methods from plotItem
|
||||||
if hasattr(self.plotItem, attr):
|
if hasattr(self.plotItem, attr):
|
||||||
m = getattr(self.plotItem, attr)
|
m = getattr(self.plotItem, attr)
|
||||||
@ -38,8 +47,9 @@ class PlotWidget(GraphicsView):
|
|||||||
return m
|
return m
|
||||||
raise exceptions.NameError(attr)
|
raise exceptions.NameError(attr)
|
||||||
|
|
||||||
def viewChanged(self, *args):
|
def viewRangeChanged(self, view, range):
|
||||||
self.emit(QtCore.SIGNAL('viewChanged'), *args)
|
#self.emit(QtCore.SIGNAL('viewChanged'), *args)
|
||||||
|
self.sigRangeChanged.emit(self, range)
|
||||||
|
|
||||||
def widgetGroupInterface(self):
|
def widgetGroupInterface(self):
|
||||||
return (None, PlotWidget.saveState, PlotWidget.restoreState)
|
return (None, PlotWidget.saveState, PlotWidget.restoreState)
|
||||||
|
3
Point.py
3
Point.py
@ -34,6 +34,9 @@ class Point(QtCore.QPointF):
|
|||||||
return
|
return
|
||||||
QtCore.QPointF.__init__(self, *args)
|
QtCore.QPointF.__init__(self, *args)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return 2
|
||||||
|
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
return (Point, (self.x(), self.y()))
|
return (Point, (self.x(), self.y()))
|
||||||
|
|
||||||
|
@ -2,14 +2,6 @@
|
|||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
from ptime import time
|
from ptime import time
|
||||||
|
|
||||||
def proxyConnect(source, signal, slot, delay=0.3):
|
|
||||||
"""Connect a signal to a slot with delay. Returns the SignalProxy
|
|
||||||
object that was created. Be sure to store this object so it is not
|
|
||||||
garbage-collected immediately."""
|
|
||||||
sp = SignalProxy(source, signal, delay)
|
|
||||||
sp.connect(sp, signal, slot)
|
|
||||||
return sp
|
|
||||||
|
|
||||||
class SignalProxy(QtCore.QObject):
|
class SignalProxy(QtCore.QObject):
|
||||||
"""Object which collects rapid-fire signals and condenses them
|
"""Object which collects rapid-fire signals and condenses them
|
||||||
into a single signal. Used, for example, to prevent a SpinBox
|
into a single signal. Used, for example, to prevent a SpinBox
|
||||||
@ -17,53 +9,70 @@ class SignalProxy(QtCore.QObject):
|
|||||||
over it."""
|
over it."""
|
||||||
|
|
||||||
def __init__(self, source, signal, delay=0.3):
|
def __init__(self, source, signal, delay=0.3):
|
||||||
|
"""Initialization arguments:
|
||||||
|
source - Any QObject that will emit signal, or None if signal is new style
|
||||||
|
signal - Output of QtCore.SIGNAL(...), or obj.signal for new style
|
||||||
|
delay - Time (in seconds) to wait for signals to stop before emitting (default 0.3s)"""
|
||||||
|
|
||||||
QtCore.QObject.__init__(self)
|
QtCore.QObject.__init__(self)
|
||||||
source.connect(source, signal, self.signal)
|
if source is None:
|
||||||
|
signal.connect(self.signalReceived)
|
||||||
|
self.signal = QtCore.SIGNAL('signal')
|
||||||
|
else:
|
||||||
|
source.connect(source, signal, self.signalReceived)
|
||||||
|
self.signal = signal
|
||||||
self.delay = delay
|
self.delay = delay
|
||||||
self.waitUntil = 0
|
|
||||||
self.args = None
|
self.args = None
|
||||||
self.timers = 0
|
self.timer = QtCore.QTimer()
|
||||||
self.signal = signal
|
self.timer.timeout.connect(self.flush)
|
||||||
self.block = False
|
self.block = False
|
||||||
|
|
||||||
def setDelay(self, delay):
|
def setDelay(self, delay):
|
||||||
self.delay = delay
|
self.delay = delay
|
||||||
|
|
||||||
|
def signalReceived(self, *args):
|
||||||
|
"""Received signal. Cancel previous timer and store args to be forwarded later."""
|
||||||
|
if self.block:
|
||||||
|
return
|
||||||
|
self.args = args
|
||||||
|
self.timer.stop()
|
||||||
|
self.timer.start((self.delay*1000)+1)
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
"""If there is a signal queued up, send it now."""
|
"""If there is a signal queued up, send it now."""
|
||||||
if self.args is None or self.block:
|
if self.args is None or self.block:
|
||||||
return False
|
return False
|
||||||
if self.block:
|
|
||||||
return
|
|
||||||
self.emit(self.signal, *self.args)
|
self.emit(self.signal, *self.args)
|
||||||
self.args = None
|
self.args = None
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def signal(self, *args):
|
|
||||||
"""Received signal, queue to be forwarded later."""
|
|
||||||
if self.block:
|
|
||||||
return
|
|
||||||
self.waitUntil = time() + self.delay
|
|
||||||
self.args = args
|
|
||||||
self.timers += 1
|
|
||||||
QtCore.QTimer.singleShot((self.delay*1000)+1, self.tryEmit)
|
|
||||||
|
|
||||||
def tryEmit(self):
|
|
||||||
"""Emit signal if it has been long enougn since receiving the last signal."""
|
|
||||||
if self.args is None or self.block:
|
|
||||||
return False
|
|
||||||
self.timers -= 1
|
|
||||||
t = time()
|
|
||||||
if t >= self.waitUntil:
|
|
||||||
return self.flush()
|
|
||||||
else:
|
|
||||||
if self.timers == 0:
|
|
||||||
self.timers += 1
|
|
||||||
QtCore.QTimer.singleShot((self.waitUntil - t) * 1000, self.tryEmit)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
self.block = True
|
self.block = True
|
||||||
|
|
||||||
|
|
||||||
|
def proxyConnect(source, signal, slot, delay=0.3):
|
||||||
|
"""Connect a signal to a slot with delay. Returns the SignalProxy
|
||||||
|
object that was created. Be sure to store this object so it is not
|
||||||
|
garbage-collected immediately."""
|
||||||
|
sp = SignalProxy(source, signal, delay)
|
||||||
|
if source is None:
|
||||||
|
sp.connect(sp, QtCore.SIGNAL('signal'), slot)
|
||||||
|
else:
|
||||||
|
sp.connect(sp, signal, slot)
|
||||||
|
return sp
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from PyQt4 import QtGui
|
||||||
|
app = QtGui.QApplication([])
|
||||||
|
win = QtGui.QMainWindow()
|
||||||
|
spin = QtGui.QSpinBox()
|
||||||
|
win.setCentralWidget(spin)
|
||||||
|
win.show()
|
||||||
|
|
||||||
|
def fn(*args):
|
||||||
|
print "Got signal:", args
|
||||||
|
|
||||||
|
proxy = proxyConnect(spin, QtCore.SIGNAL('valueChanged(int)'), fn)
|
||||||
|
|
||||||
|
|
@ -3,17 +3,16 @@
|
|||||||
import sys, os
|
import sys, os
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
from pyqtgraph.GraphicsView import *
|
|
||||||
from pyqtgraph.graphicsItems import *
|
|
||||||
from numpy import random
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
from scipy.ndimage import *
|
import numpy as np
|
||||||
|
import pyqtgraph as pg
|
||||||
|
|
||||||
app = QtGui.QApplication([])
|
app = QtGui.QApplication([])
|
||||||
|
|
||||||
## Create window with GraphicsView widget
|
## Create window with GraphicsView widget
|
||||||
win = QtGui.QMainWindow()
|
win = QtGui.QMainWindow()
|
||||||
view = GraphicsView()
|
view = pg.GraphicsView()
|
||||||
#view.useOpenGL(True)
|
#view.useOpenGL(True)
|
||||||
win.setCentralWidget(view)
|
win.setCentralWidget(view)
|
||||||
win.show()
|
win.show()
|
||||||
@ -25,26 +24,29 @@ view.enableMouse()
|
|||||||
view.setAspectLocked(True)
|
view.setAspectLocked(True)
|
||||||
|
|
||||||
## Create image item
|
## Create image item
|
||||||
img = ImageItem()
|
img = pg.ImageItem()
|
||||||
view.scene().addItem(img)
|
view.scene().addItem(img)
|
||||||
|
|
||||||
## Set initial view bounds
|
## Set initial view bounds
|
||||||
view.setRange(QtCore.QRectF(0, 0, 200, 200))
|
view.setRange(QtCore.QRectF(0, 0, 200, 200))
|
||||||
|
|
||||||
|
## Create random image
|
||||||
|
data = np.random.normal(size=(50, 200, 200))
|
||||||
|
i = 0
|
||||||
|
|
||||||
def updateData():
|
def updateData():
|
||||||
global img
|
global img, data, i
|
||||||
## Create random image
|
|
||||||
data = random.random((200, 200))
|
|
||||||
|
|
||||||
## Display the data
|
## Display the data
|
||||||
img.updateImage(data)
|
img.updateImage(data[i])
|
||||||
|
i = (i+1) % data.shape[0]
|
||||||
|
|
||||||
|
|
||||||
# update image data every 20ms (or so)
|
# update image data every 20ms (or so)
|
||||||
t = QtCore.QTimer()
|
t = QtCore.QTimer()
|
||||||
QtCore.QObject.connect(t, QtCore.SIGNAL('timeout()'), updateData)
|
t.timeout.connect(updateData)
|
||||||
t.start(20)
|
t.start(20)
|
||||||
|
|
||||||
|
## Start Qt event loop unless running in interactive mode.
|
||||||
|
if sys.flags.interactive != 1:
|
||||||
app.exec_()
|
app.exec_()
|
||||||
|
@ -3,24 +3,25 @@
|
|||||||
import sys, os
|
import sys, os
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
from pyqtgraph.ImageView import *
|
|
||||||
from numpy import random, linspace
|
import numpy as np
|
||||||
|
import scipy
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
from scipy.ndimage import *
|
import pyqtgraph as pg
|
||||||
|
|
||||||
app = QtGui.QApplication([])
|
app = QtGui.QApplication([])
|
||||||
|
|
||||||
## Create window with ImageView widget
|
## Create window with ImageView widget
|
||||||
win = QtGui.QMainWindow()
|
win = QtGui.QMainWindow()
|
||||||
imv = ImageView()
|
imv = pg.ImageView()
|
||||||
win.setCentralWidget(imv)
|
win.setCentralWidget(imv)
|
||||||
win.show()
|
win.show()
|
||||||
|
|
||||||
## Create random 3D data set
|
## Create random 3D data set with noisy signals
|
||||||
img = gaussian_filter(random.normal(size=(200, 200)), (5, 5)) * 20 + 100
|
img = scipy.ndimage.gaussian_filter(np.random.normal(size=(200, 200)), (5, 5)) * 20 + 100
|
||||||
img = img[newaxis,:,:]
|
img = img[np.newaxis,:,:]
|
||||||
decay = exp(-linspace(0,0.3,100))[:,newaxis,newaxis]
|
decay = np.exp(-np.linspace(0,0.3,100))[:,np.newaxis,np.newaxis]
|
||||||
data = random.normal(size=(100, 200, 200))
|
data = np.random.normal(size=(100, 200, 200))
|
||||||
data += img * decay
|
data += img * decay
|
||||||
|
|
||||||
#for i in range(data.shape[0]):
|
#for i in range(data.shape[0]):
|
||||||
@ -28,16 +29,18 @@ data += img * decay
|
|||||||
data += 2
|
data += 2
|
||||||
|
|
||||||
## Add time-varying signal
|
## Add time-varying signal
|
||||||
sig = zeros(data.shape[0])
|
sig = np.zeros(data.shape[0])
|
||||||
sig[30:] += exp(-linspace(1,10, 70))
|
sig[30:] += np.exp(-np.linspace(1,10, 70))
|
||||||
sig[40:] += exp(-linspace(1,10, 60))
|
sig[40:] += np.exp(-np.linspace(1,10, 60))
|
||||||
sig[70:] += exp(-linspace(1,10, 30))
|
sig[70:] += np.exp(-np.linspace(1,10, 30))
|
||||||
|
|
||||||
sig = sig[:,newaxis,newaxis] * 3
|
sig = sig[:,np.newaxis,np.newaxis] * 3
|
||||||
data[:,50:60,50:60] += sig
|
data[:,50:60,50:60] += sig
|
||||||
|
|
||||||
|
|
||||||
## Display the data
|
## Display the data
|
||||||
imv.setImage(data, xvals=linspace(1., 3., data.shape[0]))
|
imv.setImage(data, xvals=np.linspace(1., 3., data.shape[0]))
|
||||||
|
|
||||||
app.exec_()
|
## Start Qt event loop unless running in interactive mode.
|
||||||
|
if sys.flags.interactive != 1:
|
||||||
|
app.exec_()
|
||||||
|
@ -4,14 +4,16 @@
|
|||||||
import sys, os
|
import sys, os
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
|
|
||||||
from scipy import random
|
from scipy import random
|
||||||
from numpy import linspace
|
from numpy import linspace
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt4 import QtGui, QtCore
|
||||||
from pyqtgraph.MultiPlotWidget import *
|
import pyqtgraph as pg
|
||||||
|
from pyqtgraph.MultiPlotWidget import MultiPlotWidget
|
||||||
try:
|
try:
|
||||||
from metaarray import *
|
from metaarray import *
|
||||||
except:
|
except:
|
||||||
print "MultiPlot is only used with MetaArray for now (and you do not have the metaarray module)"
|
print "MultiPlot is only used with MetaArray for now (and you do not have the metaarray package)"
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
app = QtGui.QApplication([])
|
app = QtGui.QApplication([])
|
||||||
@ -23,4 +25,7 @@ mw.show()
|
|||||||
ma = MetaArray(random.random((3, 1000)), info=[{'name': 'Signal', 'cols': [{'name': 'Col1'}, {'name': 'Col2'}, {'name': 'Col3'}]}, {'name': 'Time', 'vals': linspace(0., 1., 1000)}])
|
ma = MetaArray(random.random((3, 1000)), info=[{'name': 'Signal', 'cols': [{'name': 'Col1'}, {'name': 'Col2'}, {'name': 'Col3'}]}, {'name': 'Time', 'vals': linspace(0., 1., 1000)}])
|
||||||
pw.plot(ma)
|
pw.plot(ma)
|
||||||
|
|
||||||
app.exec_()
|
## Start Qt event loop unless running in interactive mode.
|
||||||
|
if sys.flags.interactive != 1:
|
||||||
|
app.exec_()
|
||||||
|
|
||||||
|
@ -4,11 +4,10 @@
|
|||||||
import sys, os
|
import sys, os
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
from scipy import random
|
|
||||||
from PyQt4 import QtGui, QtCore
|
|
||||||
from pyqtgraph.PlotWidget import *
|
|
||||||
from pyqtgraph.graphicsItems import *
|
|
||||||
|
|
||||||
|
from PyQt4 import QtGui, QtCore
|
||||||
|
import numpy as np
|
||||||
|
import pyqtgraph as pg
|
||||||
|
|
||||||
app = QtGui.QApplication([])
|
app = QtGui.QApplication([])
|
||||||
mw = QtGui.QMainWindow()
|
mw = QtGui.QMainWindow()
|
||||||
@ -17,77 +16,56 @@ mw.setCentralWidget(cw)
|
|||||||
l = QtGui.QVBoxLayout()
|
l = QtGui.QVBoxLayout()
|
||||||
cw.setLayout(l)
|
cw.setLayout(l)
|
||||||
|
|
||||||
pw = PlotWidget()
|
pw = pg.PlotWidget(name='Plot1') ## giving the plots names allows us to link their axes together
|
||||||
l.addWidget(pw)
|
l.addWidget(pw)
|
||||||
pw2 = PlotWidget()
|
pw2 = pg.PlotWidget(name='Plot2')
|
||||||
l.addWidget(pw2)
|
l.addWidget(pw2)
|
||||||
pw3 = PlotWidget()
|
pw3 = pg.PlotWidget()
|
||||||
l.addWidget(pw3)
|
l.addWidget(pw3)
|
||||||
|
|
||||||
pw.registerPlot('Plot1')
|
mw.show()
|
||||||
pw2.registerPlot('Plot2')
|
|
||||||
|
|
||||||
#p1 = PlotCurveItem()
|
## Create an empty plot curve to be filled later, set its pen
|
||||||
#pw.addItem(p1)
|
|
||||||
p1 = pw.plot()
|
p1 = pw.plot()
|
||||||
|
p1.setPen((200,200,100))
|
||||||
|
|
||||||
|
## Add in some extra graphics
|
||||||
rect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, 0, 1, 1))
|
rect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, 0, 1, 1))
|
||||||
rect.setPen(QtGui.QPen(QtGui.QColor(100, 200, 100)))
|
rect.setPen(QtGui.QPen(QtGui.QColor(100, 200, 100)))
|
||||||
pw.addItem(rect)
|
pw.addItem(rect)
|
||||||
|
|
||||||
#pen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(255, 255, 255, 50)), 5)
|
|
||||||
#pen.setCosmetic(True)
|
|
||||||
#pen.setJoinStyle(QtCore.Qt.MiterJoin)
|
|
||||||
#p1.setShadowPen(pen)
|
|
||||||
p1.setPen(QtGui.QPen(QtGui.QColor(255, 255, 255)))
|
|
||||||
|
|
||||||
#l1 = QtGui.QGraphicsLineItem(0, 2, 2, 3)
|
|
||||||
#l1.setPen(QtGui.QPen(QtGui.QColor(255,0,0)))
|
|
||||||
|
|
||||||
#l2 = InfiniteLine(pw2, 1.5, 90, movable=True)
|
|
||||||
#
|
|
||||||
#lr1 = LinearRegionItem(pw2, 'vertical', [1.1, 1.3])
|
|
||||||
#pw2.addItem(lr1)
|
|
||||||
#lr2 = LinearRegionItem(pw2, 'horizontal', [50, 100])
|
|
||||||
#pw2.addItem(lr2)
|
|
||||||
|
|
||||||
|
|
||||||
#l3 = InfiniteLine(pw, [1.5, 1.5], 45)
|
|
||||||
#pw.addItem(l1)
|
|
||||||
#pw2.addItem(l2)
|
|
||||||
#pw.addItem(l3)
|
|
||||||
|
|
||||||
pw3.plot(array([100000]*100))
|
|
||||||
|
|
||||||
|
|
||||||
mw.show()
|
|
||||||
|
|
||||||
|
|
||||||
def rand(n):
|
def rand(n):
|
||||||
data = random.random(n)
|
data = np.random.random(n)
|
||||||
data[int(n*0.1):int(n*0.13)] += .5
|
data[int(n*0.1):int(n*0.13)] += .5
|
||||||
data[int(n*0.18)] += 2
|
data[int(n*0.18)] += 2
|
||||||
data[int(n*0.1):int(n*0.13)] *= 5
|
data[int(n*0.1):int(n*0.13)] *= 5
|
||||||
data[int(n*0.18)] *= 20
|
data[int(n*0.18)] *= 20
|
||||||
return data, arange(n, n+len(data)) / float(n)
|
data *= 1e-12
|
||||||
|
return data, np.arange(n, n+len(data)) / float(n)
|
||||||
|
|
||||||
|
|
||||||
def updateData():
|
def updateData():
|
||||||
yd, xd = rand(10000)
|
yd, xd = rand(10000)
|
||||||
p1.updateData(yd, x=xd)
|
p1.updateData(yd, x=xd)
|
||||||
|
|
||||||
yd, xd = rand(10000)
|
## Start a timer to rapidly update the plot in pw
|
||||||
updateData()
|
|
||||||
pw.autoRange()
|
|
||||||
|
|
||||||
t = QtCore.QTimer()
|
t = QtCore.QTimer()
|
||||||
|
t.timeout.connect(updateData)
|
||||||
QtCore.QObject.connect(t, QtCore.SIGNAL('timeout()'), updateData)
|
|
||||||
t.start(50)
|
t.start(50)
|
||||||
|
|
||||||
|
## Multiple parameterized plots--we can autogenerate averages for these.
|
||||||
for i in range(0, 5):
|
for i in range(0, 5):
|
||||||
for j in range(0, 3):
|
for j in range(0, 3):
|
||||||
yd, xd = rand(10000)
|
yd, xd = rand(10000)
|
||||||
pw2.plot(y=yd*(j+1), x=xd, params={'iter': i, 'val': j})
|
pw2.plot(y=yd*(j+1), x=xd, params={'iter': i, 'val': j})
|
||||||
|
|
||||||
#app.exec_()
|
## Test large numbers
|
||||||
|
curve = pw3.plot(np.random.normal(size=100)*1e6)
|
||||||
|
curve.setPen('w') ## white pen
|
||||||
|
curve.setShadowPen(pg.mkPen((70,70,30), width=6, cosmetic=True))
|
||||||
|
|
||||||
|
|
||||||
|
## Start Qt event loop unless running in interactive mode.
|
||||||
|
if sys.flags.interactive != 1:
|
||||||
|
app.exec_()
|
||||||
|
@ -4,32 +4,26 @@
|
|||||||
import sys, os
|
import sys, os
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
from numpy import random
|
|
||||||
from scipy import zeros, ones
|
|
||||||
from pyqtgraph.graphicsWindows import *
|
|
||||||
from pyqtgraph.graphicsItems import *
|
|
||||||
from pyqtgraph.widgets import *
|
|
||||||
from pyqtgraph.PlotWidget import *
|
|
||||||
from pyqtgraph.functions import mkPen
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
import numpy as np
|
||||||
|
import pyqtgraph as pg
|
||||||
|
|
||||||
|
## create GUI
|
||||||
app = QtGui.QApplication([])
|
app = QtGui.QApplication([])
|
||||||
|
w = QtGui.QMainWindow()
|
||||||
class Win(QtGui.QMainWindow):
|
v = pg.GraphicsView()
|
||||||
pass
|
v.invertY(True) ## Images usually have their Y-axis pointing downward
|
||||||
|
|
||||||
w = Win()
|
|
||||||
v = GraphicsView(useOpenGL=False)
|
|
||||||
v.invertY(True)
|
|
||||||
v.setAspectLocked(True)
|
v.setAspectLocked(True)
|
||||||
v.enableMouse(True)
|
v.enableMouse(True)
|
||||||
v.autoPixelScale = False
|
v.autoPixelScale = False
|
||||||
|
|
||||||
w.setCentralWidget(v)
|
w.setCentralWidget(v)
|
||||||
s = v.scene()
|
s = v.scene()
|
||||||
v.setRange(QtCore.QRect(-2, -2, 220, 220))
|
v.setRange(QtCore.QRect(-2, -2, 220, 220))
|
||||||
|
w.show()
|
||||||
|
|
||||||
arr = ones((100, 100), dtype=float)
|
## Create image to display
|
||||||
|
arr = np.ones((100, 100), dtype=float)
|
||||||
arr[45:55, 45:55] = 0
|
arr[45:55, 45:55] = 0
|
||||||
arr[25, :] = 5
|
arr[25, :] = 5
|
||||||
arr[:, 25] = 5
|
arr[:, 25] = 5
|
||||||
@ -38,21 +32,23 @@ arr[:, 75] = 5
|
|||||||
arr[50, :] = 10
|
arr[50, :] = 10
|
||||||
arr[:, 50] = 10
|
arr[:, 50] = 10
|
||||||
|
|
||||||
im1 = ImageItem(arr)
|
## Create image items, add to scene and set position
|
||||||
im2 = ImageItem(arr)
|
im1 = pg.ImageItem(arr)
|
||||||
|
im2 = pg.ImageItem(arr)
|
||||||
s.addItem(im1)
|
s.addItem(im1)
|
||||||
s.addItem(im2)
|
s.addItem(im2)
|
||||||
im2.moveBy(110, 20)
|
im2.moveBy(110, 20)
|
||||||
im3 = ImageItem()
|
im3 = pg.ImageItem()
|
||||||
s.addItem(im3)
|
s.addItem(im3)
|
||||||
im3.moveBy(0, 130)
|
im3.moveBy(0, 130)
|
||||||
im3.setZValue(10)
|
im3.setZValue(10)
|
||||||
im4 = ImageItem()
|
im4 = pg.ImageItem()
|
||||||
s.addItem(im4)
|
s.addItem(im4)
|
||||||
im4.moveBy(110, 130)
|
im4.moveBy(110, 130)
|
||||||
im4.setZValue(10)
|
im4.setZValue(10)
|
||||||
|
|
||||||
pi1 = PlotItem()
|
## create the plot
|
||||||
|
pi1 = pg.PlotItem()
|
||||||
s.addItem(pi1)
|
s.addItem(pi1)
|
||||||
pi1.scale(0.5, 0.5)
|
pi1.scale(0.5, 0.5)
|
||||||
pi1.setGeometry(0, 170, 300, 100)
|
pi1.setGeometry(0, 170, 300, 100)
|
||||||
@ -76,34 +72,39 @@ def updateRoiPlot(roi, data=None):
|
|||||||
if data is not None:
|
if data is not None:
|
||||||
roi.curve.updateData(data.mean(axis=1))
|
roi.curve.updateData(data.mean(axis=1))
|
||||||
|
|
||||||
#def updatePlot(roi)
|
|
||||||
|
|
||||||
|
## Create a variety of different ROI types
|
||||||
rois = []
|
rois = []
|
||||||
rois.append(TestROI([0, 0], [20, 20], maxBounds=QtCore.QRectF(-10, -10, 230, 140), pen=mkPen(0)))
|
rois.append(pg.widgets.TestROI([0, 0], [20, 20], maxBounds=QtCore.QRectF(-10, -10, 230, 140), pen=(0,9)))
|
||||||
rois.append(LineROI([0, 0], [20, 20], width=5, pen=mkPen(1)))
|
rois.append(pg.widgets.LineROI([0, 0], [20, 20], width=5, pen=(1,9)))
|
||||||
rois.append(MultiLineROI([[0, 50], [50, 60], [60, 30]], width=5, pen=mkPen(2)))
|
rois.append(pg.widgets.MultiLineROI([[0, 50], [50, 60], [60, 30]], width=5, pen=(2,9)))
|
||||||
rois.append(EllipseROI([110, 10], [30, 20], pen=mkPen(3)))
|
rois.append(pg.widgets.EllipseROI([110, 10], [30, 20], pen=(3,9)))
|
||||||
rois.append(CircleROI([110, 50], [20, 20], pen=mkPen(4)))
|
rois.append(pg.widgets.CircleROI([110, 50], [20, 20], pen=(4,9)))
|
||||||
rois.append(PolygonROI([[2,0], [2.1,0], [2,.1]], pen=mkPen(5)))
|
rois.append(pg.widgets.PolygonROI([[2,0], [2.1,0], [2,.1]], pen=(5,9)))
|
||||||
#rois.append(SpiralROI([20,30], [1,1], pen=mkPen(0)))
|
#rois.append(SpiralROI([20,30], [1,1], pen=mkPen(0)))
|
||||||
|
|
||||||
|
## Add each ROI to the scene and link its data to a plot curve with the same color
|
||||||
for r in rois:
|
for r in rois:
|
||||||
s.addItem(r)
|
s.addItem(r)
|
||||||
c = pi1.plot(pen=r.pen)
|
c = pi1.plot(pen=r.pen)
|
||||||
r.curve = c
|
r.curve = c
|
||||||
r.connect(r, QtCore.SIGNAL('regionChanged'), updateRoi)
|
r.sigRegionChanged.connect(updateRoi)
|
||||||
|
|
||||||
def updateImage():
|
def updateImage():
|
||||||
global im1, arr, lastRoi
|
global im1, arr, lastRoi
|
||||||
r = abs(random.normal(loc=0, scale=(arr.max()-arr.min())*0.1, size=arr.shape))
|
r = abs(np.random.normal(loc=0, scale=(arr.max()-arr.min())*0.1, size=arr.shape))
|
||||||
im1.updateImage(arr + r)
|
im1.updateImage(arr + r)
|
||||||
updateRoi(lastRoi)
|
updateRoi(lastRoi)
|
||||||
for r in rois:
|
for r in rois:
|
||||||
updateRoiPlot(r)
|
updateRoiPlot(r)
|
||||||
|
|
||||||
|
## Rapidly update one of the images with random noise
|
||||||
t = QtCore.QTimer()
|
t = QtCore.QTimer()
|
||||||
t.connect(t, QtCore.SIGNAL('timeout()'), updateImage)
|
t.timeout.connect(updateImage)
|
||||||
t.start(50)
|
t.start(50)
|
||||||
|
|
||||||
w.show()
|
|
||||||
app.exec_()
|
|
||||||
|
## Start Qt event loop unless running in interactive mode.
|
||||||
|
if sys.flags.interactive != 1:
|
||||||
|
app.exec_()
|
||||||
|
@ -3,18 +3,16 @@
|
|||||||
import sys, os
|
import sys, os
|
||||||
sys.path = [os.path.join(os.path.dirname(__file__), '..', '..')] + sys.path
|
sys.path = [os.path.join(os.path.dirname(__file__), '..', '..')] + sys.path
|
||||||
|
|
||||||
from pyqtgraph.GraphicsView import *
|
|
||||||
from pyqtgraph.graphicsItems import *
|
|
||||||
#from numpy import random
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
from scipy.ndimage import *
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import pyqtgraph as pg
|
||||||
|
|
||||||
app = QtGui.QApplication([])
|
app = QtGui.QApplication([])
|
||||||
|
|
||||||
## Create window with GraphicsView widget
|
## Create window with GraphicsView widget
|
||||||
win = QtGui.QMainWindow()
|
win = QtGui.QMainWindow()
|
||||||
view = GraphicsView()
|
view = pg.GraphicsView()
|
||||||
#view.useOpenGL(True)
|
#view.useOpenGL(True)
|
||||||
win.setCentralWidget(view)
|
win.setCentralWidget(view)
|
||||||
win.show()
|
win.show()
|
||||||
@ -26,7 +24,7 @@ view.enableMouse()
|
|||||||
view.setAspectLocked(True)
|
view.setAspectLocked(True)
|
||||||
|
|
||||||
## Create image item
|
## Create image item
|
||||||
img = ImageItem(np.zeros((200,200)))
|
img = pg.ImageItem(np.zeros((200,200)))
|
||||||
view.scene().addItem(img)
|
view.scene().addItem(img)
|
||||||
|
|
||||||
## Set initial view bounds
|
## Set initial view bounds
|
||||||
@ -35,4 +33,6 @@ view.setRange(QtCore.QRectF(0, 0, 200, 200))
|
|||||||
img.setDrawKernel(1)
|
img.setDrawKernel(1)
|
||||||
img.setLevels(10,0)
|
img.setLevels(10,0)
|
||||||
|
|
||||||
#app.exec_()
|
## Start Qt event loop unless running in interactive mode.
|
||||||
|
if sys.flags.interactive != 1:
|
||||||
|
app.exec_()
|
||||||
|
@ -1,32 +1,26 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import sys, os
|
import sys, os
|
||||||
|
## Add path to library (just for examples; you do not need this)
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt4 import QtGui, QtCore
|
||||||
from pyqtgraph.PlotWidget import *
|
import pyqtgraph as pg
|
||||||
from pyqtgraph.graphicsItems import *
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
app = QtGui.QApplication([])
|
app = QtGui.QApplication([])
|
||||||
mw = QtGui.QMainWindow()
|
mw = QtGui.QMainWindow()
|
||||||
cw = PlotWidget()
|
cw = pg.PlotWidget()
|
||||||
mw.setCentralWidget(cw)
|
mw.setCentralWidget(cw)
|
||||||
mw.show()
|
mw.show()
|
||||||
|
|
||||||
|
s1 = pg.ScatterPlotItem(size=10, pen=QtGui.QPen(QtCore.Qt.NoPen), brush=QtGui.QBrush(QtGui.QColor(255, 255, 255, 20)))
|
||||||
#s1 = SpotItem(5, pxMode=True, brush=QtGui.QBrush(QtGui.QColor(0, 0, 200)), pen=QtGui.QPen(QtGui.QColor(100,100,100)))
|
|
||||||
#s1.setPos(1, 0)
|
|
||||||
#s2 = SpotItem(.1, pxMode=False, brush=QtGui.QBrush(QtGui.QColor(0, 200, 0)), pen=QtGui.QPen(QtGui.QColor(100,100,100)))
|
|
||||||
#s2.setPos(0, 1)
|
|
||||||
#cw.addItem(s1)
|
|
||||||
#cw.addItem(s2)
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
s1 = ScatterPlotItem(size=10, pen=QtGui.QPen(QtCore.Qt.NoPen), brush=QtGui.QBrush(QtGui.QColor(255, 255, 255, 20)))
|
|
||||||
pos = np.random.normal(size=(2,3000))
|
pos = np.random.normal(size=(2,3000))
|
||||||
spots = [{'pos': pos[:,i]} for i in range(3000)]
|
spots = [{'pos': pos[:,i]} for i in range(3000)]
|
||||||
s1.addPoints(spots)
|
s1.addPoints(spots)
|
||||||
|
|
||||||
cw.addDataItem(s1)
|
cw.addDataItem(s1)
|
||||||
|
|
||||||
|
## Start Qt event loop unless running in interactive mode.
|
||||||
|
if sys.flags.interactive != 1:
|
||||||
|
app.exec_()
|
||||||
|
|
||||||
|
@ -4,10 +4,12 @@
|
|||||||
import sys, os
|
import sys, os
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
from scipy import random
|
## This example uses a ViewBox to create a PlotWidget-like interface
|
||||||
|
|
||||||
|
#from scipy import random
|
||||||
|
import numpy as np
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt4 import QtGui, QtCore
|
||||||
from pyqtgraph.GraphicsView import *
|
import pyqtgraph as pg
|
||||||
from pyqtgraph.graphicsItems import *
|
|
||||||
|
|
||||||
app = QtGui.QApplication([])
|
app = QtGui.QApplication([])
|
||||||
mw = QtGui.QMainWindow()
|
mw = QtGui.QMainWindow()
|
||||||
@ -19,15 +21,15 @@ mw.show()
|
|||||||
mw.resize(800, 600)
|
mw.resize(800, 600)
|
||||||
|
|
||||||
|
|
||||||
gv = GraphicsView(cw)
|
gv = pg.GraphicsView(cw)
|
||||||
gv.enableMouse(False)
|
gv.enableMouse(False) ## Mouse interaction will be handled by the ViewBox
|
||||||
l = QtGui.QGraphicsGridLayout()
|
l = QtGui.QGraphicsGridLayout()
|
||||||
l.setHorizontalSpacing(0)
|
l.setHorizontalSpacing(0)
|
||||||
l.setVerticalSpacing(0)
|
l.setVerticalSpacing(0)
|
||||||
|
|
||||||
|
|
||||||
vb = ViewBox()
|
vb = pg.ViewBox()
|
||||||
p1 = PlotCurveItem()
|
p1 = pg.PlotCurveItem()
|
||||||
vb.addItem(p1)
|
vb.addItem(p1)
|
||||||
vl.addWidget(gv)
|
vl.addWidget(gv)
|
||||||
|
|
||||||
@ -61,21 +63,21 @@ l.addItem(vb, 0, 1)
|
|||||||
gv.centralWidget.setLayout(l)
|
gv.centralWidget.setLayout(l)
|
||||||
|
|
||||||
|
|
||||||
xScale = ScaleItem(orientation='bottom', linkView=vb)
|
xScale = pg.ScaleItem(orientation='bottom', linkView=vb)
|
||||||
l.addItem(xScale, 1, 1)
|
l.addItem(xScale, 1, 1)
|
||||||
yScale = ScaleItem(orientation='left', linkView=vb)
|
yScale = pg.ScaleItem(orientation='left', linkView=vb)
|
||||||
l.addItem(yScale, 0, 0)
|
l.addItem(yScale, 0, 0)
|
||||||
|
|
||||||
xScale.setLabel(text=u"<span style='color: #ff0000; font-weight: bold'>X</span> <i>Axis</i>", units="s")
|
xScale.setLabel(text=u"<span style='color: #ff0000; font-weight: bold'>X</span> <i>Axis</i>", units="s")
|
||||||
yScale.setLabel('Y Axis', units='V')
|
yScale.setLabel('Y Axis', units='V')
|
||||||
|
|
||||||
def rand(n):
|
def rand(n):
|
||||||
data = random.random(n)
|
data = np.random.random(n)
|
||||||
data[int(n*0.1):int(n*0.13)] += .5
|
data[int(n*0.1):int(n*0.13)] += .5
|
||||||
data[int(n*0.18)] += 2
|
data[int(n*0.18)] += 2
|
||||||
data[int(n*0.1):int(n*0.13)] *= 5
|
data[int(n*0.1):int(n*0.13)] *= 5
|
||||||
data[int(n*0.18)] *= 20
|
data[int(n*0.18)] *= 20
|
||||||
return data, arange(n, n+len(data)) / float(n)
|
return data, np.arange(n, n+len(data)) / float(n)
|
||||||
|
|
||||||
|
|
||||||
def updateData():
|
def updateData():
|
||||||
@ -87,7 +89,9 @@ updateData()
|
|||||||
vb.autoRange()
|
vb.autoRange()
|
||||||
|
|
||||||
t = QtCore.QTimer()
|
t = QtCore.QTimer()
|
||||||
QtCore.QObject.connect(t, QtCore.SIGNAL('timeout()'), updateData)
|
t.timeout.connect(updateData)
|
||||||
t.start(50)
|
t.start(50)
|
||||||
|
|
||||||
#app.exec_()
|
## Start Qt event loop unless running in interactive mode.
|
||||||
|
if sys.flags.interactive != 1:
|
||||||
|
app.exec_()
|
||||||
|
94
functions.py
94
functions.py
@ -18,7 +18,8 @@ colorAbbrev = {
|
|||||||
|
|
||||||
|
|
||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
from numpy import clip, floor, log
|
import numpy as np
|
||||||
|
import scipy.ndimage
|
||||||
|
|
||||||
## Copied from acq4/lib/util/functions
|
## Copied from acq4/lib/util/functions
|
||||||
SI_PREFIXES = u'yzafpnµm kMGTPEZY'
|
SI_PREFIXES = u'yzafpnµm kMGTPEZY'
|
||||||
@ -28,7 +29,7 @@ def siScale(x, minVal=1e-25):
|
|||||||
m = 0
|
m = 0
|
||||||
x = 0
|
x = 0
|
||||||
else:
|
else:
|
||||||
m = int(clip(floor(log(abs(x))/log(1000)), -9.0, 9.0))
|
m = int(np.clip(np.floor(np.log(abs(x))/np.log(1000)), -9.0, 9.0))
|
||||||
if m == 0:
|
if m == 0:
|
||||||
pref = ''
|
pref = ''
|
||||||
elif m < -8 or m > 8:
|
elif m < -8 or m > 8:
|
||||||
@ -145,13 +146,13 @@ def mkColor(*args):
|
|||||||
return QtGui.QColor(r, g, b, a)
|
return QtGui.QColor(r, g, b, a)
|
||||||
|
|
||||||
def colorTuple(c):
|
def colorTuple(c):
|
||||||
return (c.red(), c.blue(), c.green(), c.alpha())
|
return (c.red(), c.green(), c.blue(), c.alpha())
|
||||||
|
|
||||||
def colorStr(c):
|
def colorStr(c):
|
||||||
"""Generate a hex string code from a QColor"""
|
"""Generate a hex string code from a QColor"""
|
||||||
return ('%02x'*4) % colorTuple(c)
|
return ('%02x'*4) % colorTuple(c)
|
||||||
|
|
||||||
def intColor(index, hues=9, values=3, maxValue=255, minValue=150, maxHue=360, minHue=0, sat=255):
|
def intColor(index, hues=9, values=1, maxValue=255, minValue=150, maxHue=360, minHue=0, sat=255, alpha=255, **kargs):
|
||||||
"""Creates a QColor from a single index. Useful for stepping through a predefined list of colors.
|
"""Creates a QColor from a single index. Useful for stepping through a predefined list of colors.
|
||||||
- The argument "index" determines which color from the set will be returned
|
- The argument "index" determines which color from the set will be returned
|
||||||
- All other arguments determine what the set of predefined colors will be
|
- All other arguments determine what the set of predefined colors will be
|
||||||
@ -163,9 +164,90 @@ def intColor(index, hues=9, values=3, maxValue=255, minValue=150, maxHue=360, mi
|
|||||||
ind = int(index) % (hues * values)
|
ind = int(index) % (hues * values)
|
||||||
indh = ind % hues
|
indh = ind % hues
|
||||||
indv = ind / hues
|
indv = ind / hues
|
||||||
v = minValue + indv * ((maxValue-minValue) / (values-1))
|
if values > 1:
|
||||||
|
v = minValue + indv * ((maxValue-minValue) / (values-1))
|
||||||
|
else:
|
||||||
|
v = maxValue
|
||||||
h = minHue + (indh * (maxHue-minHue)) / hues
|
h = minHue + (indh * (maxHue-minHue)) / hues
|
||||||
|
|
||||||
c = QtGui.QColor()
|
c = QtGui.QColor()
|
||||||
c.setHsv(h, sat, v)
|
c.setHsv(h, sat, v)
|
||||||
return c
|
c.setAlpha(alpha)
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def affineSlice(data, shape, origin, vectors, axes, **kargs):
|
||||||
|
"""Take an arbitrary slice through an array.
|
||||||
|
Parameters:
|
||||||
|
data: the original dataset
|
||||||
|
shape: the shape of the slice to take (Note the return value may have more dimensions than len(shape))
|
||||||
|
origin: the location in the original dataset that will become the origin in the sliced data.
|
||||||
|
vectors: list of unit vectors which point in the direction of the slice axes
|
||||||
|
each vector must be the same length as axes
|
||||||
|
If the vectors are not unit length, the result will be scaled.
|
||||||
|
If the vectors are not orthogonal, the result will be sheared.
|
||||||
|
axes: the axes in the original dataset which correspond to the slice vectors
|
||||||
|
|
||||||
|
Example: start with a 4D data set, take a diagonal-planar slice out of the last 3 axes
|
||||||
|
- data = array with dims (time, x, y, z) = (100, 40, 40, 40)
|
||||||
|
- The plane to pull out is perpendicular to the vector (x,y,z) = (1,1,1)
|
||||||
|
- The origin of the slice will be at (x,y,z) = (40, 0, 0)
|
||||||
|
- The we will slice a 20x20 plane from each timepoint, giving a final shape (100, 20, 20)
|
||||||
|
affineSlice(data, shape=(20,20), origin=(40,0,0), vectors=((-1, 1, 0), (-1, 0, 1)), axes=(1,2,3))
|
||||||
|
|
||||||
|
Note the following:
|
||||||
|
len(shape) == len(vectors)
|
||||||
|
len(origin) == len(axes) == len(vectors[0])
|
||||||
|
"""
|
||||||
|
|
||||||
|
# sanity check
|
||||||
|
if len(shape) != len(vectors):
|
||||||
|
raise Exception("shape and vectors must have same length.")
|
||||||
|
if len(origin) != len(axes):
|
||||||
|
raise Exception("origin and axes must have same length.")
|
||||||
|
for v in vectors:
|
||||||
|
if len(v) != len(axes):
|
||||||
|
raise Exception("each vector must be same length as axes.")
|
||||||
|
shape = (np.ceil(shape[0]), np.ceil(shape[1]))
|
||||||
|
|
||||||
|
## transpose data so slice axes come first
|
||||||
|
trAx = range(data.ndim)
|
||||||
|
for x in axes:
|
||||||
|
trAx.remove(x)
|
||||||
|
tr1 = tuple(axes) + tuple(trAx)
|
||||||
|
data = data.transpose(tr1)
|
||||||
|
#print "tr1:", tr1
|
||||||
|
## dims are now [(slice axes), (other axes)]
|
||||||
|
|
||||||
|
|
||||||
|
## make sure vectors are arrays
|
||||||
|
vectors = np.array(vectors)
|
||||||
|
origin = np.array(origin)
|
||||||
|
origin.shape = (len(axes),) + (1,)*len(shape)
|
||||||
|
|
||||||
|
## Build array of sample locations.
|
||||||
|
grid = np.mgrid[tuple([slice(0,x) for x in shape])] ## mesh grid of indexes
|
||||||
|
#print shape, grid.shape
|
||||||
|
x = (grid[np.newaxis,...] * vectors.transpose()[(Ellipsis,) + (np.newaxis,)*len(shape)]).sum(axis=1) ## magic
|
||||||
|
x += origin
|
||||||
|
#print "X values:"
|
||||||
|
#print x
|
||||||
|
## iterate manually over unused axes since map_coordinates won't do it for us
|
||||||
|
extraShape = data.shape[len(axes):]
|
||||||
|
output = np.empty(tuple(shape) + extraShape, dtype=data.dtype)
|
||||||
|
for inds in np.ndindex(*extraShape):
|
||||||
|
ind = (Ellipsis,) + inds
|
||||||
|
#print data[ind].shape, x.shape, output[ind].shape, output.shape
|
||||||
|
output[ind] = scipy.ndimage.map_coordinates(data[ind], x, **kargs)
|
||||||
|
|
||||||
|
tr = range(output.ndim)
|
||||||
|
trb = []
|
||||||
|
for i in range(min(axes)):
|
||||||
|
ind = tr1.index(i) + (len(shape)-len(axes))
|
||||||
|
tr.remove(ind)
|
||||||
|
trb.append(ind)
|
||||||
|
tr2 = tuple(trb+tr)
|
||||||
|
|
||||||
|
## Untranspose array before returning
|
||||||
|
return output.transpose(tr2)
|
||||||
|
|
||||||
|
265
graphicsItems.py
265
graphicsItems.py
@ -11,7 +11,7 @@ Provides ImageItem, PlotCurveItem, and ViewBox, amongst others.
|
|||||||
from PyQt4 import QtGui, QtCore
|
from PyQt4 import QtGui, QtCore
|
||||||
if not hasattr(QtCore, 'Signal'):
|
if not hasattr(QtCore, 'Signal'):
|
||||||
QtCore.Signal = QtCore.pyqtSignal
|
QtCore.Signal = QtCore.pyqtSignal
|
||||||
from ObjectWorkaround import *
|
#from ObjectWorkaround import *
|
||||||
#tryWorkaround(QtCore, QtGui)
|
#tryWorkaround(QtCore, QtGui)
|
||||||
#from numpy import *
|
#from numpy import *
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -28,8 +28,16 @@ from Point import *
|
|||||||
from functions import *
|
from functions import *
|
||||||
import types, sys, struct
|
import types, sys, struct
|
||||||
import weakref
|
import weakref
|
||||||
|
#import debug
|
||||||
#from debug import *
|
#from debug import *
|
||||||
|
|
||||||
|
## QGraphicsObject didn't appear until 4.6; this is for compatibility with 4.5
|
||||||
|
if not hasattr(QtGui, 'QGraphicsObject'):
|
||||||
|
class QGraphicsObject(QtGui.QGraphicsWidget):
|
||||||
|
def shape(self):
|
||||||
|
return QtGui.QGraphicsItem.shape(self)
|
||||||
|
QtGui.QGraphicsObject = QGraphicsObject
|
||||||
|
|
||||||
|
|
||||||
## Should probably just use QGraphicsGroupItem and instruct it to pass events on to children..
|
## Should probably just use QGraphicsGroupItem and instruct it to pass events on to children..
|
||||||
class ItemGroup(QtGui.QGraphicsItem):
|
class ItemGroup(QtGui.QGraphicsItem):
|
||||||
@ -68,12 +76,12 @@ class ItemGroup(QtGui.QGraphicsItem):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GraphicsObject(QGraphicsObject):
|
class GraphicsObject(QtGui.QGraphicsObject):
|
||||||
"""Extends QGraphicsObject with a few important functions.
|
"""Extends QGraphicsObject with a few important functions.
|
||||||
(Most of these assume that the object is in a scene with a single view)"""
|
(Most of these assume that the object is in a scene with a single view)"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
QGraphicsObject.__init__(self, *args)
|
QtGui.QGraphicsObject.__init__(self, *args)
|
||||||
self._view = None
|
self._view = None
|
||||||
|
|
||||||
def getViewWidget(self):
|
def getViewWidget(self):
|
||||||
@ -174,14 +182,19 @@ class GraphicsObject(QGraphicsObject):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ImageItem(QtGui.QGraphicsPixmapItem, QObjectWorkaround):
|
class ImageItem(QtGui.QGraphicsObject):
|
||||||
|
|
||||||
|
sigImageChanged = QtCore.Signal()
|
||||||
|
|
||||||
if 'linux' not in sys.platform: ## disable weave optimization on linux--broken there.
|
if 'linux' not in sys.platform: ## disable weave optimization on linux--broken there.
|
||||||
useWeave = True
|
useWeave = True
|
||||||
else:
|
else:
|
||||||
useWeave = False
|
useWeave = False
|
||||||
|
|
||||||
def __init__(self, image=None, copy=True, parent=None, border=None, *args):
|
def __init__(self, image=None, copy=True, parent=None, border=None, *args):
|
||||||
QObjectWorkaround.__init__(self)
|
#QObjectWorkaround.__init__(self)
|
||||||
|
QtGui.QGraphicsObject.__init__(self)
|
||||||
|
#self.pixmapItem = QtGui.QGraphicsPixmapItem(self)
|
||||||
self.qimage = QtGui.QImage()
|
self.qimage = QtGui.QImage()
|
||||||
self.pixmap = None
|
self.pixmap = None
|
||||||
#self.useWeave = True
|
#self.useWeave = True
|
||||||
@ -195,7 +208,7 @@ class ImageItem(QtGui.QGraphicsPixmapItem, QObjectWorkaround):
|
|||||||
border = mkPen(border)
|
border = mkPen(border)
|
||||||
self.border = border
|
self.border = border
|
||||||
|
|
||||||
QtGui.QGraphicsPixmapItem.__init__(self, parent, *args)
|
#QtGui.QGraphicsPixmapItem.__init__(self, parent, *args)
|
||||||
#self.pixmapItem = QtGui.QGraphicsPixmapItem(self)
|
#self.pixmapItem = QtGui.QGraphicsPixmapItem(self)
|
||||||
if image is not None:
|
if image is not None:
|
||||||
self.updateImage(image, copy, autoRange=True)
|
self.updateImage(image, copy, autoRange=True)
|
||||||
@ -218,7 +231,12 @@ class ImageItem(QtGui.QGraphicsPixmapItem, QObjectWorkaround):
|
|||||||
if self.pixmap is None:
|
if self.pixmap is None:
|
||||||
return None
|
return None
|
||||||
return self.pixmap.height()
|
return self.pixmap.height()
|
||||||
|
|
||||||
|
def boundingRect(self):
|
||||||
|
if self.pixmap is None:
|
||||||
|
return QtCore.QRectF(0., 0., 0., 0.)
|
||||||
|
return QtCore.QRectF(0., 0., float(self.width()), float(self.height()))
|
||||||
|
|
||||||
def setClipLevel(self, level=None):
|
def setClipLevel(self, level=None):
|
||||||
self.clipLevel = level
|
self.clipLevel = level
|
||||||
|
|
||||||
@ -252,6 +270,8 @@ class ImageItem(QtGui.QGraphicsPixmapItem, QObjectWorkaround):
|
|||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
gotNewData = True
|
gotNewData = True
|
||||||
|
if self.image is None or image.shape != self.image.shape:
|
||||||
|
self.prepareGeometryChange()
|
||||||
if copy:
|
if copy:
|
||||||
self.image = image.view(np.ndarray).copy()
|
self.image = image.view(np.ndarray).copy()
|
||||||
else:
|
else:
|
||||||
@ -323,7 +343,7 @@ class ImageItem(QtGui.QGraphicsPixmapItem, QObjectWorkaround):
|
|||||||
im2 = im.transpose(axh['y'], axh['x'], axh['c'])
|
im2 = im.transpose(axh['y'], axh['x'], axh['c'])
|
||||||
|
|
||||||
for i in range(0, im.shape[axh['c']]):
|
for i in range(0, im.shape[axh['c']]):
|
||||||
im1[..., i] = im2[..., i]
|
im1[..., 2-i] = im2[..., i] ## for some reason, the colors line up as BGR in the final image.
|
||||||
|
|
||||||
for i in range(im.shape[axh['c']], 3):
|
for i in range(im.shape[axh['c']], 3):
|
||||||
im1[..., i] = 0
|
im1[..., i] = 0
|
||||||
@ -345,14 +365,16 @@ class ImageItem(QtGui.QGraphicsPixmapItem, QObjectWorkaround):
|
|||||||
im1[..., 2][mask] = 255
|
im1[..., 2][mask] = 255
|
||||||
#print "Final image:", im1.dtype, im1.min(), im1.max(), im1.shape
|
#print "Final image:", im1.dtype, im1.min(), im1.max(), im1.shape
|
||||||
self.ims = im1.tostring() ## Must be held in memory here because qImage won't do it for us :(
|
self.ims = im1.tostring() ## Must be held in memory here because qImage won't do it for us :(
|
||||||
qimage = QtGui.QImage(self.ims, im1.shape[1], im1.shape[0], QtGui.QImage.Format_ARGB32)
|
qimage = QtGui.QImage(buffer(self.ims), im1.shape[1], im1.shape[0], QtGui.QImage.Format_ARGB32)
|
||||||
self.pixmap = QtGui.QPixmap.fromImage(qimage)
|
self.pixmap = QtGui.QPixmap.fromImage(qimage)
|
||||||
##del self.ims
|
##del self.ims
|
||||||
self.setPixmap(self.pixmap)
|
#self.pixmapItem.setPixmap(self.pixmap)
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
if gotNewData:
|
if gotNewData:
|
||||||
self.emit(QtCore.SIGNAL('imageChanged'))
|
#self.emit(QtCore.SIGNAL('imageChanged'))
|
||||||
|
self.sigImageChanged.emit()
|
||||||
|
|
||||||
def getPixmap(self):
|
def getPixmap(self):
|
||||||
return self.pixmap.copy()
|
return self.pixmap.copy()
|
||||||
@ -397,8 +419,15 @@ class ImageItem(QtGui.QGraphicsPixmapItem, QObjectWorkaround):
|
|||||||
p.setPen(self.border)
|
p.setPen(self.border)
|
||||||
p.drawRect(self.boundingRect())
|
p.drawRect(self.boundingRect())
|
||||||
|
|
||||||
|
def pixelSize(self):
|
||||||
|
"""return size of a single pixel in the image"""
|
||||||
|
br = self.sceneBoundingRect()
|
||||||
|
return br.width()/self.pixmap.width(), br.height()/self.pixmap.height()
|
||||||
|
|
||||||
class PlotCurveItem(GraphicsObject):
|
class PlotCurveItem(GraphicsObject):
|
||||||
|
|
||||||
|
sigPlotChanged = QtCore.Signal(object)
|
||||||
|
|
||||||
"""Class representing a single plot curve."""
|
"""Class representing a single plot curve."""
|
||||||
|
|
||||||
sigClicked = QtCore.Signal(object)
|
sigClicked = QtCore.Signal(object)
|
||||||
@ -565,6 +594,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
self.updateData(y, x, copy)
|
self.updateData(y, x, copy)
|
||||||
|
|
||||||
def updateData(self, data, x=None, copy=False):
|
def updateData(self, data, x=None, copy=False):
|
||||||
|
#prof = debug.Profiler('PlotCurveItem.updateData', disabled=True)
|
||||||
if isinstance(data, list):
|
if isinstance(data, list):
|
||||||
data = np.array(data)
|
data = np.array(data)
|
||||||
if isinstance(x, list):
|
if isinstance(x, list):
|
||||||
@ -591,7 +621,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
x = data[tuple(ind)]
|
x = data[tuple(ind)]
|
||||||
elif data.ndim == 1:
|
elif data.ndim == 1:
|
||||||
y = data
|
y = data
|
||||||
|
#prof.mark("data checks")
|
||||||
self.prepareGeometryChange()
|
self.prepareGeometryChange()
|
||||||
if copy:
|
if copy:
|
||||||
self.yData = y.copy()
|
self.yData = y.copy()
|
||||||
@ -602,6 +632,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
self.xData = x.copy()
|
self.xData = x.copy()
|
||||||
else:
|
else:
|
||||||
self.xData = x
|
self.xData = x
|
||||||
|
#prof.mark('copy')
|
||||||
|
|
||||||
if x is None:
|
if x is None:
|
||||||
self.xData = np.arange(0, self.yData.shape[0])
|
self.xData = np.arange(0, self.yData.shape[0])
|
||||||
@ -610,10 +641,15 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
raise Exception("X and Y arrays must be the same shape--got %s and %s." % (str(x.shape), str(y.shape)))
|
raise Exception("X and Y arrays must be the same shape--got %s and %s." % (str(x.shape), str(y.shape)))
|
||||||
|
|
||||||
self.path = None
|
self.path = None
|
||||||
#self.specPath = None
|
|
||||||
self.xDisp = self.yDisp = None
|
self.xDisp = self.yDisp = None
|
||||||
|
|
||||||
|
#prof.mark('set')
|
||||||
self.update()
|
self.update()
|
||||||
self.emit(QtCore.SIGNAL('plotChanged'), self)
|
#prof.mark('update')
|
||||||
|
#self.emit(QtCore.SIGNAL('plotChanged'), self)
|
||||||
|
self.sigPlotChanged.emit(self)
|
||||||
|
#prof.mark('emit')
|
||||||
|
#prof.finish()
|
||||||
|
|
||||||
def generatePath(self, x, y):
|
def generatePath(self, x, y):
|
||||||
path = QtGui.QPainterPath()
|
path = QtGui.QPainterPath()
|
||||||
@ -634,25 +670,32 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
## 0(i4)
|
## 0(i4)
|
||||||
##
|
##
|
||||||
## All values are big endian--pack using struct.pack('>d') or struct.pack('>i')
|
## All values are big endian--pack using struct.pack('>d') or struct.pack('>i')
|
||||||
#
|
|
||||||
|
#prof = debug.Profiler('PlotCurveItem.generatePath', disabled=True)
|
||||||
|
|
||||||
n = x.shape[0]
|
n = x.shape[0]
|
||||||
# create empty array, pad with extra space on either end
|
# create empty array, pad with extra space on either end
|
||||||
arr = np.empty(n+2, dtype=[('x', '>f8'), ('y', '>f8'), ('c', '>i4')])
|
arr = np.empty(n+2, dtype=[('x', '>f8'), ('y', '>f8'), ('c', '>i4')])
|
||||||
|
#prof.mark('create empty')
|
||||||
# write first two integers
|
# write first two integers
|
||||||
arr.data[12:20] = struct.pack('>ii', n, 0)
|
arr.data[12:20] = struct.pack('>ii', n, 0)
|
||||||
# Fill array with vertex values
|
# Fill array with vertex values
|
||||||
arr[1:-1]['x'] = x
|
arr[1:-1]['x'] = x
|
||||||
arr[1:-1]['y'] = y
|
arr[1:-1]['y'] = y
|
||||||
arr[1:-1]['c'] = 1
|
arr[1:-1]['c'] = 1
|
||||||
|
#prof.mark('fill array')
|
||||||
# write last 0
|
# write last 0
|
||||||
lastInd = 20*(n+1)
|
lastInd = 20*(n+1)
|
||||||
arr.data[lastInd:lastInd+4] = struct.pack('>i', 0)
|
arr.data[lastInd:lastInd+4] = struct.pack('>i', 0)
|
||||||
|
|
||||||
# create datastream object and stream into path
|
# create datastream object and stream into path
|
||||||
buf = QtCore.QByteArray(arr.data[12:lastInd+4]) # I think one unnecessary copy happens here
|
buf = QtCore.QByteArray(arr.data[12:lastInd+4]) # I think one unnecessary copy happens here
|
||||||
|
#prof.mark('create buffer')
|
||||||
ds = QtCore.QDataStream(buf)
|
ds = QtCore.QDataStream(buf)
|
||||||
|
#prof.mark('create dataStream')
|
||||||
ds >> path
|
ds >> path
|
||||||
|
#prof.mark('load path')
|
||||||
|
#prof.finish()
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
@ -677,6 +720,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
return QtCore.QRectF(xmin, ymin, xmax-xmin, ymax-ymin)
|
return QtCore.QRectF(xmin, ymin, xmax-xmin, ymax-ymin)
|
||||||
|
|
||||||
def paint(self, p, opt, widget):
|
def paint(self, p, opt, widget):
|
||||||
|
#prof = debug.Profiler('PlotCurveItem.paint '+str(id(self)), disabled=True)
|
||||||
if self.xData is None:
|
if self.xData is None:
|
||||||
return
|
return
|
||||||
#if self.opts['spectrumMode']:
|
#if self.opts['spectrumMode']:
|
||||||
@ -688,6 +732,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
if self.path is None:
|
if self.path is None:
|
||||||
self.path = self.generatePath(*self.getData())
|
self.path = self.generatePath(*self.getData())
|
||||||
path = self.path
|
path = self.path
|
||||||
|
#prof.mark('generate path')
|
||||||
|
|
||||||
if self.shadow is not None:
|
if self.shadow is not None:
|
||||||
sp = QtGui.QPen(self.shadow)
|
sp = QtGui.QPen(self.shadow)
|
||||||
@ -709,7 +754,9 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
p.drawPath(path)
|
p.drawPath(path)
|
||||||
p.setPen(cp)
|
p.setPen(cp)
|
||||||
p.drawPath(path)
|
p.drawPath(path)
|
||||||
|
#prof.mark('drawPath')
|
||||||
|
|
||||||
|
#prof.finish()
|
||||||
#p.setPen(QtGui.QPen(QtGui.QColor(255,0,0)))
|
#p.setPen(QtGui.QPen(QtGui.QColor(255,0,0)))
|
||||||
#p.drawRect(self.boundingRect())
|
#p.drawRect(self.boundingRect())
|
||||||
|
|
||||||
@ -742,7 +789,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
self.sigClicked.emit(self)
|
self.sigClicked.emit(self)
|
||||||
|
|
||||||
|
|
||||||
class CurvePoint(QtGui.QGraphicsItem, QObjectWorkaround):
|
class CurvePoint(QtGui.QGraphicsObject):
|
||||||
"""A GraphicsItem that sets its location to a point on a PlotCurveItem.
|
"""A GraphicsItem that sets its location to a point on a PlotCurveItem.
|
||||||
The position along the curve is a property, and thus can be easily animated."""
|
The position along the curve is a property, and thus can be easily animated."""
|
||||||
|
|
||||||
@ -750,17 +797,16 @@ class CurvePoint(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
"""Position can be set either as an index referring to the sample number or
|
"""Position can be set either as an index referring to the sample number or
|
||||||
the position 0.0 - 1.0"""
|
the position 0.0 - 1.0"""
|
||||||
|
|
||||||
QtGui.QGraphicsItem.__init__(self)
|
QtGui.QGraphicsObject.__init__(self)
|
||||||
QObjectWorkaround.__init__(self)
|
#QObjectWorkaround.__init__(self)
|
||||||
self.curve = None
|
self.curve = weakref.ref(curve)
|
||||||
|
self.setParentItem(curve)
|
||||||
self.setProperty('position', 0.0)
|
self.setProperty('position', 0.0)
|
||||||
self.setProperty('index', 0)
|
self.setProperty('index', 0)
|
||||||
|
|
||||||
if hasattr(self, 'ItemHasNoContents'):
|
if hasattr(self, 'ItemHasNoContents'):
|
||||||
self.setFlags(self.flags() | self.ItemHasNoContents)
|
self.setFlags(self.flags() | self.ItemHasNoContents)
|
||||||
|
|
||||||
self.curve = curve
|
|
||||||
self.setParentItem(curve)
|
|
||||||
if pos is not None:
|
if pos is not None:
|
||||||
self.setPos(pos)
|
self.setPos(pos)
|
||||||
else:
|
else:
|
||||||
@ -773,22 +819,22 @@ class CurvePoint(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
self.setProperty('index', index)
|
self.setProperty('index', index)
|
||||||
|
|
||||||
def event(self, ev):
|
def event(self, ev):
|
||||||
if not isinstance(ev, QtCore.QDynamicPropertyChangeEvent) or self.curve is None:
|
if not isinstance(ev, QtCore.QDynamicPropertyChangeEvent) or self.curve() is None:
|
||||||
return
|
return False
|
||||||
|
|
||||||
if ev.propertyName() == 'index':
|
if ev.propertyName() == 'index':
|
||||||
index = self.property('index').toInt()[0]
|
index = self.property('index').toInt()[0]
|
||||||
elif ev.propertyName() == 'position':
|
elif ev.propertyName() == 'position':
|
||||||
index = None
|
index = None
|
||||||
else:
|
else:
|
||||||
return
|
return False
|
||||||
|
|
||||||
(x, y) = self.curve.getData()
|
(x, y) = self.curve().getData()
|
||||||
if index is None:
|
if index is None:
|
||||||
#print self.property('position').toDouble()[0], self.property('position').typeName()
|
#print self.property('position').toDouble()[0], self.property('position').typeName()
|
||||||
index = (len(x)-1) * clip(self.property('position').toDouble()[0], 0.0, 1.0)
|
index = (len(x)-1) * clip(self.property('position').toDouble()[0], 0.0, 1.0)
|
||||||
|
|
||||||
if index != int(index):
|
if index != int(index): ## interpolate floating-point values
|
||||||
i1 = int(index)
|
i1 = int(index)
|
||||||
i2 = clip(i1+1, 0, len(x)-1)
|
i2 = clip(i1+1, 0, len(x)-1)
|
||||||
s2 = index-i1
|
s2 = index-i1
|
||||||
@ -806,6 +852,7 @@ class CurvePoint(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
self.resetTransform()
|
self.resetTransform()
|
||||||
self.rotate(180+ ang * 180 / np.pi)
|
self.rotate(180+ ang * 180 / np.pi)
|
||||||
QtGui.QGraphicsItem.setPos(self, *newPos)
|
QtGui.QGraphicsItem.setPos(self, *newPos)
|
||||||
|
return True
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
return QtCore.QRectF()
|
return QtCore.QRectF()
|
||||||
@ -814,7 +861,7 @@ class CurvePoint(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def makeAnimation(self, prop='position', start=0.0, end=1.0, duration=10000, loop=1):
|
def makeAnimation(self, prop='position', start=0.0, end=1.0, duration=10000, loop=1):
|
||||||
anim = QtCore.QPropertyAnimation(self._qObj_, prop)
|
anim = QtCore.QPropertyAnimation(self, prop)
|
||||||
anim.setDuration(duration)
|
anim.setDuration(duration)
|
||||||
anim.setStartValue(start)
|
anim.setStartValue(start)
|
||||||
anim.setEndValue(end)
|
anim.setEndValue(end)
|
||||||
@ -939,22 +986,27 @@ class ScatterPlotItem(QtGui.QGraphicsWidget):
|
|||||||
for s in spots:
|
for s in spots:
|
||||||
pos = Point(s['pos'])
|
pos = Point(s['pos'])
|
||||||
size = s.get('size', self.size)
|
size = s.get('size', self.size)
|
||||||
|
if self.pxMode:
|
||||||
|
psize = 0
|
||||||
|
else:
|
||||||
|
psize = size
|
||||||
|
if xmn is None:
|
||||||
|
xmn = pos[0]-psize
|
||||||
|
xmx = pos[0]+psize
|
||||||
|
ymn = pos[1]-psize
|
||||||
|
ymx = pos[1]+psize
|
||||||
|
else:
|
||||||
|
xmn = min(xmn, pos[0]-psize)
|
||||||
|
xmx = max(xmx, pos[0]+psize)
|
||||||
|
ymn = min(ymn, pos[1]-psize)
|
||||||
|
ymx = max(ymx, pos[1]+psize)
|
||||||
|
#print pos, xmn, xmx, ymn, ymx
|
||||||
brush = s.get('brush', self.brush)
|
brush = s.get('brush', self.brush)
|
||||||
pen = s.get('pen', self.pen)
|
pen = s.get('pen', self.pen)
|
||||||
pen.setCosmetic(True)
|
pen.setCosmetic(True)
|
||||||
data = s.get('data', None)
|
data = s.get('data', None)
|
||||||
item = self.mkSpot(pos, size, self.pxMode, brush, pen, data)
|
item = self.mkSpot(pos, size, self.pxMode, brush, pen, data)
|
||||||
self.spots.append(item)
|
self.spots.append(item)
|
||||||
if xmn is None:
|
|
||||||
xmn = pos[0]-size
|
|
||||||
xmx = pos[0]+size
|
|
||||||
ymn = pos[1]-size
|
|
||||||
ymx = pos[1]+size
|
|
||||||
else:
|
|
||||||
xmn = min(xmn, pos[0]-size)
|
|
||||||
xmx = max(xmx, pos[0]+size)
|
|
||||||
ymn = min(ymn, pos[1]-size)
|
|
||||||
ymx = max(ymx, pos[1]+size)
|
|
||||||
self.range = [[xmn, xmx], [ymn, ymx]]
|
self.range = [[xmn, xmx], [ymn, ymx]]
|
||||||
|
|
||||||
|
|
||||||
@ -967,7 +1019,8 @@ class ScatterPlotItem(QtGui.QGraphicsWidget):
|
|||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
((xmn, xmx), (ymn, ymx)) = self.range
|
((xmn, xmx), (ymn, ymx)) = self.range
|
||||||
|
if xmn is None or xmx is None or ymn is None or ymx is None:
|
||||||
|
return QtCore.QRectF()
|
||||||
return QtCore.QRectF(xmn, ymn, xmx-xmn, ymx-ymn)
|
return QtCore.QRectF(xmn, ymn, xmx-xmn, ymx-ymn)
|
||||||
|
|
||||||
def paint(self, p, *args):
|
def paint(self, p, *args):
|
||||||
@ -985,13 +1038,15 @@ class SpotItem(QtGui.QGraphicsWidget):
|
|||||||
def __init__(self, size, pxMode, brush, pen, data):
|
def __init__(self, size, pxMode, brush, pen, data):
|
||||||
QtGui.QGraphicsWidget.__init__(self)
|
QtGui.QGraphicsWidget.__init__(self)
|
||||||
if pxMode:
|
if pxMode:
|
||||||
|
self.setCacheMode(self.DeviceCoordinateCache)
|
||||||
self.setFlags(self.flags() | self.ItemIgnoresTransformations)
|
self.setFlags(self.flags() | self.ItemIgnoresTransformations)
|
||||||
#self.setCacheMode(self.DeviceCoordinateCache) ## causes crash on linux
|
#self.setCacheMode(self.DeviceCoordinateCache) ## causes crash on linux
|
||||||
self.pen = pen
|
self.pen = pen
|
||||||
self.brush = brush
|
self.brush = brush
|
||||||
self.path = QtGui.QPainterPath()
|
self.path = QtGui.QPainterPath()
|
||||||
s2 = size/2.
|
#s2 = size/2.
|
||||||
self.path.addEllipse(QtCore.QRectF(-s2, -s2, size, size))
|
self.path.addEllipse(QtCore.QRectF(-0.5, -0.5, 1, 1))
|
||||||
|
self.scale(size, size)
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def setBrush(self, brush):
|
def setBrush(self, brush):
|
||||||
@ -1036,6 +1091,7 @@ class SpotItem(QtGui.QGraphicsWidget):
|
|||||||
|
|
||||||
|
|
||||||
class ROIPlotItem(PlotCurveItem):
|
class ROIPlotItem(PlotCurveItem):
|
||||||
|
"""Plot curve that monitors an ROI and image for changes to automatically replot."""
|
||||||
def __init__(self, roi, data, img, axes=(0,1), xVals=None, color=None):
|
def __init__(self, roi, data, img, axes=(0,1), xVals=None, color=None):
|
||||||
self.roi = roi
|
self.roi = roi
|
||||||
self.roiData = data
|
self.roiData = data
|
||||||
@ -1043,7 +1099,8 @@ class ROIPlotItem(PlotCurveItem):
|
|||||||
self.axes = axes
|
self.axes = axes
|
||||||
self.xVals = xVals
|
self.xVals = xVals
|
||||||
PlotCurveItem.__init__(self, self.getRoiData(), x=self.xVals, color=color)
|
PlotCurveItem.__init__(self, self.getRoiData(), x=self.xVals, color=color)
|
||||||
roi.connect(roi, QtCore.SIGNAL('regionChanged'), self.roiChangedEvent)
|
#roi.connect(roi, QtCore.SIGNAL('regionChanged'), self.roiChangedEvent)
|
||||||
|
roi.sigRegionChanged.connect(self.roiChangedEvent)
|
||||||
#self.roiChangedEvent()
|
#self.roiChangedEvent()
|
||||||
|
|
||||||
def getRoiData(self):
|
def getRoiData(self):
|
||||||
@ -1073,7 +1130,8 @@ class UIGraphicsItem(GraphicsObject):
|
|||||||
self._viewRect = self._view().rect()
|
self._viewRect = self._view().rect()
|
||||||
self._viewTransform = self.viewTransform()
|
self._viewTransform = self.viewTransform()
|
||||||
self.setNewBounds()
|
self.setNewBounds()
|
||||||
QtCore.QObject.connect(view, QtCore.SIGNAL('viewChanged'), self.viewChangedEvent)
|
#QtCore.QObject.connect(view, QtCore.SIGNAL('viewChanged'), self.viewChangedEvent)
|
||||||
|
view.sigRangeChanged.connect(self.viewRangeChanged)
|
||||||
|
|
||||||
def viewRect(self):
|
def viewRect(self):
|
||||||
"""Return the viewport widget rect"""
|
"""Return the viewport widget rect"""
|
||||||
@ -1110,7 +1168,7 @@ class UIGraphicsItem(GraphicsObject):
|
|||||||
self.bounds = self.viewTransform().inverted()[0].mapRect(bounds)
|
self.bounds = self.viewTransform().inverted()[0].mapRect(bounds)
|
||||||
self.prepareGeometryChange()
|
self.prepareGeometryChange()
|
||||||
|
|
||||||
def viewChangedEvent(self):
|
def viewRangeChanged(self):
|
||||||
"""Called when the view widget is resized"""
|
"""Called when the view widget is resized"""
|
||||||
self.boundingRect()
|
self.boundingRect()
|
||||||
self.update()
|
self.update()
|
||||||
@ -1378,23 +1436,31 @@ class ScaleItem(QtGui.QGraphicsWidget):
|
|||||||
|
|
||||||
def linkToView(self, view):
|
def linkToView(self, view):
|
||||||
if self.orientation in ['right', 'left']:
|
if self.orientation in ['right', 'left']:
|
||||||
signal = QtCore.SIGNAL('yRangeChanged')
|
if self.linkedView is not None and self.linkedView() is not None:
|
||||||
|
#view.sigYRangeChanged.disconnect(self.linkedViewChanged)
|
||||||
|
## should be this instead?
|
||||||
|
self.linkedView().sigYRangeChanged.disconnect(self.linkedViewChanged)
|
||||||
|
self.linkedView = weakref.ref(view)
|
||||||
|
view.sigYRangeChanged.connect(self.linkedViewChanged)
|
||||||
|
#signal = QtCore.SIGNAL('yRangeChanged')
|
||||||
else:
|
else:
|
||||||
signal = QtCore.SIGNAL('xRangeChanged')
|
if self.linkedView is not None and self.linkedView() is not None:
|
||||||
|
#view.sigYRangeChanged.disconnect(self.linkedViewChanged)
|
||||||
|
## should be this instead?
|
||||||
|
self.linkedView().sigXRangeChanged.disconnect(self.linkedViewChanged)
|
||||||
|
self.linkedView = weakref.ref(view)
|
||||||
|
view.sigXRangeChanged.connect(self.linkedViewChanged)
|
||||||
|
#signal = QtCore.SIGNAL('xRangeChanged')
|
||||||
|
|
||||||
if self.linkedView is not None:
|
|
||||||
QtCore.QObject.disconnect(view, signal, self.linkedViewChanged)
|
|
||||||
self.linkedView = view
|
|
||||||
QtCore.QObject.connect(view, signal, self.linkedViewChanged)
|
|
||||||
|
|
||||||
def linkedViewChanged(self, _, newRange):
|
def linkedViewChanged(self, view, newRange):
|
||||||
self.setRange(*newRange)
|
self.setRange(*newRange)
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
if self.linkedView is None or self.grid is False:
|
if self.linkedView is None or self.linkedView() is None or self.grid is False:
|
||||||
return self.mapRectFromParent(self.geometry())
|
return self.mapRectFromParent(self.geometry())
|
||||||
else:
|
else:
|
||||||
return self.mapRectFromParent(self.geometry()) | self.mapRectFromScene(self.linkedView.mapRectToScene(self.linkedView.boundingRect()))
|
return self.mapRectFromParent(self.geometry()) | self.mapRectFromScene(self.linkedView().mapRectToScene(self.linkedView().boundingRect()))
|
||||||
|
|
||||||
def paint(self, p, opt, widget):
|
def paint(self, p, opt, widget):
|
||||||
p.setPen(self.pen)
|
p.setPen(self.pen)
|
||||||
@ -1402,10 +1468,10 @@ class ScaleItem(QtGui.QGraphicsWidget):
|
|||||||
#bounds = self.boundingRect()
|
#bounds = self.boundingRect()
|
||||||
bounds = self.mapRectFromParent(self.geometry())
|
bounds = self.mapRectFromParent(self.geometry())
|
||||||
|
|
||||||
if self.linkedView is None or self.grid is False:
|
if self.linkedView is None or self.linkedView() is None or self.grid is False:
|
||||||
tbounds = bounds
|
tbounds = bounds
|
||||||
else:
|
else:
|
||||||
tbounds = self.mapRectFromScene(self.linkedView.mapRectToScene(self.linkedView.boundingRect()))
|
tbounds = self.mapRectFromScene(self.linkedView().mapRectToScene(self.linkedView().boundingRect()))
|
||||||
|
|
||||||
if self.orientation == 'left':
|
if self.orientation == 'left':
|
||||||
p.drawLine(bounds.topRight(), bounds.bottomRight())
|
p.drawLine(bounds.topRight(), bounds.bottomRight())
|
||||||
@ -1577,6 +1643,12 @@ class ScaleItem(QtGui.QGraphicsWidget):
|
|||||||
|
|
||||||
|
|
||||||
class ViewBox(QtGui.QGraphicsWidget):
|
class ViewBox(QtGui.QGraphicsWidget):
|
||||||
|
|
||||||
|
sigYRangeChanged = QtCore.Signal(object, object)
|
||||||
|
sigXRangeChanged = QtCore.Signal(object, object)
|
||||||
|
sigRangeChangedManually = QtCore.Signal(object)
|
||||||
|
sigRangeChanged = QtCore.Signal(object, object)
|
||||||
|
|
||||||
"""Box that allows internal scaling/panning of children by mouse drag. Not compatible with GraphicsView having the same functionality."""
|
"""Box that allows internal scaling/panning of children by mouse drag. Not compatible with GraphicsView having the same functionality."""
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QtGui.QGraphicsWidget.__init__(self, parent)
|
QtGui.QGraphicsWidget.__init__(self, parent)
|
||||||
@ -1745,7 +1817,8 @@ class ViewBox(QtGui.QGraphicsWidget):
|
|||||||
mask *= np.array([1, -1])
|
mask *= np.array([1, -1])
|
||||||
tr = dif*mask
|
tr = dif*mask
|
||||||
self.translateBy(tr, viewCoords=True)
|
self.translateBy(tr, viewCoords=True)
|
||||||
self.emit(QtCore.SIGNAL('rangeChangedManually'), self.mouseEnabled)
|
#self.emit(QtCore.SIGNAL('rangeChangedManually'), self.mouseEnabled)
|
||||||
|
self.sigRangeChangedManually.emit(self.mouseEnabled)
|
||||||
ev.accept()
|
ev.accept()
|
||||||
elif ev.buttons() & QtCore.Qt.RightButton:
|
elif ev.buttons() & QtCore.Qt.RightButton:
|
||||||
dif = ev.screenPos() - ev.lastScreenPos()
|
dif = ev.screenPos() - ev.lastScreenPos()
|
||||||
@ -1755,7 +1828,8 @@ class ViewBox(QtGui.QGraphicsWidget):
|
|||||||
#print mask, dif, s
|
#print mask, dif, s
|
||||||
center = Point(self.childGroup.transform().inverted()[0].map(ev.buttonDownPos(QtCore.Qt.RightButton)))
|
center = Point(self.childGroup.transform().inverted()[0].map(ev.buttonDownPos(QtCore.Qt.RightButton)))
|
||||||
self.scaleBy(s, center)
|
self.scaleBy(s, center)
|
||||||
self.emit(QtCore.SIGNAL('rangeChangedManually'), self.mouseEnabled)
|
#self.emit(QtCore.SIGNAL('rangeChangedManually'), self.mouseEnabled)
|
||||||
|
self.sigRangeChangedManually.emit(self.mouseEnabled)
|
||||||
ev.accept()
|
ev.accept()
|
||||||
else:
|
else:
|
||||||
ev.ignore()
|
ev.ignore()
|
||||||
@ -1802,8 +1876,10 @@ class ViewBox(QtGui.QGraphicsWidget):
|
|||||||
self.range[1] = [min, max]
|
self.range[1] = [min, max]
|
||||||
#self.ctrl.yMinText.setText('%g' % min)
|
#self.ctrl.yMinText.setText('%g' % min)
|
||||||
#self.ctrl.yMaxText.setText('%g' % max)
|
#self.ctrl.yMaxText.setText('%g' % max)
|
||||||
self.emit(QtCore.SIGNAL('yRangeChanged'), self, (min, max))
|
#self.emit(QtCore.SIGNAL('yRangeChanged'), self, (min, max))
|
||||||
self.emit(QtCore.SIGNAL('viewChanged'), self)
|
self.sigYRangeChanged.emit(self, (min, max))
|
||||||
|
#self.emit(QtCore.SIGNAL('viewChanged'), self)
|
||||||
|
self.sigRangeChanged.emit(self, self.range)
|
||||||
if update:
|
if update:
|
||||||
self.updateMatrix()
|
self.updateMatrix()
|
||||||
|
|
||||||
@ -1827,8 +1903,10 @@ class ViewBox(QtGui.QGraphicsWidget):
|
|||||||
self.range[0] = [min, max]
|
self.range[0] = [min, max]
|
||||||
#self.ctrl.xMinText.setText('%g' % min)
|
#self.ctrl.xMinText.setText('%g' % min)
|
||||||
#self.ctrl.xMaxText.setText('%g' % max)
|
#self.ctrl.xMaxText.setText('%g' % max)
|
||||||
self.emit(QtCore.SIGNAL('xRangeChanged'), self, (min, max))
|
#self.emit(QtCore.SIGNAL('xRangeChanged'), self, (min, max))
|
||||||
self.emit(QtCore.SIGNAL('viewChanged'), self)
|
self.sigXRangeChanged.emit(self, (min, max))
|
||||||
|
#self.emit(QtCore.SIGNAL('viewChanged'), self)
|
||||||
|
self.sigRangeChanged.emit(self, self.range)
|
||||||
if update:
|
if update:
|
||||||
self.updateMatrix()
|
self.updateMatrix()
|
||||||
|
|
||||||
@ -1852,6 +1930,11 @@ class ViewBox(QtGui.QGraphicsWidget):
|
|||||||
|
|
||||||
|
|
||||||
class InfiniteLine(GraphicsObject):
|
class InfiniteLine(GraphicsObject):
|
||||||
|
|
||||||
|
sigDragged = QtCore.Signal(object)
|
||||||
|
sigPositionChangeFinished = QtCore.Signal(object)
|
||||||
|
sigPositionChanged = QtCore.Signal(object)
|
||||||
|
|
||||||
def __init__(self, view, pos=0, angle=90, pen=None, movable=False, bounds=None):
|
def __init__(self, view, pos=0, angle=90, pen=None, movable=False, bounds=None):
|
||||||
GraphicsObject.__init__(self)
|
GraphicsObject.__init__(self)
|
||||||
self.bounds = QtCore.QRectF() ## graphicsitem boundary
|
self.bounds = QtCore.QRectF() ## graphicsitem boundary
|
||||||
@ -1877,7 +1960,8 @@ class InfiniteLine(GraphicsObject):
|
|||||||
#self.setFlag(self.ItemSendsScenePositionChanges)
|
#self.setFlag(self.ItemSendsScenePositionChanges)
|
||||||
#for p in self.getBoundingParents():
|
#for p in self.getBoundingParents():
|
||||||
#QtCore.QObject.connect(p, QtCore.SIGNAL('viewChanged'), self.updateLine)
|
#QtCore.QObject.connect(p, QtCore.SIGNAL('viewChanged'), self.updateLine)
|
||||||
QtCore.QObject.connect(self.view(), QtCore.SIGNAL('viewChanged'), self.updateLine)
|
#QtCore.QObject.connect(self.view(), QtCore.SIGNAL('viewChanged'), self.updateLine)
|
||||||
|
self.view().sigRangeChanged.connect(self.updateLine)
|
||||||
|
|
||||||
def setMovable(self, m):
|
def setMovable(self, m):
|
||||||
self.movable = m
|
self.movable = m
|
||||||
@ -1935,7 +2019,8 @@ class InfiniteLine(GraphicsObject):
|
|||||||
if self.p != newPos:
|
if self.p != newPos:
|
||||||
self.p = newPos
|
self.p = newPos
|
||||||
self.updateLine()
|
self.updateLine()
|
||||||
self.emit(QtCore.SIGNAL('positionChanged'), self)
|
#self.emit(QtCore.SIGNAL('positionChanged'), self)
|
||||||
|
self.sigPositionChanged.emit(self)
|
||||||
|
|
||||||
def getXPos(self):
|
def getXPos(self):
|
||||||
return self.p[0]
|
return self.p[0]
|
||||||
@ -2048,17 +2133,23 @@ class InfiniteLine(GraphicsObject):
|
|||||||
|
|
||||||
def mouseMoveEvent(self, ev):
|
def mouseMoveEvent(self, ev):
|
||||||
self.setPos(self.mapToParent(ev.pos()) - self.pressDelta)
|
self.setPos(self.mapToParent(ev.pos()) - self.pressDelta)
|
||||||
self.emit(QtCore.SIGNAL('dragged'), self)
|
#self.emit(QtCore.SIGNAL('dragged'), self)
|
||||||
|
self.sigDragged.emit(self)
|
||||||
self.hasMoved = True
|
self.hasMoved = True
|
||||||
|
|
||||||
def mouseReleaseEvent(self, ev):
|
def mouseReleaseEvent(self, ev):
|
||||||
if self.hasMoved and ev.button() == QtCore.Qt.LeftButton:
|
if self.hasMoved and ev.button() == QtCore.Qt.LeftButton:
|
||||||
self.hasMoved = False
|
self.hasMoved = False
|
||||||
self.emit(QtCore.SIGNAL('positionChangeFinished'), self)
|
#self.emit(QtCore.SIGNAL('positionChangeFinished'), self)
|
||||||
|
self.sigPositionChangeFinished.emit(self)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LinearRegionItem(GraphicsObject):
|
class LinearRegionItem(GraphicsObject):
|
||||||
|
|
||||||
|
sigRegionChangeFinished = QtCore.Signal(object)
|
||||||
|
sigRegionChanged = QtCore.Signal(object)
|
||||||
|
|
||||||
"""Used for marking a horizontal or vertical region in plots."""
|
"""Used for marking a horizontal or vertical region in plots."""
|
||||||
def __init__(self, view, orientation="vertical", vals=[0,1], brush=None, movable=True, bounds=None):
|
def __init__(self, view, orientation="vertical", vals=[0,1], brush=None, movable=True, bounds=None):
|
||||||
GraphicsObject.__init__(self)
|
GraphicsObject.__init__(self)
|
||||||
@ -2080,12 +2171,15 @@ class LinearRegionItem(GraphicsObject):
|
|||||||
self.lines = [
|
self.lines = [
|
||||||
InfiniteLine(view, QtCore.QPointF(vals[0], 0), 90, movable=movable, bounds=bounds),
|
InfiniteLine(view, QtCore.QPointF(vals[0], 0), 90, movable=movable, bounds=bounds),
|
||||||
InfiniteLine(view, QtCore.QPointF(vals[1], 0), 90, movable=movable, bounds=bounds)]
|
InfiniteLine(view, QtCore.QPointF(vals[1], 0), 90, movable=movable, bounds=bounds)]
|
||||||
QtCore.QObject.connect(self.view(), QtCore.SIGNAL('viewChanged'), self.updateBounds)
|
#QtCore.QObject.connect(self.view(), QtCore.SIGNAL('viewChanged'), self.updateBounds)
|
||||||
|
self.view().sigRangeChanged.connect(self.updateBounds)
|
||||||
|
|
||||||
for l in self.lines:
|
for l in self.lines:
|
||||||
l.setParentItem(self)
|
l.setParentItem(self)
|
||||||
l.connect(l, QtCore.SIGNAL('positionChangeFinished'), self.lineMoveFinished)
|
#l.connect(l, QtCore.SIGNAL('positionChangeFinished'), self.lineMoveFinished)
|
||||||
l.connect(l, QtCore.SIGNAL('positionChanged'), self.lineMoved)
|
l.sigPositionChangeFinished.connect(self.lineMoveFinished)
|
||||||
|
#l.connect(l, QtCore.SIGNAL('positionChanged'), self.lineMoved)
|
||||||
|
l.sigPositionChanged.connect(self.lineMoved)
|
||||||
|
|
||||||
if brush is None:
|
if brush is None:
|
||||||
brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 50))
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 50))
|
||||||
@ -2106,10 +2200,12 @@ class LinearRegionItem(GraphicsObject):
|
|||||||
|
|
||||||
def lineMoved(self):
|
def lineMoved(self):
|
||||||
self.updateBounds()
|
self.updateBounds()
|
||||||
self.emit(QtCore.SIGNAL('regionChanged'), self)
|
#self.emit(QtCore.SIGNAL('regionChanged'), self)
|
||||||
|
self.sigRegionChanged.emit(self)
|
||||||
|
|
||||||
def lineMoveFinished(self):
|
def lineMoveFinished(self):
|
||||||
self.emit(QtCore.SIGNAL('regionChangeFinished'), self)
|
#self.emit(QtCore.SIGNAL('regionChangeFinished'), self)
|
||||||
|
self.sigRegionChangeFinished.emit(self)
|
||||||
|
|
||||||
|
|
||||||
def updateBounds(self):
|
def updateBounds(self):
|
||||||
@ -2200,11 +2296,13 @@ class VTickGroup(QtGui.QGraphicsPathItem):
|
|||||||
if self.view is not None:
|
if self.view is not None:
|
||||||
if relative:
|
if relative:
|
||||||
#QtCore.QObject.connect(self.view, QtCore.SIGNAL('viewChanged'), self.rebuildTicks)
|
#QtCore.QObject.connect(self.view, QtCore.SIGNAL('viewChanged'), self.rebuildTicks)
|
||||||
QtCore.QObject.connect(self.view(), QtCore.SIGNAL('viewChanged'), self.rescale)
|
#QtCore.QObject.connect(self.view(), QtCore.SIGNAL('viewChanged'), self.rescale)
|
||||||
|
self.view().sigRangeChanged.connect(self.rescale)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
#QtCore.QObject.disconnect(self.view, QtCore.SIGNAL('viewChanged'), self.rebuildTicks)
|
#QtCore.QObject.disconnect(self.view, QtCore.SIGNAL('viewChanged'), self.rebuildTicks)
|
||||||
QtCore.QObject.disconnect(self.view(), QtCore.SIGNAL('viewChanged'), self.rescale)
|
#QtCore.QObject.disconnect(self.view(), QtCore.SIGNAL('viewChanged'), self.rescale)
|
||||||
|
self.view().sigRangeChanged.disconnect(self.rescale)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.rebuildTicks()
|
self.rebuildTicks()
|
||||||
@ -2268,6 +2366,8 @@ class VTickGroup(QtGui.QGraphicsPathItem):
|
|||||||
|
|
||||||
|
|
||||||
class GridItem(UIGraphicsItem):
|
class GridItem(UIGraphicsItem):
|
||||||
|
"""Class used to make square grids in plots. NOT the grid used for running scanner sequences."""
|
||||||
|
|
||||||
def __init__(self, view, bounds=None, *args):
|
def __init__(self, view, bounds=None, *args):
|
||||||
UIGraphicsItem.__init__(self, view, bounds)
|
UIGraphicsItem.__init__(self, view, bounds)
|
||||||
#QtGui.QGraphicsItem.__init__(self, *args)
|
#QtGui.QGraphicsItem.__init__(self, *args)
|
||||||
@ -2277,9 +2377,9 @@ class GridItem(UIGraphicsItem):
|
|||||||
self.picture = None
|
self.picture = None
|
||||||
|
|
||||||
|
|
||||||
def viewChangedEvent(self):
|
def viewRangeChanged(self):
|
||||||
self.picture = None
|
self.picture = None
|
||||||
UIGraphicsItem.viewChangedEvent(self)
|
UIGraphicsItem.viewRangeChanged(self)
|
||||||
#self.update()
|
#self.update()
|
||||||
|
|
||||||
def paint(self, p, opt, widget):
|
def paint(self, p, opt, widget):
|
||||||
@ -2417,7 +2517,20 @@ class ColorScaleBar(UIGraphicsItem):
|
|||||||
self.gradient = g
|
self.gradient = g
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
def setIntColorScale(self, minVal, maxVal, *args, **kargs):
|
||||||
|
colors = [intColor(i, maxVal-minVal, *args, **kargs) for i in range(minVal, maxVal)]
|
||||||
|
g = QtGui.QLinearGradient()
|
||||||
|
for i in range(len(colors)):
|
||||||
|
x = float(i)/len(colors)
|
||||||
|
g.setColorAt(x, colors[i])
|
||||||
|
self.setGradient(g)
|
||||||
|
if 'labels' not in kargs:
|
||||||
|
self.setLabels({str(minVal/10.): 0, str(maxVal): 1})
|
||||||
|
else:
|
||||||
|
self.setLabels({kargs['labels'][0]:0, kargs['labels'][1]:1})
|
||||||
|
|
||||||
def setLabels(self, l):
|
def setLabels(self, l):
|
||||||
|
"""Defines labels to appear next to the color scale"""
|
||||||
self.labels = l
|
self.labels = l
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
@ -2429,7 +2542,7 @@ class ColorScaleBar(UIGraphicsItem):
|
|||||||
labelWidth = 0
|
labelWidth = 0
|
||||||
labelHeight = 0
|
labelHeight = 0
|
||||||
for k in self.labels:
|
for k in self.labels:
|
||||||
b = p.boundingRect(QtCore.QRectF(0, 0, 0, 0), QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, k)
|
b = p.boundingRect(QtCore.QRectF(0, 0, 0, 0), QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, str(k))
|
||||||
labelWidth = max(labelWidth, b.width())
|
labelWidth = max(labelWidth, b.width())
|
||||||
labelHeight = max(labelHeight, b.height())
|
labelHeight = max(labelHeight, b.height())
|
||||||
|
|
||||||
@ -2484,6 +2597,6 @@ class ColorScaleBar(UIGraphicsItem):
|
|||||||
lh = labelHeight/unit.height()
|
lh = labelHeight/unit.height()
|
||||||
for k in self.labels:
|
for k in self.labels:
|
||||||
y = y1 + self.labels[k] * (y2-y1)
|
y = y1 + self.labels[k] * (y2-y1)
|
||||||
p.drawText(QtCore.QRectF(tx/unit.width(), y/unit.height() - lh/2.0, 1000, lh), QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, k)
|
p.drawText(QtCore.QRectF(tx/unit.width(), y/unit.height() - lh/2.0, 1000, lh), QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, str(k))
|
||||||
|
|
||||||
|
|
||||||
|
271
widgets.py
271
widgets.py
@ -16,7 +16,8 @@ from numpy.linalg import norm
|
|||||||
import scipy.ndimage as ndimage
|
import scipy.ndimage as ndimage
|
||||||
from Point import *
|
from Point import *
|
||||||
from math import cos, sin
|
from math import cos, sin
|
||||||
from ObjectWorkaround import *
|
import functions as fn
|
||||||
|
#from ObjectWorkaround import *
|
||||||
|
|
||||||
def rectStr(r):
|
def rectStr(r):
|
||||||
return "[%f, %f] + [%f, %f]" % (r.x(), r.y(), r.width(), r.height())
|
return "[%f, %f] + [%f, %f]" % (r.x(), r.y(), r.width(), r.height())
|
||||||
@ -33,10 +34,15 @@ def rectStr(r):
|
|||||||
#return QtCore.QObject.connect(self._qObj_, *args)
|
#return QtCore.QObject.connect(self._qObj_, *args)
|
||||||
|
|
||||||
|
|
||||||
class ROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
class ROI(QtGui.QGraphicsObject):
|
||||||
|
|
||||||
|
sigRegionChangeFinished = QtCore.Signal(object)
|
||||||
|
sigRegionChangeStarted = QtCore.Signal(object)
|
||||||
|
sigRegionChanged = QtCore.Signal(object)
|
||||||
|
|
||||||
def __init__(self, pos, size=Point(1, 1), angle=0.0, invertible=False, maxBounds=None, snapSize=1.0, scaleSnap=False, translateSnap=False, rotateSnap=False, parent=None, pen=None):
|
def __init__(self, pos, size=Point(1, 1), angle=0.0, invertible=False, maxBounds=None, snapSize=1.0, scaleSnap=False, translateSnap=False, rotateSnap=False, parent=None, pen=None):
|
||||||
QObjectWorkaround.__init__(self)
|
#QObjectWorkaround.__init__(self)
|
||||||
QtGui.QGraphicsItem.__init__(self, parent)
|
QtGui.QGraphicsObject.__init__(self, parent)
|
||||||
pos = Point(pos)
|
pos = Point(pos)
|
||||||
size = Point(size)
|
size = Point(size)
|
||||||
self.aspectLocked = False
|
self.aspectLocked = False
|
||||||
@ -45,7 +51,7 @@ class ROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
if pen is None:
|
if pen is None:
|
||||||
self.pen = QtGui.QPen(QtGui.QColor(255, 255, 255))
|
self.pen = QtGui.QPen(QtGui.QColor(255, 255, 255))
|
||||||
else:
|
else:
|
||||||
self.pen = pen
|
self.pen = fn.mkPen(pen)
|
||||||
self.handlePen = QtGui.QPen(QtGui.QColor(150, 255, 255))
|
self.handlePen = QtGui.QPen(QtGui.QColor(150, 255, 255))
|
||||||
self.handles = []
|
self.handles = []
|
||||||
self.state = {'pos': pos, 'size': size, 'angle': angle}
|
self.state = {'pos': pos, 'size': size, 'angle': angle}
|
||||||
@ -212,7 +218,8 @@ class ROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
self.isMoving = True
|
self.isMoving = True
|
||||||
self.preMoveState = self.getState()
|
self.preMoveState = self.getState()
|
||||||
self.cursorOffset = self.scenePos() - ev.scenePos()
|
self.cursorOffset = self.scenePos() - ev.scenePos()
|
||||||
self.emit(QtCore.SIGNAL('regionChangeStarted'), self)
|
#self.emit(QtCore.SIGNAL('regionChangeStarted'), self)
|
||||||
|
self.sigRegionChangeStarted.emit(self)
|
||||||
ev.accept()
|
ev.accept()
|
||||||
elif ev.button() == QtCore.Qt.RightButton:
|
elif ev.button() == QtCore.Qt.RightButton:
|
||||||
if self.isMoving:
|
if self.isMoving:
|
||||||
@ -236,7 +243,8 @@ class ROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
def mouseReleaseEvent(self, ev):
|
def mouseReleaseEvent(self, ev):
|
||||||
if self.translatable:
|
if self.translatable:
|
||||||
self.isMoving = False
|
self.isMoving = False
|
||||||
self.emit(QtCore.SIGNAL('regionChangeFinished'), self)
|
#self.emit(QtCore.SIGNAL('regionChangeFinished'), self)
|
||||||
|
self.sigRegionChangeFinished.emit(self)
|
||||||
|
|
||||||
def cancelMove(self):
|
def cancelMove(self):
|
||||||
self.isMoving = False
|
self.isMoving = False
|
||||||
@ -247,14 +255,16 @@ class ROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
self.isMoving = True
|
self.isMoving = True
|
||||||
self.preMoveState = self.getState()
|
self.preMoveState = self.getState()
|
||||||
|
|
||||||
self.emit(QtCore.SIGNAL('regionChangeStarted'), self)
|
#self.emit(QtCore.SIGNAL('regionChangeStarted'), self)
|
||||||
|
self.sigRegionChangeStarted.emit(self)
|
||||||
#self.pressPos = self.mapFromScene(ev.scenePos())
|
#self.pressPos = self.mapFromScene(ev.scenePos())
|
||||||
#self.pressHandlePos = self.handles[pt]['item'].pos()
|
#self.pressHandlePos = self.handles[pt]['item'].pos()
|
||||||
|
|
||||||
def pointReleaseEvent(self, pt, ev):
|
def pointReleaseEvent(self, pt, ev):
|
||||||
#print "release"
|
#print "release"
|
||||||
self.isMoving = False
|
self.isMoving = False
|
||||||
self.emit(QtCore.SIGNAL('regionChangeFinished'), self)
|
#self.emit(QtCore.SIGNAL('regionChangeFinished'), self)
|
||||||
|
self.sigRegionChangeFinished.emit(self)
|
||||||
|
|
||||||
def stateCopy(self):
|
def stateCopy(self):
|
||||||
sc = {}
|
sc = {}
|
||||||
@ -316,7 +326,8 @@ class ROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
|
|
||||||
elif h['type'] == 'f':
|
elif h['type'] == 'f':
|
||||||
h['item'].setPos(self.mapFromScene(pos))
|
h['item'].setPos(self.mapFromScene(pos))
|
||||||
self.emit(QtCore.SIGNAL('regionChanged'), self)
|
#self.emit(QtCore.SIGNAL('regionChanged'), self)
|
||||||
|
self.sigRegionChanged.emit(self)
|
||||||
|
|
||||||
elif h['type'] == 's':
|
elif h['type'] == 's':
|
||||||
#c = h['center']
|
#c = h['center']
|
||||||
@ -509,7 +520,8 @@ class ROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
if changed:
|
if changed:
|
||||||
#print "handle changed."
|
#print "handle changed."
|
||||||
self.update()
|
self.update()
|
||||||
self.emit(QtCore.SIGNAL('regionChanged'), self)
|
#self.emit(QtCore.SIGNAL('regionChanged'), self)
|
||||||
|
self.sigRegionChanged.emit(self)
|
||||||
|
|
||||||
|
|
||||||
def scale(self, s, center=[0,0]):
|
def scale(self, s, center=[0,0]):
|
||||||
@ -628,104 +640,116 @@ class ROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
|
|
||||||
|
|
||||||
def getArrayRegion(self, data, img, axes=(0,1)):
|
def getArrayRegion(self, data, img, axes=(0,1)):
|
||||||
|
shape = self.state['size']
|
||||||
|
|
||||||
## transpose data so x and y are the first 2 axes
|
origin = self.mapToItem(img, QtCore.QPointF(0, 0))
|
||||||
trAx = range(0, data.ndim)
|
|
||||||
trAx.remove(axes[0])
|
|
||||||
trAx.remove(axes[1])
|
|
||||||
tr1 = tuple(axes) + tuple(trAx)
|
|
||||||
arr = data.transpose(tr1)
|
|
||||||
|
|
||||||
## Determine the minimal area of the data we will need
|
vx = self.mapToItem(img, QtCore.QPointF(1, 0)) - origin
|
||||||
(dataBounds, roiDataTransform) = self.getArraySlice(data, img, returnSlice=False, axes=axes)
|
vy = self.mapToItem(img, QtCore.QPointF(0, 1)) - origin
|
||||||
|
vectors = ((vx.x(), vx.y()), (vy.x(), vy.y()))
|
||||||
|
origin = (origin.x(), origin.y())
|
||||||
|
|
||||||
|
#print "shape", shape, "vectors", vectors, "origin", origin
|
||||||
|
|
||||||
|
return fn.affineSlice(data, shape=shape, vectors=vectors, origin=origin, axes=axes, order=1)
|
||||||
|
|
||||||
|
### transpose data so x and y are the first 2 axes
|
||||||
|
#trAx = range(0, data.ndim)
|
||||||
|
#trAx.remove(axes[0])
|
||||||
|
#trAx.remove(axes[1])
|
||||||
|
#tr1 = tuple(axes) + tuple(trAx)
|
||||||
|
#arr = data.transpose(tr1)
|
||||||
|
|
||||||
|
### Determine the minimal area of the data we will need
|
||||||
|
#(dataBounds, roiDataTransform) = self.getArraySlice(data, img, returnSlice=False, axes=axes)
|
||||||
|
|
||||||
## Pad data boundaries by 1px if possible
|
### Pad data boundaries by 1px if possible
|
||||||
dataBounds = (
|
#dataBounds = (
|
||||||
(max(dataBounds[0][0]-1, 0), min(dataBounds[0][1]+1, arr.shape[0])),
|
#(max(dataBounds[0][0]-1, 0), min(dataBounds[0][1]+1, arr.shape[0])),
|
||||||
(max(dataBounds[1][0]-1, 0), min(dataBounds[1][1]+1, arr.shape[1]))
|
#(max(dataBounds[1][0]-1, 0), min(dataBounds[1][1]+1, arr.shape[1]))
|
||||||
)
|
#)
|
||||||
|
|
||||||
## Extract minimal data from array
|
### Extract minimal data from array
|
||||||
arr1 = arr[dataBounds[0][0]:dataBounds[0][1], dataBounds[1][0]:dataBounds[1][1]]
|
#arr1 = arr[dataBounds[0][0]:dataBounds[0][1], dataBounds[1][0]:dataBounds[1][1]]
|
||||||
|
|
||||||
## Update roiDataTransform to reflect this extraction
|
### Update roiDataTransform to reflect this extraction
|
||||||
roiDataTransform *= QtGui.QTransform().translate(-dataBounds[0][0], -dataBounds[1][0])
|
#roiDataTransform *= QtGui.QTransform().translate(-dataBounds[0][0], -dataBounds[1][0])
|
||||||
### (roiDataTransform now maps from ROI coords to extracted data coords)
|
#### (roiDataTransform now maps from ROI coords to extracted data coords)
|
||||||
|
|
||||||
|
|
||||||
## Rotate array
|
### Rotate array
|
||||||
if abs(self.state['angle']) > 1e-5:
|
#if abs(self.state['angle']) > 1e-5:
|
||||||
arr2 = ndimage.rotate(arr1, self.state['angle'] * 180 / np.pi, order=1)
|
#arr2 = ndimage.rotate(arr1, self.state['angle'] * 180 / np.pi, order=1)
|
||||||
|
|
||||||
## update data transforms to reflect this rotation
|
### update data transforms to reflect this rotation
|
||||||
rot = QtGui.QTransform().rotate(self.state['angle'] * 180 / np.pi)
|
#rot = QtGui.QTransform().rotate(self.state['angle'] * 180 / np.pi)
|
||||||
roiDataTransform *= rot
|
#roiDataTransform *= rot
|
||||||
|
|
||||||
## The rotation also causes a shift which must be accounted for:
|
### The rotation also causes a shift which must be accounted for:
|
||||||
dataBound = QtCore.QRectF(0, 0, arr1.shape[0], arr1.shape[1])
|
#dataBound = QtCore.QRectF(0, 0, arr1.shape[0], arr1.shape[1])
|
||||||
rotBound = rot.mapRect(dataBound)
|
#rotBound = rot.mapRect(dataBound)
|
||||||
roiDataTransform *= QtGui.QTransform().translate(-rotBound.left(), -rotBound.top())
|
#roiDataTransform *= QtGui.QTransform().translate(-rotBound.left(), -rotBound.top())
|
||||||
|
|
||||||
else:
|
#else:
|
||||||
arr2 = arr1
|
#arr2 = arr1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Shift off partial pixels
|
#### Shift off partial pixels
|
||||||
# 1. map ROI into current data space
|
## 1. map ROI into current data space
|
||||||
roiBounds = roiDataTransform.mapRect(self.boundingRect())
|
#roiBounds = roiDataTransform.mapRect(self.boundingRect())
|
||||||
|
|
||||||
# 2. Determine amount to shift data
|
## 2. Determine amount to shift data
|
||||||
shift = (int(roiBounds.left()) - roiBounds.left(), int(roiBounds.bottom()) - roiBounds.bottom())
|
#shift = (int(roiBounds.left()) - roiBounds.left(), int(roiBounds.bottom()) - roiBounds.bottom())
|
||||||
if abs(shift[0]) > 1e-6 or abs(shift[1]) > 1e-6:
|
#if abs(shift[0]) > 1e-6 or abs(shift[1]) > 1e-6:
|
||||||
# 3. pad array with 0s before shifting
|
## 3. pad array with 0s before shifting
|
||||||
arr2a = np.zeros((arr2.shape[0]+2, arr2.shape[1]+2) + arr2.shape[2:], dtype=arr2.dtype)
|
#arr2a = np.zeros((arr2.shape[0]+2, arr2.shape[1]+2) + arr2.shape[2:], dtype=arr2.dtype)
|
||||||
arr2a[1:-1, 1:-1] = arr2
|
#arr2a[1:-1, 1:-1] = arr2
|
||||||
|
|
||||||
# 4. shift array and udpate transforms
|
## 4. shift array and udpate transforms
|
||||||
arr3 = ndimage.shift(arr2a, shift + (0,)*(arr2.ndim-2), order=1)
|
#arr3 = ndimage.shift(arr2a, shift + (0,)*(arr2.ndim-2), order=1)
|
||||||
roiDataTransform *= QtGui.QTransform().translate(1+shift[0], 1+shift[1])
|
#roiDataTransform *= QtGui.QTransform().translate(1+shift[0], 1+shift[1])
|
||||||
else:
|
#else:
|
||||||
arr3 = arr2
|
#arr3 = arr2
|
||||||
|
|
||||||
|
|
||||||
### Extract needed region from rotated/shifted array
|
#### Extract needed region from rotated/shifted array
|
||||||
# 1. map ROI into current data space (round these values off--they should be exact integer values at this point)
|
## 1. map ROI into current data space (round these values off--they should be exact integer values at this point)
|
||||||
roiBounds = roiDataTransform.mapRect(self.boundingRect())
|
#roiBounds = roiDataTransform.mapRect(self.boundingRect())
|
||||||
#print self, roiBounds.height()
|
##print self, roiBounds.height()
|
||||||
#import traceback
|
##import traceback
|
||||||
#traceback.print_stack()
|
##traceback.print_stack()
|
||||||
|
|
||||||
roiBounds = QtCore.QRect(round(roiBounds.left()), round(roiBounds.top()), round(roiBounds.width()), round(roiBounds.height()))
|
#roiBounds = QtCore.QRect(round(roiBounds.left()), round(roiBounds.top()), round(roiBounds.width()), round(roiBounds.height()))
|
||||||
|
|
||||||
#2. intersect ROI with data bounds
|
##2. intersect ROI with data bounds
|
||||||
dataBounds = roiBounds.intersect(QtCore.QRect(0, 0, arr3.shape[0], arr3.shape[1]))
|
#dataBounds = roiBounds.intersect(QtCore.QRect(0, 0, arr3.shape[0], arr3.shape[1]))
|
||||||
|
|
||||||
#3. Extract data from array
|
##3. Extract data from array
|
||||||
db = dataBounds
|
#db = dataBounds
|
||||||
bounds = (
|
#bounds = (
|
||||||
(db.left(), db.right()+1),
|
#(db.left(), db.right()+1),
|
||||||
(db.top(), db.bottom()+1)
|
#(db.top(), db.bottom()+1)
|
||||||
)
|
#)
|
||||||
arr4 = arr3[bounds[0][0]:bounds[0][1], bounds[1][0]:bounds[1][1]]
|
#arr4 = arr3[bounds[0][0]:bounds[0][1], bounds[1][0]:bounds[1][1]]
|
||||||
|
|
||||||
### Create zero array in size of ROI
|
#### Create zero array in size of ROI
|
||||||
arr5 = np.zeros((roiBounds.width(), roiBounds.height()) + arr4.shape[2:], dtype=arr4.dtype)
|
#arr5 = np.zeros((roiBounds.width(), roiBounds.height()) + arr4.shape[2:], dtype=arr4.dtype)
|
||||||
|
|
||||||
## Fill array with ROI data
|
### Fill array with ROI data
|
||||||
orig = Point(dataBounds.topLeft() - roiBounds.topLeft())
|
#orig = Point(dataBounds.topLeft() - roiBounds.topLeft())
|
||||||
subArr = arr5[orig[0]:orig[0]+arr4.shape[0], orig[1]:orig[1]+arr4.shape[1]]
|
#subArr = arr5[orig[0]:orig[0]+arr4.shape[0], orig[1]:orig[1]+arr4.shape[1]]
|
||||||
subArr[:] = arr4[:subArr.shape[0], :subArr.shape[1]]
|
#subArr[:] = arr4[:subArr.shape[0], :subArr.shape[1]]
|
||||||
|
|
||||||
|
|
||||||
## figure out the reverse transpose order
|
### figure out the reverse transpose order
|
||||||
tr2 = np.array(tr1)
|
#tr2 = np.array(tr1)
|
||||||
for i in range(0, len(tr2)):
|
#for i in range(0, len(tr2)):
|
||||||
tr2[tr1[i]] = i
|
#tr2[tr1[i]] = i
|
||||||
tr2 = tuple(tr2)
|
#tr2 = tuple(tr2)
|
||||||
|
|
||||||
## Untranspose array before returning
|
### Untranspose array before returning
|
||||||
return arr5.transpose(tr2)
|
#return arr5.transpose(tr2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -887,10 +911,14 @@ class LineROI(ROI):
|
|||||||
self.addScaleHandle([0.5, 1], [0.5, 0.5])
|
self.addScaleHandle([0.5, 1], [0.5, 0.5])
|
||||||
|
|
||||||
|
|
||||||
class MultiLineROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
class MultiLineROI(QtGui.QGraphicsObject):
|
||||||
|
|
||||||
|
sigRegionChangeFinished = QtCore.Signal(object)
|
||||||
|
sigRegionChangeStarted = QtCore.Signal(object)
|
||||||
|
sigRegionChanged = QtCore.Signal(object)
|
||||||
|
|
||||||
def __init__(self, points, width, pen=None, **args):
|
def __init__(self, points, width, pen=None, **args):
|
||||||
QObjectWorkaround.__init__(self)
|
QtGui.QGraphicsObject.__init__(self)
|
||||||
QtGui.QGraphicsItem.__init__(self)
|
|
||||||
self.pen = pen
|
self.pen = pen
|
||||||
self.roiArgs = args
|
self.roiArgs = args
|
||||||
if len(points) < 2:
|
if len(points) < 2:
|
||||||
@ -912,9 +940,12 @@ class MultiLineROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
for l in self.lines:
|
for l in self.lines:
|
||||||
l.translatable = False
|
l.translatable = False
|
||||||
#self.addToGroup(l)
|
#self.addToGroup(l)
|
||||||
l.connect(l, QtCore.SIGNAL('regionChanged'), self.roiChangedEvent)
|
#l.connect(l, QtCore.SIGNAL('regionChanged'), self.roiChangedEvent)
|
||||||
l.connect(l, QtCore.SIGNAL('regionChangeStarted'), self.roiChangeStartedEvent)
|
l.sigRegionChanged.connect(self.roiChangedEvent)
|
||||||
l.connect(l, QtCore.SIGNAL('regionChangeFinished'), self.roiChangeFinishedEvent)
|
#l.connect(l, QtCore.SIGNAL('regionChangeStarted'), self.roiChangeStartedEvent)
|
||||||
|
l.sigRegionChangeStarted.connect(self.roiChangeStartedEvent)
|
||||||
|
#l.connect(l, QtCore.SIGNAL('regionChangeFinished'), self.roiChangeFinishedEvent)
|
||||||
|
l.sigRegionChangeFinished.connect(self.roiChangeFinishedEvent)
|
||||||
|
|
||||||
def paint(self, *args):
|
def paint(self, *args):
|
||||||
pass
|
pass
|
||||||
@ -927,13 +958,16 @@ class MultiLineROI(QtGui.QGraphicsItem, QObjectWorkaround):
|
|||||||
for l in self.lines[1:]:
|
for l in self.lines[1:]:
|
||||||
w0 = l.state['size'][1]
|
w0 = l.state['size'][1]
|
||||||
l.scale([1.0, w/w0], center=[0.5,0.5])
|
l.scale([1.0, w/w0], center=[0.5,0.5])
|
||||||
self.emit(QtCore.SIGNAL('regionChanged'), self)
|
#self.emit(QtCore.SIGNAL('regionChanged'), self)
|
||||||
|
self.sigRegionChanged.emit(self)
|
||||||
|
|
||||||
def roiChangeStartedEvent(self):
|
def roiChangeStartedEvent(self):
|
||||||
self.emit(QtCore.SIGNAL('regionChangeStarted'), self)
|
#self.emit(QtCore.SIGNAL('regionChangeStarted'), self)
|
||||||
|
self.sigRegionChangeStarted.emit(self)
|
||||||
|
|
||||||
def roiChangeFinishedEvent(self):
|
def roiChangeFinishedEvent(self):
|
||||||
self.emit(QtCore.SIGNAL('regionChangeFinished'), self)
|
#self.emit(QtCore.SIGNAL('regionChangeFinished'), self)
|
||||||
|
self.sigRegionChangeFinished.emit(self)
|
||||||
|
|
||||||
|
|
||||||
def getArrayRegion(self, arr, img=None):
|
def getArrayRegion(self, arr, img=None):
|
||||||
@ -1037,7 +1071,58 @@ class PolygonROI(ROI):
|
|||||||
sc['angle'] = self.state['angle']
|
sc['angle'] = self.state['angle']
|
||||||
#sc['handles'] = self.handles
|
#sc['handles'] = self.handles
|
||||||
return sc
|
return sc
|
||||||
|
|
||||||
|
|
||||||
|
class LineSegmentROI(ROI):
|
||||||
|
def __init__(self, positions, pos=None, **args):
|
||||||
|
if pos is None:
|
||||||
|
pos = [0,0]
|
||||||
|
ROI.__init__(self, pos, [1,1], **args)
|
||||||
|
#ROI.__init__(self, positions[0])
|
||||||
|
for p in positions:
|
||||||
|
self.addFreeHandle(p)
|
||||||
|
self.setZValue(1000)
|
||||||
|
|
||||||
|
def listPoints(self):
|
||||||
|
return [p['item'].pos() for p in self.handles]
|
||||||
|
|
||||||
|
def movePoint(self, *args, **kargs):
|
||||||
|
ROI.movePoint(self, *args, **kargs)
|
||||||
|
self.prepareGeometryChange()
|
||||||
|
for h in self.handles:
|
||||||
|
h['pos'] = h['item'].pos()
|
||||||
|
|
||||||
|
def paint(self, p, *args):
|
||||||
|
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||||
|
p.setPen(self.pen)
|
||||||
|
for i in range(len(self.handles)-1):
|
||||||
|
h1 = self.handles[i]['item'].pos()
|
||||||
|
h2 = self.handles[i-1]['item'].pos()
|
||||||
|
p.drawLine(h1, h2)
|
||||||
|
|
||||||
|
def boundingRect(self):
|
||||||
|
r = QtCore.QRectF()
|
||||||
|
for h in self.handles:
|
||||||
|
r |= self.mapFromItem(h['item'], h['item'].boundingRect()).boundingRect() ## |= gives the union of the two QRectFs
|
||||||
|
return r
|
||||||
|
|
||||||
|
def shape(self):
|
||||||
|
p = QtGui.QPainterPath()
|
||||||
|
p.moveTo(self.handles[0]['item'].pos())
|
||||||
|
for i in range(len(self.handles)):
|
||||||
|
p.lineTo(self.handles[i]['item'].pos())
|
||||||
|
return p
|
||||||
|
|
||||||
|
def stateCopy(self):
|
||||||
|
sc = {}
|
||||||
|
sc['pos'] = Point(self.state['pos'])
|
||||||
|
sc['size'] = Point(self.state['size'])
|
||||||
|
sc['angle'] = self.state['angle']
|
||||||
|
#sc['handles'] = self.handles
|
||||||
|
return sc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SpiralROI(ROI):
|
class SpiralROI(ROI):
|
||||||
def __init__(self, pos=None, size=None, **args):
|
def __init__(self, pos=None, size=None, **args):
|
||||||
if size == None:
|
if size == None:
|
||||||
|
Loading…
Reference in New Issue
Block a user