merged many changes in from acq4:

- added vertical lines / regions for plots
 - added gradient editor widget
 - many bugfixes
 - cleaned up imageview a bit
This commit is contained in:
Luke Campagnola 2010-07-24 14:29:09 -04:00
parent 7efc975400
commit 2ca08c69ce
18 changed files with 2811 additions and 1384 deletions

364
GradientWidget.py Normal file
View File

@ -0,0 +1,364 @@
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
class TickSlider(QtGui.QGraphicsView):
def __init__(self, parent=None, orientation='bottom', allowAdd=True, **kargs):
QtGui.QGraphicsView.__init__(self, parent)
#self.orientation = orientation
self.allowAdd = allowAdd
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setTransformationAnchor(QtGui.QGraphicsView.NoAnchor)
self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)
self.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing)
self.length = 100
self.tickSize = 15
self.orientations = {
'left': (270, 1, -1),
'right': (270, 1, 1),
'top': (0, 1, -1),
'bottom': (0, 1, 1)
}
self.scene = QtGui.QGraphicsScene()
self.setScene(self.scene)
self.ticks = {}
self.maxDim = 20
self.setOrientation(orientation)
self.setFrameStyle(QtGui.QFrame.NoFrame | QtGui.QFrame.Plain)
self.setBackgroundRole(QtGui.QPalette.NoRole)
self.setMouseTracking(True)
def keyPressEvent(self, ev):
ev.ignore()
def setMaxDim(self, mx=None):
if mx is None:
mx = self.maxDim
else:
self.maxDim = mx
if self.orientation in ['bottom', 'top']:
self.setFixedHeight(mx)
self.setMaximumWidth(16777215)
else:
self.setFixedWidth(mx)
self.setMaximumHeight(16777215)
def setOrientation(self, ort):
self.orientation = ort
self.resetTransform()
self.rotate(self.orientations[ort][0])
self.scale(*self.orientations[ort][1:])
self.setMaxDim()
def addTick(self, x, color=None, movable=True):
if color is None:
color = QtGui.QColor(255,255,255)
tick = Tick(self, [x*self.length, 0], color, movable, self.tickSize)
self.ticks[tick] = x
self.scene.addItem(tick)
return tick
def removeTick(self, tick):
del self.ticks[tick]
self.scene.removeItem(tick)
def tickMoved(self, tick, pos):
#print "tick changed"
## Correct position of tick if it has left bounds.
newX = min(max(0, pos.x()), self.length)
pos.setX(newX)
tick.setPos(pos)
self.ticks[tick] = float(newX) / self.length
def tickClicked(self, tick, ev):
if ev.button() == QtCore.Qt.RightButton:
self.removeTick(tick)
def widgetLength(self):
if self.orientation in ['bottom', 'top']:
return self.width()
else:
return self.height()
def resizeEvent(self, ev):
wlen = max(40, self.widgetLength())
self.setLength(wlen-self.tickSize)
bounds = self.scene.itemsBoundingRect()
bounds.setLeft(min(-self.tickSize*0.5, bounds.left()))
bounds.setRight(max(self.length + self.tickSize, bounds.right()))
#bounds.setTop(min(bounds.top(), self.tickSize))
#bounds.setBottom(max(0, bounds.bottom()))
self.setSceneRect(bounds)
self.fitInView(bounds, QtCore.Qt.KeepAspectRatio)
def setLength(self, newLen):
for t, x in self.ticks.items():
t.setPos(x * newLen, t.pos().y())
self.length = float(newLen)
def mousePressEvent(self, ev):
QtGui.QGraphicsView.mousePressEvent(self, ev)
self.ignoreRelease = False
if len(self.items(ev.pos())) > 0: ## Let items handle their own clicks
self.ignoreRelease = True
def mouseReleaseEvent(self, ev):
QtGui.QGraphicsView.mouseReleaseEvent(self, ev)
if self.ignoreRelease:
return
pos = self.mapToScene(ev.pos())
if pos.x() < 0 or pos.x() > self.length:
return
if pos.y() < 0 or pos.y() > self.tickSize:
return
if ev.button() == QtCore.Qt.LeftButton and self.allowAdd:
pos.setX(min(max(pos.x(), 0), self.length))
self.addTick(pos.x()/self.length)
elif ev.button() == QtCore.Qt.RightButton:
self.showMenu(ev)
def showMenu(self, ev):
pass
def setTickColor(self, tick, color):
tick = self.getTick(tick)
tick.color = color
tick.setBrush(QtGui.QBrush(QtGui.QColor(tick.color)))
def setTickValue(self, tick, val):
tick = self.getTick(tick)
val = min(max(0.0, val), 1.0)
x = val * self.length
pos = tick.pos()
pos.setX(x)
tick.setPos(pos)
self.ticks[tick] = val
def tickValue(self, tick):
tick = self.getTick(tick)
return self.ticks[tick]
def getTick(self, tick):
if type(tick) is int:
tick = self.listTicks()[tick][0]
return tick
def mouseMoveEvent(self, ev):
QtGui.QGraphicsView.mouseMoveEvent(self, ev)
#print ev.pos(), ev.buttons()
def listTicks(self):
ticks = self.ticks.items()
ticks.sort(lambda a,b: cmp(a[1], b[1]))
return ticks
class GradientWidget(TickSlider):
def __init__(self, *args, **kargs):
TickSlider.__init__(self, *args, **kargs)
self.rectSize = 15
self.gradRect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, -self.rectSize, 100, self.rectSize))
self.colorMode = 'rgb'
#self.gradient = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(100,0))
self.scene.addItem(self.gradRect)
self.addTick(0, QtGui.QColor(0,0,0), True)
self.addTick(1, QtGui.QColor(255,0,0), True)
self.setMaxDim(self.rectSize + self.tickSize)
self.updateGradient()
#self.btn = QtGui.QPushButton('RGB')
#self.btnProxy = self.scene.addWidget(self.btn)
#self.btnProxy.setFlag(self.btnProxy.ItemIgnoresTransformations)
#self.btnProxy.scale(0.7, 0.7)
#self.btnProxy.translate(-self.btnProxy.sceneBoundingRect().width()+self.tickSize/2., 0)
#if self.orientation == 'bottom':
#self.btnProxy.translate(0, -self.rectSize)
def setColorMode(self, cm):
if cm not in ['rgb', 'hsv']:
raise Exception("Unknown color mode %s" % str(cm))
self.colorMode = cm
self.updateGradient()
def updateGradient(self):
self.gradient = self.getGradient()
self.gradRect.setBrush(QtGui.QBrush(self.gradient))
self.emit(QtCore.SIGNAL('gradientChanged'), self)
def setLength(self, newLen):
TickSlider.setLength(self, newLen)
self.gradRect.setRect(0, -self.rectSize, newLen, self.rectSize)
self.updateGradient()
def tickClicked(self, tick, ev):
if ev.button() == QtCore.Qt.LeftButton:
if not tick.colorChangeAllowed:
return
color = QtGui.QColorDialog.getColor(tick.color, None, "Select Color", QtGui.QColorDialog.ShowAlphaChannel)
if color.isValid():
self.setTickColor(tick, color)
self.updateGradient()
elif ev.button() == QtCore.Qt.RightButton:
if not tick.removeAllowed:
return
if len(self.ticks) > 2:
self.removeTick(tick)
self.updateGradient()
def tickMoved(self, tick, pos):
TickSlider.tickMoved(self, tick, pos)
self.updateGradient()
def getGradient(self):
g = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(self.length,0))
if self.colorMode == 'rgb':
ticks = self.listTicks()
g.setStops([(x, QtGui.QColor(t.color)) for t,x in ticks])
elif self.colorMode == 'hsv': ## HSV mode is approximated for display by interpolating 10 points between each stop
ticks = self.listTicks()
stops = []
stops.append((ticks[0][1], ticks[0][0].color))
for i in range(1,len(ticks)):
x1 = ticks[i-1][1]
x2 = ticks[i][1]
dx = (x2-x1) / 10.
for j in range(1,10):
x = x1 + dx*j
stops.append((x, self.getColor(x)))
stops.append((x2, self.getColor(x2)))
g.setStops(stops)
return g
def getColor(self, x):
ticks = self.listTicks()
if x <= ticks[0][1]:
return QtGui.QColor(ticks[0][0].color) # always copy colors before handing them out
if x >= ticks[-1][1]:
return QtGui.QColor(ticks[-1][0].color)
x2 = ticks[0][1]
for i in range(1,len(ticks)):
x1 = x2
x2 = ticks[i][1]
if x1 <= x and x2 >= x:
break
dx = (x2-x1)
if dx == 0:
f = 0.
else:
f = (x-x1) / dx
c1 = ticks[i-1][0].color
c2 = ticks[i][0].color
if self.colorMode == 'rgb':
r = c1.red() * (1.-f) + c2.red() * f
g = c1.green() * (1.-f) + c2.green() * f
b = c1.blue() * (1.-f) + c2.blue() * f
return QtGui.QColor(r, g, b)
elif self.colorMode == 'hsv':
h1,s1,v1,_ = c1.getHsv()
h2,s2,v2,_ = c2.getHsv()
h = h1 * (1.-f) + h2 * f
s = s1 * (1.-f) + s2 * f
v = v1 * (1.-f) + v2 * f
c = QtGui.QColor()
c.setHsv(h,s,v)
return c
def mouseReleaseEvent(self, ev):
TickSlider.mouseReleaseEvent(self, ev)
self.updateGradient()
def addTick(self, x, color=None, movable=True):
if color is None:
color = self.getColor(x)
t = TickSlider.addTick(self, x, color=color, movable=movable)
t.colorChangeAllowed = True
t.removeAllowed = True
return t
class GammaWidget(TickSlider):
pass
class Tick(QtGui.QGraphicsPolygonItem):
def __init__(self, view, pos, color, movable=True, scale=10):
#QObjectWorkaround.__init__(self)
self.movable = movable
self.view = view
self.scale = scale
self.color = color
#self.endTick = endTick
self.pg = QtGui.QPolygonF([QtCore.QPointF(0,0), QtCore.QPointF(-scale/3**0.5,scale), QtCore.QPointF(scale/3**0.5,scale)])
QtGui.QGraphicsPolygonItem.__init__(self, self.pg)
self.setPos(pos[0], pos[1])
self.setFlags(QtGui.QGraphicsItem.ItemIsMovable | QtGui.QGraphicsItem.ItemIsSelectable)
self.setBrush(QtGui.QBrush(QtGui.QColor(self.color)))
if self.movable:
self.setZValue(1)
else:
self.setZValue(0)
#def x(self):
#return self.pos().x()/100.
def mouseMoveEvent(self, ev):
#print self, "move", ev.scenePos()
if not self.movable:
return
if not ev.buttons() & QtCore.Qt.LeftButton:
return
newPos = ev.scenePos() + self.mouseOffset
newPos.setY(self.pos().y())
#newPos.setX(min(max(newPos.x(), 0), 100))
self.setPos(newPos)
self.view.tickMoved(self, newPos)
self.movedSincePress = True
#self.emit(QtCore.SIGNAL('tickChanged'), self)
ev.accept()
def mousePressEvent(self, ev):
self.movedSincePress = False
if ev.button() == QtCore.Qt.LeftButton:
ev.accept()
self.mouseOffset = self.pos() - ev.scenePos()
self.pressPos = ev.scenePos()
elif ev.button() == QtCore.Qt.RightButton:
ev.accept()
#if self.endTick:
#return
#self.view.tickChanged(self, delete=True)
def mouseReleaseEvent(self, ev):
#print self, "release", ev.scenePos()
if not self.movedSincePress:
self.view.tickClicked(self, ev)
#if ev.button() == QtCore.Qt.LeftButton and ev.scenePos() == self.pressPos:
#color = QtGui.QColorDialog.getColor(self.color, None, "Select Color", QtGui.QColorDialog.ShowAlphaChannel)
#if color.isValid():
#self.color = color
#self.setBrush(QtGui.QBrush(QtGui.QColor(self.color)))
##self.emit(QtCore.SIGNAL('tickChanged'), self)
#self.view.tickChanged(self)

26
GradientWidgetTest.py Normal file
View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from GradientWidget import *
from PyQt4 import QtGui
app = QtGui.QApplication([])
w = QtGui.QMainWindow()
w.show()
w.resize(400,400)
cw = QtGui.QWidget()
w.setCentralWidget(cw)
l = QtGui.QGridLayout()
l.setSpacing(0)
cw.setLayout(l)
w1 = GradientWidget(orientation='top')
w2 = GradientWidget(orientation='right', allowAdd=False)
w2.setTickColor(1, QtGui.QColor(255,255,255))
w3 = GradientWidget(orientation='bottom')
w4 = TickSlider(orientation='left')
l.addWidget(w1, 0, 1)
l.addWidget(w2, 1, 2)
l.addWidget(w3, 2, 1)
l.addWidget(w4, 1, 0)

View File

@ -10,11 +10,11 @@ from PyQt4 import QtCore, QtGui, QtOpenGL, QtSvg
#import time
from Point import *
#from vector import *
import sys
class GraphicsView(QtGui.QGraphicsView):
def __init__(self, *args):
def __init__(self, parent=None, useOpenGL=True):
"""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
that is automatically scaled to the full view geometry.
@ -26,8 +26,9 @@ class GraphicsView(QtGui.QGraphicsView):
The view can be panned using the middle mouse button and scaled using the right mouse button if
enabled via enableMouse()."""
QtGui.QGraphicsView.__init__(self, *args)
self.setViewport(QtOpenGL.QGLWidget())
QtGui.QGraphicsView.__init__(self, parent)
self.useOpenGL(useOpenGL)
palette = QtGui.QPalette()
brush = QtGui.QBrush(QtGui.QColor(0,0,0))
brush.setStyle(QtCore.Qt.SolidPattern)
@ -49,6 +50,7 @@ class GraphicsView(QtGui.QGraphicsView):
#self.setResizeAnchor(QtGui.QGraphicsView.NoAnchor)
self.setViewportUpdateMode(QtGui.QGraphicsView.SmartViewportUpdate)
self.setSceneRect(QtCore.QRectF(-1e10, -1e10, 2e10, 2e10))
#self.setSceneRect(1, 1, 0, 0) ## Set an empty (but non-zero) scene rect so that the view doesn't try to automatically update for us.
#self.setInteractive(False)
self.lockedViewports = []
self.lastMousePos = None
@ -68,6 +70,18 @@ class GraphicsView(QtGui.QGraphicsView):
self.scaleCenter = False ## should scaling center around view center (True) or mouse click (False)
self.clickAccepted = False
def useOpenGL(self, b=True):
if b:
v = QtOpenGL.QGLWidget()
else:
v = QtGui.QWidget()
#v.setStyleSheet("background-color: #000000;")
self.setViewport(v)
def keyPressEvent(self, ev):
ev.ignore()
def setCentralItem(self, item):
if self.centralWidget is not None:
self.scene().removeItem(self.centralWidget)
@ -77,6 +91,9 @@ class GraphicsView(QtGui.QGraphicsView):
def addItem(self, *args):
return self.scene().addItem(*args)
def removeItem(self, *args):
return self.scene().removeItem(*args)
def enableMouse(self, b=True):
self.mouseEnabled = b
self.autoPixelRange = (not b)
@ -128,6 +145,8 @@ class GraphicsView(QtGui.QGraphicsView):
v.setXRange(self.range, padding=0)
def visibleRange(self):
"""Return the boundaries of the view in scene coordinates"""
## easier to just return self.range ?
r = QtCore.QRectF(self.rect())
return self.viewportTransform().inverted()[0].mapRect(r)
@ -347,6 +366,16 @@ class GraphicsView(QtGui.QGraphicsView):
self.setRenderHints(rh)
self.png.save(fileName)
def writePs(self, fileName=None):
if fileName is None:
fileName = str(QtGui.QFileDialog.getSaveFileName())
printer = QtGui.QPrinter(QtGui.QPrinter.HighResolution)
printer.setOutputFileName(fileName)
painter = QtGui.QPainter(printer)
self.render(painter)
painter.end()
#def getFreehandLine(self):
## Wait for click

View File

@ -17,6 +17,11 @@ from ImageViewTemplate import *
from graphicsItems import *
from widgets import ROI
from PyQt4 import QtCore, QtGui
import sys
from numpy import ndarray
import ptime
from SignalProxy import proxyConnect
class PlotROI(ROI):
def __init__(self, size):
@ -35,12 +40,25 @@ class ImageView(QtGui.QWidget):
self.ui = Ui_Form()
self.ui.setupUi(self)
self.scene = self.ui.graphicsView.sceneObj
self.ignoreTimeLine = False
if 'linux' in sys.platform.lower(): ## Stupid GL bug in linux.
self.ui.graphicsView.setViewport(QtGui.QWidget())
self.ui.graphicsView.enableMouse(True)
self.ui.graphicsView.autoPixelRange = False
self.ui.graphicsView.setAspectLocked(True)
self.ui.graphicsView.invertY()
self.ui.graphicsView.enableMouse()
self. ticks = [t[0] for t in self.ui.gradientWidget.listTicks()]
self.ticks[0].colorChangeAllowed = False
self.ticks[1].colorChangeAllowed = False
self.ui.gradientWidget.allowAdd = False
self.ui.gradientWidget.setTickColor(self.ticks[1], QtGui.QColor(255,255,255))
self.ui.gradientWidget.setOrientation('right')
self.imageItem = ImageItem()
self.scene.addItem(self.imageItem)
self.currentIndex = 0
@ -51,26 +69,46 @@ class ImageView(QtGui.QWidget):
self.roi.setZValue(20)
self.scene.addItem(self.roi)
self.roi.hide()
self.ui.roiPlot.hide()
self.normRoi = PlotROI(10)
self.normRoi.setPen(QtGui.QPen(QtGui.QColor(255,255,0)))
self.normRoi.setZValue(20)
self.scene.addItem(self.normRoi)
self.normRoi.hide()
#self.ui.roiPlot.hide()
self.roiCurve = self.ui.roiPlot.plot()
self.roiTimeLine = InfiniteLine(self.ui.roiPlot, 0)
self.roiTimeLine.setPen(QtGui.QPen(QtGui.QColor(255, 255, 0, 200)))
self.ui.roiPlot.addItem(self.roiTimeLine)
self.timeLine = InfiniteLine(self.ui.roiPlot, 0, movable=True)
self.timeLine.setPen(QtGui.QPen(QtGui.QColor(255, 255, 0, 200)))
self.timeLine.setZValue(1)
self.ui.roiPlot.addItem(self.timeLine)
self.ui.splitter.setSizes([self.height()-35, 35])
self.ui.roiPlot.showScale('left', False)
self.normLines = []
for i in [0,1]:
l = InfiniteLine(self.ui.roiPlot, 0)
l.setPen(QtGui.QPen(QtGui.QColor(0, 100, 200, 200)))
self.ui.roiPlot.addItem(l)
self.normLines.append(l)
l.hide()
self.keysPressed = {}
self.playTimer = QtCore.QTimer()
self.playRate = 0
self.lastPlayTime = 0
#self.normLines = []
#for i in [0,1]:
#l = InfiniteLine(self.ui.roiPlot, 0)
#l.setPen(QtGui.QPen(QtGui.QColor(0, 100, 200, 200)))
#self.ui.roiPlot.addItem(l)
#self.normLines.append(l)
#l.hide()
self.normRgn = LinearRegionItem(self.ui.roiPlot, 'vertical')
self.normRgn.setZValue(0)
self.ui.roiPlot.addItem(self.normRgn)
self.normRgn.hide()
for fn in ['addItem']:
## wrap functions from graphics view
for fn in ['addItem', 'removeItem']:
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.whiteSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateImage)
QtCore.QObject.connect(self.ui.blackSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateImage)
#QtCore.QObject.connect(self.ui.timeSlider, QtCore.SIGNAL('valueChanged(int)'), self.timeChanged)
self.timeLine.connect(QtCore.SIGNAL('positionChanged'), self.timeLineChanged)
#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.gradientWidget, QtCore.SIGNAL('gradientChanged'), self.updateImage)
QtCore.QObject.connect(self.ui.roiBtn, QtCore.SIGNAL('clicked()'), self.roiClicked)
self.roi.connect(QtCore.SIGNAL('regionChanged'), self.roiChanged)
QtCore.QObject.connect(self.ui.normBtn, QtCore.SIGNAL('toggled(bool)'), self.normToggled)
@ -80,21 +118,151 @@ class ImageView(QtGui.QWidget):
QtCore.QObject.connect(self.ui.normROICheck, QtCore.SIGNAL('clicked()'), self.updateNorm)
QtCore.QObject.connect(self.ui.normFrameCheck, QtCore.SIGNAL('clicked()'), self.updateNorm)
QtCore.QObject.connect(self.ui.normTimeRangeCheck, QtCore.SIGNAL('clicked()'), 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.playTimer, QtCore.SIGNAL('timeout()'), self.timeout)
##QtCore.QObject.connect(self.ui.normStartSlider, 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.normRoi.connect(QtCore.SIGNAL('regionChangeFinished'), self.updateNorm)
self.ui.roiPlot.registerPlot(self.name + '_ROI')
self.noRepeatKeys = [QtCore.Qt.Key_Right, QtCore.Qt.Key_Left, QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown]
#def __dtor__(self):
##print "Called ImageView sip destructor"
#self.quit()
#QtGui.QWidget.__dtor__(self)
def quit(self):
self.scene.clear()
del self.image
del self.imageDisp
def keyPressEvent(self, ev):
if ev.key() == QtCore.Qt.Key_Space:
if self.playRate == 0:
fps = (self.getProcessedImage().shape[0]-1) / (self.tVals[-1] - self.tVals[0])
self.play(fps)
#print fps
else:
self.play(0)
ev.accept()
elif ev.key() == QtCore.Qt.Key_Home:
self.setCurrentIndex(0)
self.play(0)
ev.accept()
elif ev.key() == QtCore.Qt.Key_End:
self.setCurrentIndex(self.getProcessedImage().shape[0]-1)
self.play(0)
ev.accept()
elif ev.key() in self.noRepeatKeys:
ev.accept()
if ev.isAutoRepeat():
return
self.keysPressed[ev.key()] = 1
self.evalKeyState()
else:
QtGui.QWidget.keyPressEvent(self, ev)
def keyReleaseEvent(self, ev):
if ev.key() in [QtCore.Qt.Key_Space, QtCore.Qt.Key_Home, QtCore.Qt.Key_End]:
ev.accept()
elif ev.key() in self.noRepeatKeys:
ev.accept()
if ev.isAutoRepeat():
return
try:
del self.keysPressed[ev.key()]
except:
self.keysPressed = {}
self.evalKeyState()
else:
QtGui.QWidget.keyReleaseEvent(self, ev)
def evalKeyState(self):
if len(self.keysPressed) == 1:
key = self.keysPressed.keys()[0]
if key == QtCore.Qt.Key_Right:
self.play(20)
self.lastPlayTime = ptime.time() + 0.2 ## 2ms wait before start
self.jumpFrames(1)
elif key == QtCore.Qt.Key_Left:
self.play(-20)
self.lastPlayTime = ptime.time() + 0.2
self.jumpFrames(-1)
elif key == QtCore.Qt.Key_Up:
self.play(-100)
elif key == QtCore.Qt.Key_Down:
self.play(100)
elif key == QtCore.Qt.Key_PageUp:
self.play(-1000)
elif key == QtCore.Qt.Key_PageDown:
self.play(1000)
else:
self.play(0)
def play(self, rate):
#print "play:", rate
self.playRate = rate
if rate == 0:
self.playTimer.stop()
return
self.lastPlayTime = ptime.time()
if not self.playTimer.isActive():
self.playTimer.start(16)
def timeout(self):
now = ptime.time()
dt = now - self.lastPlayTime
if dt < 0:
return
n = int(self.playRate * dt)
#print n, dt
if n != 0:
#print n, dt, self.lastPlayTime
self.lastPlayTime += (float(n)/self.playRate)
if self.currentIndex+n > self.image.shape[0]:
self.play(0)
self.jumpFrames(n)
def setCurrentIndex(self, ind):
self.currentIndex = clip(ind, 0, self.getProcessedImage().shape[0]-1)
self.updateImage()
self.ignoreTimeLine = True
self.timeLine.setValue(self.tVals[self.currentIndex])
self.ignoreTimeLine = False
def jumpFrames(self, n):
"""If this is a video, move ahead n frames"""
if self.axes['t'] is not None:
self.setCurrentIndex(self.currentIndex + n)
def updateNorm(self):
for l, sl in zip(self.normLines, [self.ui.normStartSlider, self.ui.normStopSlider]):
if self.ui.normTimeRangeCheck.isChecked():
l.show()
else:
l.hide()
#for l, sl in zip(self.normLines, [self.ui.normStartSlider, self.ui.normStopSlider]):
#if self.ui.normTimeRangeCheck.isChecked():
#l.show()
#else:
#l.hide()
i, t = self.timeIndex(sl)
l.setPos(t)
#i, t = self.timeIndex(sl)
#l.setPos(t)
if self.ui.normTimeRangeCheck.isChecked():
#print "show!"
self.normRgn.show()
else:
self.normRgn.hide()
if self.ui.normROICheck.isChecked():
#print "show!"
self.normRoi.show()
else:
self.normRoi.hide()
self.imageDisp = None
self.updateImage()
@ -102,15 +270,25 @@ class ImageView(QtGui.QWidget):
def normToggled(self, b):
self.ui.normGroup.setVisible(b)
self.normRoi.setVisible(b and self.ui.normROICheck.isChecked())
self.normRgn.setVisible(b and self.ui.normTimeRangeCheck.isChecked())
def roiClicked(self):
if self.ui.roiBtn.isChecked():
self.roi.show()
self.ui.roiPlot.show()
#self.ui.roiPlot.show()
self.ui.roiPlot.setMouseEnabled(True, True)
self.ui.splitter.setSizes([self.height()*0.6, self.height()*0.4])
self.roiCurve.show()
self.roiChanged()
self.ui.roiPlot.showScale('left', True)
else:
self.roi.hide()
self.ui.roiPlot.hide()
self.ui.roiPlot.setMouseEnabled(False, False)
self.ui.roiPlot.setXRange(self.tVals.min(), self.tVals.max())
self.ui.splitter.setSizes([self.height()-35, 35])
self.roiCurve.hide()
self.ui.roiPlot.showScale('left', False)
def roiChanged(self):
if self.image is None:
@ -130,25 +308,41 @@ class ImageView(QtGui.QWidget):
self.roiCurve.setData(y=data, x=self.tVals)
#self.ui.roiPlot.replot()
def setImage(self, img, autoRange=True, autoLevels=True, levels=None):
def setImage(self, img, autoRange=True, autoLevels=True, levels=None, axes=None, xvals=None):
"""Set the image to be displayed in the widget.
Options are:
img: ndarray; the image to be displayed.
autoRange: bool; whether to scale/pan the view to fit the image.
autoLevels: bool; whether to update the white/black levels to fit the image.
levels: (min, max); the white and black level values to use.
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.
"""
if not isinstance(img, ndarray):
raise Exception("Image must be specified as ndarray.")
self.image = img
if hasattr(img, 'xvals'):
if xvals is not None:
self.tVals = xvals
elif hasattr(img, 'xvals'):
self.tVals = img.xvals(0)
else:
self.tVals = arange(img.shape[0])
self.ui.timeSlider.setValue(0)
#self.ui.timeSlider.setValue(0)
#self.ui.normStartSlider.setValue(0)
#self.ui.timeSlider.setMaximum(img.shape[0]-1)
if img.ndim == 2:
self.axes = {'t': None, 'x': 0, 'y': 1, 'c': None}
elif img.ndim == 3:
if img.shape[2] <= 3:
self.axes = {'t': None, 'x': 0, 'y': 1, 'c': 2}
else:
self.axes = {'t': 0, 'x': 1, 'y': 2, 'c': None}
elif img.ndim == 4:
self.axes = {'t': 0, 'x': 1, 'y': 2, 'c': 3}
if axes is None:
if img.ndim == 2:
self.axes = {'t': None, 'x': 0, 'y': 1, 'c': None}
elif img.ndim == 3:
if img.shape[2] <= 4:
self.axes = {'t': None, 'x': 0, 'y': 1, 'c': 2}
else:
self.axes = {'t': 0, 'x': 1, 'y': 2, 'c': None}
elif img.ndim == 4:
self.axes = {'t': 0, 'x': 1, 'y': 2, 'c': 3}
self.imageDisp = None
@ -163,11 +357,36 @@ class ImageView(QtGui.QWidget):
if self.ui.roiBtn.isChecked():
self.roiChanged()
if self.axes['t'] is not None:
#self.ui.roiPlot.show()
self.ui.roiPlot.setXRange(self.tVals.min(), self.tVals.max())
#self.ui.roiPlot.setMouseEnabled(False, False)
if len(self.tVals) > 1:
start = self.tVals.min()
stop = self.tVals.max() + abs(self.tVals[-1] - self.tVals[0]) * 0.02
elif len(self.tVals) == 1:
start = self.tVals[0] - 0.5
stop = self.tVals[0] + 0.5
else:
start = 0
stop = 1
for s in [self.timeLine, self.normRgn]:
s.setBounds([start, stop])
#else:
#self.ui.roiPlot.hide()
self.roiClicked()
def autoLevels(self):
image = self.getProcessedImage()
self.ui.whiteSlider.setValue(self.ui.whiteSlider.maximum())
self.ui.blackSlider.setValue(0)
#self.ui.whiteSlider.setValue(self.ui.whiteSlider.maximum())
#self.ui.blackSlider.setValue(0)
self.ui.gradientWidget.setTickValue(self.ticks[0], 0.0)
self.ui.gradientWidget.setTickValue(self.ticks[1], 1.0)
self.imageItem.setLevels(white=self.whiteLevel(), black=self.blackLevel())
def autoRange(self):
@ -189,7 +408,7 @@ class ImageView(QtGui.QWidget):
return image
div = self.ui.normDivideRadio.isChecked()
norm = image.copy()
norm = image.view(ndarray).copy()
#if div:
#norm = ones(image.shape)
#else:
@ -198,8 +417,8 @@ class ImageView(QtGui.QWidget):
norm = norm.astype(float32)
if self.ui.normTimeRangeCheck.isChecked() and image.ndim == 3:
(sind, start) = self.timeIndex(self.ui.normStartSlider)
(eind, end) = self.timeIndex(self.ui.normStopSlider)
(sind, start) = self.timeIndex(self.normRgn.lines[0])
(eind, end) = self.timeIndex(self.normRgn.lines[1])
#print start, end, sind, eind
n = image[sind:eind+1].mean(axis=0)
n.shape = (1,) + n.shape
@ -216,17 +435,27 @@ class ImageView(QtGui.QWidget):
else:
norm -= n
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 = n[:,newaxis,newaxis]
#print start, end, sind, eind
if div:
norm /= n
else:
norm -= n
return norm
def timeChanged(self):
(ind, time) = self.timeIndex(self.ui.timeSlider)
def timeLineChanged(self):
#(ind, time) = self.timeIndex(self.ui.timeSlider)
if self.ignoreTimeLine:
return
self.play(0)
(ind, time) = self.timeIndex(self.timeLine)
if ind != self.currentIndex:
self.currentIndex = ind
self.updateImage()
self.roiTimeLine.setPos(time)
#self.ui.roiPlot.replot()
#self.timeLine.setPos(time)
self.emit(QtCore.SIGNAL('timeChanged'), ind, time)
def updateImage(self):
@ -237,29 +466,38 @@ class ImageView(QtGui.QWidget):
image = self.getProcessedImage()
#print "update:", image.ndim, image.max(), image.min(), self.blackLevel(), self.whiteLevel()
if self.axes['t'] is None:
self.ui.timeSlider.hide()
#self.ui.timeSlider.hide()
self.imageItem.updateImage(image, white=self.whiteLevel(), black=self.blackLevel())
self.ui.roiPlot.hide()
self.ui.roiBtn.hide()
else:
self.ui.timeSlider.show()
self.ui.roiBtn.show()
self.ui.roiPlot.show()
#self.ui.timeSlider.show()
self.imageItem.updateImage(image[self.currentIndex], white=self.whiteLevel(), black=self.blackLevel())
def timeIndex(self, slider):
"""Return the time and frame index indicated by a slider"""
if self.image is None:
return (0,0)
v = slider.value()
vmax = slider.maximum()
f = float(v) / vmax
t = 0.0
#v = slider.value()
#vmax = slider.maximum()
#f = float(v) / vmax
t = slider.value()
#t = 0.0
#xv = self.image.xvals('Time')
xv = self.tVals
if xv is None:
ind = int(f * self.image.shape[0])
ind = int(t)
#ind = int(f * self.image.shape[0])
else:
if len(xv) < 2:
return (0,0)
totTime = xv[-1] + (xv[-1]-xv[-2])
t = f * totTime
#t = f * totTime
inds = argwhere(xv < t)
if len(inds) < 1:
return (0,t)
@ -268,8 +506,10 @@ class ImageView(QtGui.QWidget):
return ind, t
def whiteLevel(self):
return self.levelMin + (self.levelMax-self.levelMin) * self.ui.whiteSlider.value() / self.ui.whiteSlider.maximum()
return self.levelMin + (self.levelMax-self.levelMin) * self.ui.gradientWidget.tickValue(self.ticks[1])
#return self.levelMin + (self.levelMax-self.levelMin) * self.ui.whiteSlider.value() / self.ui.whiteSlider.maximum()
def blackLevel(self):
return self.levelMin + ((self.levelMax-self.levelMin) / self.ui.blackSlider.maximum()) * self.ui.blackSlider.value()
return self.levelMin + (self.levelMax-self.levelMin) * self.ui.gradientWidget.tickValue(self.ticks[0])
#return self.levelMin + ((self.levelMax-self.levelMin) / self.ui.blackSlider.maximum()) * self.ui.blackSlider.value()

View File

@ -1,188 +1,167 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ImageViewTemplate.ui'
#
# Created: Mon Mar 29 22:40:48 2010
# by: PyQt4 UI code generator 4.6
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(757, 495)
self.verticalLayout = QtGui.QVBoxLayout(Form)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setMargin(0)
self.verticalLayout.setObjectName("verticalLayout")
self.splitter = QtGui.QSplitter(Form)
self.splitter.setOrientation(QtCore.Qt.Vertical)
self.splitter.setObjectName("splitter")
self.layoutWidget = QtGui.QWidget(self.splitter)
self.layoutWidget.setObjectName("layoutWidget")
self.gridLayout = QtGui.QGridLayout(self.layoutWidget)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName("gridLayout")
self.graphicsView = GraphicsView(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.graphicsView.sizePolicy().hasHeightForWidth())
self.graphicsView.setSizePolicy(sizePolicy)
self.graphicsView.setObjectName("graphicsView")
self.gridLayout.addWidget(self.graphicsView, 0, 0, 3, 1)
self.blackSlider = QtGui.QSlider(self.layoutWidget)
self.blackSlider.setMaximum(4096)
self.blackSlider.setOrientation(QtCore.Qt.Vertical)
self.blackSlider.setInvertedAppearance(False)
self.blackSlider.setInvertedControls(False)
self.blackSlider.setTickPosition(QtGui.QSlider.TicksBelow)
self.blackSlider.setTickInterval(410)
self.blackSlider.setObjectName("blackSlider")
self.gridLayout.addWidget(self.blackSlider, 0, 1, 1, 1)
self.whiteSlider = QtGui.QSlider(self.layoutWidget)
self.whiteSlider.setMaximum(4096)
self.whiteSlider.setProperty("value", 4096)
self.whiteSlider.setOrientation(QtCore.Qt.Vertical)
self.whiteSlider.setObjectName("whiteSlider")
self.gridLayout.addWidget(self.whiteSlider, 0, 2, 1, 2)
self.label = QtGui.QLabel(self.layoutWidget)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 1, 1, 1, 1)
self.label_2 = QtGui.QLabel(self.layoutWidget)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 2, 1, 1)
self.roiBtn = QtGui.QPushButton(self.layoutWidget)
self.roiBtn.setMaximumSize(QtCore.QSize(40, 16777215))
self.roiBtn.setCheckable(True)
self.roiBtn.setObjectName("roiBtn")
self.gridLayout.addWidget(self.roiBtn, 2, 1, 1, 3)
self.timeSlider = QtGui.QSlider(self.layoutWidget)
self.timeSlider.setMaximum(65535)
self.timeSlider.setOrientation(QtCore.Qt.Horizontal)
self.timeSlider.setObjectName("timeSlider")
self.gridLayout.addWidget(self.timeSlider, 4, 0, 1, 1)
self.normBtn = QtGui.QPushButton(self.layoutWidget)
self.normBtn.setMaximumSize(QtCore.QSize(50, 16777215))
self.normBtn.setCheckable(True)
self.normBtn.setObjectName("normBtn")
self.gridLayout.addWidget(self.normBtn, 4, 1, 1, 2)
self.normGroup = QtGui.QGroupBox(self.layoutWidget)
self.normGroup.setObjectName("normGroup")
self.gridLayout_2 = QtGui.QGridLayout(self.normGroup)
self.gridLayout_2.setMargin(0)
self.gridLayout_2.setSpacing(0)
self.gridLayout_2.setObjectName("gridLayout_2")
self.normSubtractRadio = QtGui.QRadioButton(self.normGroup)
self.normSubtractRadio.setObjectName("normSubtractRadio")
self.gridLayout_2.addWidget(self.normSubtractRadio, 0, 2, 1, 1)
self.normDivideRadio = QtGui.QRadioButton(self.normGroup)
self.normDivideRadio.setChecked(False)
self.normDivideRadio.setObjectName("normDivideRadio")
self.gridLayout_2.addWidget(self.normDivideRadio, 0, 1, 1, 1)
self.label_5 = QtGui.QLabel(self.normGroup)
font = QtGui.QFont()
font.setWeight(75)
font.setBold(True)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.gridLayout_2.addWidget(self.label_5, 0, 0, 1, 1)
self.label_3 = QtGui.QLabel(self.normGroup)
font = QtGui.QFont()
font.setWeight(75)
font.setBold(True)
self.label_3.setFont(font)
self.label_3.setObjectName("label_3")
self.gridLayout_2.addWidget(self.label_3, 1, 0, 1, 1)
self.label_4 = QtGui.QLabel(self.normGroup)
font = QtGui.QFont()
font.setWeight(75)
font.setBold(True)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.gridLayout_2.addWidget(self.label_4, 4, 0, 1, 1)
self.normROICheck = QtGui.QCheckBox(self.normGroup)
self.normROICheck.setObjectName("normROICheck")
self.gridLayout_2.addWidget(self.normROICheck, 1, 1, 1, 1)
self.normStartSlider = QtGui.QSlider(self.normGroup)
self.normStartSlider.setMaximum(65535)
self.normStartSlider.setOrientation(QtCore.Qt.Horizontal)
self.normStartSlider.setObjectName("normStartSlider")
self.gridLayout_2.addWidget(self.normStartSlider, 2, 0, 1, 6)
self.normStopSlider = QtGui.QSlider(self.normGroup)
self.normStopSlider.setMaximum(65535)
self.normStopSlider.setOrientation(QtCore.Qt.Horizontal)
self.normStopSlider.setObjectName("normStopSlider")
self.gridLayout_2.addWidget(self.normStopSlider, 3, 0, 1, 6)
self.normXBlurSpin = QtGui.QDoubleSpinBox(self.normGroup)
self.normXBlurSpin.setObjectName("normXBlurSpin")
self.gridLayout_2.addWidget(self.normXBlurSpin, 4, 2, 1, 1)
self.label_8 = QtGui.QLabel(self.normGroup)
self.label_8.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label_8.setObjectName("label_8")
self.gridLayout_2.addWidget(self.label_8, 4, 1, 1, 1)
self.label_9 = QtGui.QLabel(self.normGroup)
self.label_9.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label_9.setObjectName("label_9")
self.gridLayout_2.addWidget(self.label_9, 4, 3, 1, 1)
self.normYBlurSpin = QtGui.QDoubleSpinBox(self.normGroup)
self.normYBlurSpin.setObjectName("normYBlurSpin")
self.gridLayout_2.addWidget(self.normYBlurSpin, 4, 4, 1, 1)
self.label_10 = QtGui.QLabel(self.normGroup)
self.label_10.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label_10.setObjectName("label_10")
self.gridLayout_2.addWidget(self.label_10, 4, 5, 1, 1)
self.normStopLabel = QtGui.QLabel(self.normGroup)
self.normStopLabel.setObjectName("normStopLabel")
self.gridLayout_2.addWidget(self.normStopLabel, 3, 6, 1, 1)
self.normStartLabel = QtGui.QLabel(self.normGroup)
self.normStartLabel.setObjectName("normStartLabel")
self.gridLayout_2.addWidget(self.normStartLabel, 2, 6, 1, 1)
self.normOffRadio = QtGui.QRadioButton(self.normGroup)
self.normOffRadio.setChecked(True)
self.normOffRadio.setObjectName("normOffRadio")
self.gridLayout_2.addWidget(self.normOffRadio, 0, 3, 1, 1)
self.normTimeRangeCheck = QtGui.QCheckBox(self.normGroup)
self.normTimeRangeCheck.setObjectName("normTimeRangeCheck")
self.gridLayout_2.addWidget(self.normTimeRangeCheck, 1, 3, 1, 1)
self.normFrameCheck = QtGui.QCheckBox(self.normGroup)
self.normFrameCheck.setObjectName("normFrameCheck")
self.gridLayout_2.addWidget(self.normFrameCheck, 1, 2, 1, 1)
self.normTBlurSpin = QtGui.QDoubleSpinBox(self.normGroup)
self.normTBlurSpin.setObjectName("normTBlurSpin")
self.gridLayout_2.addWidget(self.normTBlurSpin, 4, 6, 1, 1)
self.gridLayout.addWidget(self.normGroup, 5, 0, 1, 4)
self.roiPlot = PlotWidget(self.splitter)
self.roiPlot.setMinimumSize(QtCore.QSize(0, 40))
self.roiPlot.setObjectName("roiPlot")
self.verticalLayout.addWidget(self.splitter)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("Form", "B", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("Form", "W", None, QtGui.QApplication.UnicodeUTF8))
self.roiBtn.setText(QtGui.QApplication.translate("Form", "ROI", None, QtGui.QApplication.UnicodeUTF8))
self.normBtn.setText(QtGui.QApplication.translate("Form", "Norm", None, QtGui.QApplication.UnicodeUTF8))
self.normGroup.setTitle(QtGui.QApplication.translate("Form", "Normalization", None, QtGui.QApplication.UnicodeUTF8))
self.normSubtractRadio.setText(QtGui.QApplication.translate("Form", "Subtract", None, QtGui.QApplication.UnicodeUTF8))
self.normDivideRadio.setText(QtGui.QApplication.translate("Form", "Divide", None, QtGui.QApplication.UnicodeUTF8))
self.label_5.setText(QtGui.QApplication.translate("Form", "Operation:", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate("Form", "Mean:", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("Form", "Blur:", None, QtGui.QApplication.UnicodeUTF8))
self.normROICheck.setText(QtGui.QApplication.translate("Form", "ROI", None, QtGui.QApplication.UnicodeUTF8))
self.label_8.setText(QtGui.QApplication.translate("Form", "X", None, QtGui.QApplication.UnicodeUTF8))
self.label_9.setText(QtGui.QApplication.translate("Form", "Y", None, QtGui.QApplication.UnicodeUTF8))
self.label_10.setText(QtGui.QApplication.translate("Form", "T", None, QtGui.QApplication.UnicodeUTF8))
self.normStopLabel.setText(QtGui.QApplication.translate("Form", "Stop", None, QtGui.QApplication.UnicodeUTF8))
self.normStartLabel.setText(QtGui.QApplication.translate("Form", "Start", None, QtGui.QApplication.UnicodeUTF8))
self.normOffRadio.setText(QtGui.QApplication.translate("Form", "Off", None, QtGui.QApplication.UnicodeUTF8))
self.normTimeRangeCheck.setText(QtGui.QApplication.translate("Form", "Time range", None, QtGui.QApplication.UnicodeUTF8))
self.normFrameCheck.setText(QtGui.QApplication.translate("Form", "Frame", None, QtGui.QApplication.UnicodeUTF8))
from GraphicsView import GraphicsView
from PlotWidget import PlotWidget
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ImageViewTemplate.ui'
#
# Created: Sat Jul 17 13:05:44 2010
# by: PyQt4 UI code generator 4.5.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(726, 588)
self.verticalLayout = QtGui.QVBoxLayout(Form)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setMargin(0)
self.verticalLayout.setObjectName("verticalLayout")
self.splitter = QtGui.QSplitter(Form)
self.splitter.setOrientation(QtCore.Qt.Vertical)
self.splitter.setObjectName("splitter")
self.layoutWidget = QtGui.QWidget(self.splitter)
self.layoutWidget.setObjectName("layoutWidget")
self.gridLayout = QtGui.QGridLayout(self.layoutWidget)
self.gridLayout.setMargin(0)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName("gridLayout")
self.graphicsView = GraphicsView(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(10)
sizePolicy.setVerticalStretch(10)
sizePolicy.setHeightForWidth(self.graphicsView.sizePolicy().hasHeightForWidth())
self.graphicsView.setSizePolicy(sizePolicy)
self.graphicsView.setObjectName("graphicsView")
self.gridLayout.addWidget(self.graphicsView, 1, 0, 3, 1)
self.roiBtn = QtGui.QPushButton(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(1)
sizePolicy.setHeightForWidth(self.roiBtn.sizePolicy().hasHeightForWidth())
self.roiBtn.setSizePolicy(sizePolicy)
self.roiBtn.setMaximumSize(QtCore.QSize(30, 16777215))
self.roiBtn.setCheckable(True)
self.roiBtn.setObjectName("roiBtn")
self.gridLayout.addWidget(self.roiBtn, 3, 3, 1, 1)
self.gradientWidget = GradientWidget(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(100)
sizePolicy.setHeightForWidth(self.gradientWidget.sizePolicy().hasHeightForWidth())
self.gradientWidget.setSizePolicy(sizePolicy)
self.gradientWidget.setObjectName("gradientWidget")
self.gridLayout.addWidget(self.gradientWidget, 1, 3, 1, 1)
self.normBtn = QtGui.QPushButton(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(1)
sizePolicy.setHeightForWidth(self.normBtn.sizePolicy().hasHeightForWidth())
self.normBtn.setSizePolicy(sizePolicy)
self.normBtn.setMaximumSize(QtCore.QSize(30, 16777215))
self.normBtn.setCheckable(True)
self.normBtn.setObjectName("normBtn")
self.gridLayout.addWidget(self.normBtn, 2, 3, 1, 1)
self.normGroup = QtGui.QGroupBox(self.layoutWidget)
self.normGroup.setObjectName("normGroup")
self.gridLayout_2 = QtGui.QGridLayout(self.normGroup)
self.gridLayout_2.setMargin(0)
self.gridLayout_2.setSpacing(0)
self.gridLayout_2.setObjectName("gridLayout_2")
self.normSubtractRadio = QtGui.QRadioButton(self.normGroup)
self.normSubtractRadio.setObjectName("normSubtractRadio")
self.gridLayout_2.addWidget(self.normSubtractRadio, 0, 2, 1, 1)
self.normDivideRadio = QtGui.QRadioButton(self.normGroup)
self.normDivideRadio.setChecked(False)
self.normDivideRadio.setObjectName("normDivideRadio")
self.gridLayout_2.addWidget(self.normDivideRadio, 0, 1, 1, 1)
self.label_5 = QtGui.QLabel(self.normGroup)
font = QtGui.QFont()
font.setWeight(75)
font.setBold(True)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.gridLayout_2.addWidget(self.label_5, 0, 0, 1, 1)
self.label_3 = QtGui.QLabel(self.normGroup)
font = QtGui.QFont()
font.setWeight(75)
font.setBold(True)
self.label_3.setFont(font)
self.label_3.setObjectName("label_3")
self.gridLayout_2.addWidget(self.label_3, 1, 0, 1, 1)
self.label_4 = QtGui.QLabel(self.normGroup)
font = QtGui.QFont()
font.setWeight(75)
font.setBold(True)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.gridLayout_2.addWidget(self.label_4, 2, 0, 1, 1)
self.normROICheck = QtGui.QCheckBox(self.normGroup)
self.normROICheck.setObjectName("normROICheck")
self.gridLayout_2.addWidget(self.normROICheck, 1, 1, 1, 1)
self.normXBlurSpin = QtGui.QDoubleSpinBox(self.normGroup)
self.normXBlurSpin.setObjectName("normXBlurSpin")
self.gridLayout_2.addWidget(self.normXBlurSpin, 2, 2, 1, 1)
self.label_8 = QtGui.QLabel(self.normGroup)
self.label_8.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label_8.setObjectName("label_8")
self.gridLayout_2.addWidget(self.label_8, 2, 1, 1, 1)
self.label_9 = QtGui.QLabel(self.normGroup)
self.label_9.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label_9.setObjectName("label_9")
self.gridLayout_2.addWidget(self.label_9, 2, 3, 1, 1)
self.normYBlurSpin = QtGui.QDoubleSpinBox(self.normGroup)
self.normYBlurSpin.setObjectName("normYBlurSpin")
self.gridLayout_2.addWidget(self.normYBlurSpin, 2, 4, 1, 1)
self.label_10 = QtGui.QLabel(self.normGroup)
self.label_10.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label_10.setObjectName("label_10")
self.gridLayout_2.addWidget(self.label_10, 2, 5, 1, 1)
self.normOffRadio = QtGui.QRadioButton(self.normGroup)
self.normOffRadio.setChecked(True)
self.normOffRadio.setObjectName("normOffRadio")
self.gridLayout_2.addWidget(self.normOffRadio, 0, 3, 1, 1)
self.normTimeRangeCheck = QtGui.QCheckBox(self.normGroup)
self.normTimeRangeCheck.setObjectName("normTimeRangeCheck")
self.gridLayout_2.addWidget(self.normTimeRangeCheck, 1, 3, 1, 1)
self.normFrameCheck = QtGui.QCheckBox(self.normGroup)
self.normFrameCheck.setObjectName("normFrameCheck")
self.gridLayout_2.addWidget(self.normFrameCheck, 1, 2, 1, 1)
self.normTBlurSpin = QtGui.QDoubleSpinBox(self.normGroup)
self.normTBlurSpin.setObjectName("normTBlurSpin")
self.gridLayout_2.addWidget(self.normTBlurSpin, 2, 6, 1, 1)
self.gridLayout.addWidget(self.normGroup, 0, 0, 1, 4)
self.roiPlot = PlotWidget(self.splitter)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.roiPlot.sizePolicy().hasHeightForWidth())
self.roiPlot.setSizePolicy(sizePolicy)
self.roiPlot.setMinimumSize(QtCore.QSize(0, 40))
self.roiPlot.setObjectName("roiPlot")
self.verticalLayout.addWidget(self.splitter)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.roiBtn.setText(QtGui.QApplication.translate("Form", "R", None, QtGui.QApplication.UnicodeUTF8))
self.normBtn.setText(QtGui.QApplication.translate("Form", "N", None, QtGui.QApplication.UnicodeUTF8))
self.normGroup.setTitle(QtGui.QApplication.translate("Form", "Normalization", None, QtGui.QApplication.UnicodeUTF8))
self.normSubtractRadio.setText(QtGui.QApplication.translate("Form", "Subtract", None, QtGui.QApplication.UnicodeUTF8))
self.normDivideRadio.setText(QtGui.QApplication.translate("Form", "Divide", None, QtGui.QApplication.UnicodeUTF8))
self.label_5.setText(QtGui.QApplication.translate("Form", "Operation:", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate("Form", "Mean:", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("Form", "Blur:", None, QtGui.QApplication.UnicodeUTF8))
self.normROICheck.setText(QtGui.QApplication.translate("Form", "ROI", None, QtGui.QApplication.UnicodeUTF8))
self.label_8.setText(QtGui.QApplication.translate("Form", "X", None, QtGui.QApplication.UnicodeUTF8))
self.label_9.setText(QtGui.QApplication.translate("Form", "Y", None, QtGui.QApplication.UnicodeUTF8))
self.label_10.setText(QtGui.QApplication.translate("Form", "T", None, QtGui.QApplication.UnicodeUTF8))
self.normOffRadio.setText(QtGui.QApplication.translate("Form", "Off", None, QtGui.QApplication.UnicodeUTF8))
self.normTimeRangeCheck.setText(QtGui.QApplication.translate("Form", "Time range", None, QtGui.QApplication.UnicodeUTF8))
self.normFrameCheck.setText(QtGui.QApplication.translate("Form", "Frame", None, QtGui.QApplication.UnicodeUTF8))
from GraphicsView import GraphicsView
from pyqtgraph.GradientWidget import GradientWidget
from PlotWidget import PlotWidget

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>757</width>
<height>495</height>
<width>726</width>
<height>588</height>
</rect>
</property>
<property name="windowTitle">
@ -27,113 +27,77 @@
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0" rowspan="3">
<item row="1" column="0" rowspan="3">
<widget class="GraphicsView" name="graphicsView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
<horstretch>10</horstretch>
<verstretch>10</verstretch>
</sizepolicy>
</property>
<zorder>normGroup</zorder>
<zorder>normGroup</zorder>
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="blackSlider">
<property name="maximum">
<number>4096</number>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>410</number>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QSlider" name="whiteSlider">
<property name="maximum">
<number>4096</number>
</property>
<property name="value">
<number>4096</number>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string>B</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>W</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="3">
<item row="3" column="3">
<widget class="QPushButton" name="roiBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>ROI</string>
<string>R</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QSlider" name="timeSlider">
<property name="maximum">
<number>65535</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="1" column="3">
<widget class="GradientWidget" name="gradientWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>100</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<item row="2" column="3">
<widget class="QPushButton" name="normBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Norm</string>
<string>N</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0" colspan="4">
<item row="0" column="0" colspan="4">
<widget class="QGroupBox" name="normGroup">
<property name="title">
<string>Normalization</string>
@ -188,7 +152,7 @@
</property>
</widget>
</item>
<item row="4" column="0">
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="font">
<font>
@ -208,30 +172,10 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="6">
<widget class="QSlider" name="normStartSlider">
<property name="maximum">
<number>65535</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0" colspan="6">
<widget class="QSlider" name="normStopSlider">
<property name="maximum">
<number>65535</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="2">
<item row="2" column="2">
<widget class="QDoubleSpinBox" name="normXBlurSpin"/>
</item>
<item row="4" column="1">
<item row="2" column="1">
<widget class="QLabel" name="label_8">
<property name="text">
<string>X</string>
@ -241,7 +185,7 @@
</property>
</widget>
</item>
<item row="4" column="3">
<item row="2" column="3">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Y</string>
@ -251,10 +195,10 @@
</property>
</widget>
</item>
<item row="4" column="4">
<item row="2" column="4">
<widget class="QDoubleSpinBox" name="normYBlurSpin"/>
</item>
<item row="4" column="5">
<item row="2" column="5">
<widget class="QLabel" name="label_10">
<property name="text">
<string>T</string>
@ -264,20 +208,6 @@
</property>
</widget>
</item>
<item row="3" column="6">
<widget class="QLabel" name="normStopLabel">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QLabel" name="normStartLabel">
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QRadioButton" name="normOffRadio">
<property name="text">
@ -302,7 +232,7 @@
</property>
</widget>
</item>
<item row="4" column="6">
<item row="2" column="6">
<widget class="QDoubleSpinBox" name="normTBlurSpin"/>
</item>
</layout>
@ -311,6 +241,12 @@
</layout>
</widget>
<widget class="PlotWidget" name="roiPlot" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
@ -323,6 +259,12 @@
</layout>
</widget>
<customwidgets>
<customwidget>
<class>GradientWidget</class>
<extends>QWidget</extends>
<header>pyqtgraph.GradientWidget</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GraphicsView</class>
<extends>QWidget</extends>

22
ObjectWorkaround.py Normal file
View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
class QObjectWorkaround:
def __init__(self):
self._qObj_ = QtCore.QObject()
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)
class QGraphicsObject(QtGui.QGraphicsItem, QObjectWorkaround):
def __init__(self, *args):
QtGui.QGraphicsItem.__init__(self, *args)
QObjectWorkaround.__init__(self)

View File

@ -20,6 +20,8 @@ This class is very heavily featured:
from graphicsItems import *
from plotConfigTemplate import *
from PyQt4 import QtGui, QtCore, QtSvg
#from ObjectWorkaround import *
#tryWorkaround(QtCore, QtGui)
import weakref
try:
@ -42,7 +44,7 @@ class PlotItem(QtGui.QGraphicsWidget):
lastFileDir = None
managers = {}
def __init__(self, parent=None):
def __init__(self, parent=None, name=None):
QtGui.QGraphicsWidget.__init__(self, parent)
## Set up control buttons
@ -56,6 +58,7 @@ class PlotItem(QtGui.QGraphicsWidget):
for b in [self.ctrlBtn, self.autoBtn]:
proxy = QtGui.QGraphicsProxyWidget(self)
proxy.setWidget(b)
proxy.setAcceptHoverEvents(False)
b.setStyleSheet("background-color: #000000; color: #888; font-size: 6pt")
QtCore.QObject.connect(self.ctrlBtn, QtCore.SIGNAL('clicked()'), self.ctrlBtnClicked)
QtCore.QObject.connect(self.autoBtn, QtCore.SIGNAL('clicked()'), self.enableAutoScale)
@ -124,7 +127,7 @@ class PlotItem(QtGui.QGraphicsWidget):
## Wrap a few methods from viewBox
for m in ['setXRange', 'setYRange', 'setRange', 'autoRange', 'viewRect']:
for m in ['setXRange', 'setYRange', 'setRange', 'autoRange', 'viewRect', 'setMouseEnabled']:
setattr(self, m, getattr(self.vb, m))
self.items = []
@ -178,9 +181,13 @@ class PlotItem(QtGui.QGraphicsWidget):
QtCore.QObject.connect(c.alphaSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateAlpha)
QtCore.QObject.connect(c.autoAlphaCheck, QtCore.SIGNAL('toggled(bool)'), self.updateAlpha)
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.powerSpectrumGroup, QtCore.SIGNAL('toggled(bool)'), self.updateSpectrumMode)
QtCore.QObject.connect(c.saveSvgBtn, QtCore.SIGNAL('clicked()'), self.saveSvgClicked)
QtCore.QObject.connect(c.saveImgBtn, QtCore.SIGNAL('clicked()'), self.saveImgClicked)
QtCore.QObject.connect(c.saveCsvBtn, QtCore.SIGNAL('clicked()'), self.saveCsvClicked)
#QtCore.QObject.connect(c.gridGroup, QtCore.SIGNAL('toggled(bool)'), self.updateGrid)
#QtCore.QObject.connect(c.gridAlphaSlider, QtCore.SIGNAL('valueChanged(int)'), self.updateGrid)
@ -215,7 +222,11 @@ class PlotItem(QtGui.QGraphicsWidget):
self.showScale('top', False)
self.showScale('left', True)
self.showScale('bottom', True)
if name is not None:
self.registerPlot(name)
def __del__(self):
if self.manager is not None:
self.manager.removeWidget(self.name)
@ -250,6 +261,13 @@ class PlotItem(QtGui.QGraphicsWidget):
refs= gc.get_referrers(self)
print " error during update. Referrers are:", refs
raise
def updateGrid(self, *args):
g = self.ctrl.gridGroup.isChecked()
if g:
g = self.ctrl.gridAlphaSlider.value()
for k in self.scales:
self.scales[k]['item'].setGrid(g)
def viewGeometry(self):
"""return the screen geometry of the viewbox"""
@ -261,6 +279,8 @@ class PlotItem(QtGui.QGraphicsWidget):
return wr
def viewChanged(self, *args):
self.emit(QtCore.SIGNAL('viewChanged'), *args)
@ -273,23 +293,31 @@ class PlotItem(QtGui.QGraphicsWidget):
def yLinkComboChanged(self):
self.setYLink(str(self.ctrl.yLinkCombo.currentText()))
def setXLink(self, plotName=None):
if self.manager is None:
return
if self.xLinkPlot is not None:
self.manager.unlinkX(self, self.xLinkPlot)
plot = self.manager.getWidget(plotName)
def setXLink(self, plot=None):
"""Link this plot's X axis to another plot (pass either the PlotItem/PlotWidget or the registered name of the plot)"""
if isinstance(plot, basestring):
if self.manager is None:
return
if self.xLinkPlot is not None:
self.manager.unlinkX(self, self.xLinkPlot)
plot = self.manager.getWidget(plot)
if not isinstance(plot, PlotItem) and hasattr(plot, 'getPlotItem'):
plot = plot.getPlotItem()
self.xLinkPlot = plot
if plot is not None:
self.setManualXScale()
self.manager.linkX(self, plot)
def setYLink(self, plotName=None):
if self.manager is None:
return
if self.yLinkPlot is not None:
self.manager.unlinkY(self, self.yLinkPlot)
plot = self.manager.getWidget(plotName)
def setYLink(self, plot=None):
"""Link this plot's Y axis to another plot (pass either the PlotItem/PlotWidget or the registered name of the plot)"""
if isinstance(plot, basestring):
if self.manager is None:
return
if self.yLinkPlot is not None:
self.manager.unlinkY(self, self.yLinkPlot)
plot = self.manager.getWidget(plot)
if not isinstance(plot, PlotItem) and hasattr(plot, 'getPlotItem'):
plot = plot.getPlotItem()
self.yLinkPlot = plot
if plot is not None:
self.setManualYScale()
@ -339,6 +367,8 @@ class PlotItem(QtGui.QGraphicsWidget):
self.recomputeAverages()
def recomputeAverages(self):
if not self.ctrl.averageGroup.isChecked():
return
for k in self.avgCurves:
self.removeItem(self.avgCurves[k][1])
#Qwt.QwtPlotCurve.detach(self.avgCurves[k][1])
@ -406,6 +436,8 @@ class PlotItem(QtGui.QGraphicsWidget):
self.vb.setMouseEnabled(*state)
def xRangeChanged(self, _, range):
if any(isnan(range)) or any(isinf(range)):
raise Exception("yRange invalid: %s. Signal came from %s" % (str(range), str(self.sender())))
self.ctrl.xMinText.setText('%0.5g' % range[0])
self.ctrl.xMaxText.setText('%0.5g' % range[1])
@ -423,6 +455,8 @@ class PlotItem(QtGui.QGraphicsWidget):
self.emit(QtCore.SIGNAL('xRangeChanged'), self, range)
def yRangeChanged(self, _, range):
if any(isnan(range)) or any(isinf(range)):
raise Exception("yRange invalid: %s. Signal came from %s" % (str(range), str(self.sender())))
self.ctrl.yMinText.setText('%0.5g' % range[0])
self.ctrl.yMaxText.setText('%0.5g' % range[1])
@ -511,18 +545,25 @@ class PlotItem(QtGui.QGraphicsWidget):
if not item in self.items:
return
self.items.remove(item)
self.vb.removeItem(item)
if item.scene() is not None:
self.vb.removeItem(item)
if item in self.curves:
self.curves.remove(item)
self.updateDecimation()
self.updateParamList()
QtCore.QObject.connect(item, QtCore.SIGNAL('plotChanged'), self.plotChanged)
item.connect(QtCore.SIGNAL('plotChanged'), self.plotChanged)
def clear(self):
for i in self.items[:]:
self.removeItem(i)
self.avgCurves = {}
def clearPlots(self):
for i in self.curves[:]:
self.removeItem(i)
self.avgCurves = {}
def plot(self, data=None, x=None, clear=False, params=None, pen=None):
if clear:
self.clear()
@ -549,6 +590,8 @@ class PlotItem(QtGui.QGraphicsWidget):
return curve
def addCurve(self, c, params=None):
if params is None:
params = {}
c.setMeta(params)
self.curves.append(c)
#Qwt.QwtPlotCurve.attach(c, self)
@ -569,7 +612,7 @@ class PlotItem(QtGui.QGraphicsWidget):
if self.ctrl.averageGroup.isChecked():
self.addAvgCurve(c)
QtCore.QObject.connect(c, QtCore.SIGNAL('plotChanged'), self.plotChanged)
c.connect(QtCore.SIGNAL('plotChanged'), self.plotChanged)
self.plotChanged()
def plotChanged(self, curve=None):
@ -587,7 +630,7 @@ class PlotItem(QtGui.QGraphicsWidget):
mn = cmn
if mx is None or cmx > mx:
mx = cmx
if mn is None or mx is None:
if mn is None or mx is None or any(isnan([mn, mx])) or any(isinf([mn, mx])):
continue
if mn == mx:
mn -= 1
@ -632,24 +675,58 @@ class PlotItem(QtGui.QGraphicsWidget):
if fileName is None:
fileName = QtGui.QFileDialog.getSaveFileName()
fileName = str(fileName)
PlotItem.lastFileDir = os.path.dirname(fileName)
self.svg = QtSvg.QSvgGenerator()
self.svg.setFileName(fileName)
res = 120.
self.svg.setResolution(res)
self.svg.setSize(QtCore.QSize(self.size().width(), self.size().height()))
painter = QtGui.QPainter(self.svg)
#self.scene().render(painter, QtCore.QRectF(), self.mapRectToScene(self.boundingRect()))
items = self.scene().items()
self.scene().views()[0].drawItems(painter, len(items), items)
#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)
#self.svg.setSize(QtCore.QSize(self.size().width(), self.size().height()))
self.svg.setViewBox(bounds)
self.svg.setSize(QtCore.QSize(bounds.width(), bounds.height()))
painter = QtGui.QPainter(self.svg)
#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)
painter.end()
## Workaround to set pen widths correctly
import re
data = open(fileName).readlines()
for i in range(len(data)):
line = data[i]
m = re.match(r'(<g .*)stroke-width="1"(.*transform="matrix\(([^\)]+)\)".*)', line)
if m is not None:
#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):
if fileName is None:
fileName = QtGui.QFileDialog.getSaveFileName()
fileName = str(fileName)
PlotItem.lastFileDir = os.path.dirname(fileName)
self.png = QtGui.QImage(int(self.size().width()), int(self.size().height()), QtGui.QImage.Format_ARGB32)
painter = QtGui.QPainter(self.png)
painter.setRenderHints(painter.Antialiasing | painter.TextAntialiasing)
@ -657,6 +734,29 @@ class PlotItem(QtGui.QGraphicsWidget):
painter.end()
self.png.save(fileName)
def writeCsv(self, fileName=None):
if fileName is None:
fileName = QtGui.QFileDialog.getSaveFileName()
fileName = str(fileName)
PlotItem.lastFileDir = os.path.dirname(fileName)
fd = open(fileName, 'w')
data = [c.getData() for c in self.curves]
i = 0
while True:
done = True
for d in data:
if i < len(d[0]):
fd.write('%g,%g,'%(d[0][i], d[1][i]))
done = False
else:
fd.write(' , ,')
fd.write('\n')
if done:
break
i += 1
fd.close()
def saveState(self):
if not HAVE_WIDGETGROUP:
@ -672,8 +772,18 @@ class PlotItem(QtGui.QGraphicsWidget):
raise Exception("State save/restore requires WidgetGroup class.")
if 'paramList' in state:
self.paramList = state['paramList'].copy()
self.stateGroup.setState(state)
self.stateGroup.setState(state)
self.updateSpectrumMode()
self.updateDownsampling()
self.updateAlpha()
self.updateDecimation()
self.stateGroup.setState(state)
self.updateXScale()
self.updateYScale()
self.updateParamList()
#print "\nRESTORE %s:\n" % str(self.name), state
#print "Restoring state. averageGroup.isChecked(): %s state: %s" % (str(self.ctrl.averageGroup.isChecked()), str(state['averageGroup']))
#avg = self.ctrl.averageGroup.isChecked()
@ -787,7 +897,6 @@ class PlotItem(QtGui.QGraphicsWidget):
self.mouseScreenPos = ev.screenPos()
def ctrlBtnClicked(self):
#print self.mousePos
self.ctrlMenu.popup(self.mouseScreenPos)
#def _checkLabelKey(self, key):
@ -923,6 +1032,8 @@ class PlotItem(QtGui.QGraphicsWidget):
#self.fileDialog.setDirectory(PlotItem.lastFileDir)
self.fileDialog.setFileMode(QtGui.QFileDialog.AnyFile)
self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
if PlotItem.lastFileDir is not None:
self.fileDialog.setDirectory(PlotItem.lastFileDir)
self.fileDialog.show()
QtCore.QObject.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString)'), self.writeSvg)
@ -934,11 +1045,23 @@ class PlotItem(QtGui.QGraphicsWidget):
self.fileDialog = QtGui.QFileDialog()
#if PlotItem.lastFileDir is not None:
#self.fileDialog.setDirectory(PlotItem.lastFileDir)
if PlotItem.lastFileDir is not None:
self.fileDialog.setDirectory(PlotItem.lastFileDir)
self.fileDialog.setFileMode(QtGui.QFileDialog.AnyFile)
self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
self.fileDialog.show()
QtCore.QObject.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString)'), self.writeImage)
def saveCsvClicked(self):
self.fileDialog = QtGui.QFileDialog()
#if PlotItem.lastFileDir is not None:
#self.fileDialog.setDirectory(PlotItem.lastFileDir)
if PlotItem.lastFileDir is not None:
self.fileDialog.setDirectory(PlotItem.lastFileDir)
self.fileDialog.setFileMode(QtGui.QFileDialog.AnyFile)
self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
self.fileDialog.show()
QtCore.QObject.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString)'), self.writeCsv)
#def imgFileSelected(self, fileName):
##PlotWidget.lastFileDir = os.path.split(fileName)[0]
#self.writeImage(str(fileName))

View File

@ -11,17 +11,26 @@ import exceptions
class PlotWidget(GraphicsView):
"""Widget implementing a graphicsView with a single PlotItem inside."""
def __init__(self, parent=None):
def __init__(self, parent=None, **kargs):
GraphicsView.__init__(self, parent)
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
self.enableMouse(False)
self.plotItem = PlotItem()
self.plotItem = PlotItem(**kargs)
self.setCentralItem(self.plotItem)
## Explicitly wrap methods from plotItem
for m in ['addItem', 'autoRange', 'clear']:
for m in ['addItem', 'removeItem', 'autoRange', 'clear', 'setXRange', 'setYRange']:
setattr(self, m, getattr(self.plotItem, m))
QtCore.QObject.connect(self.plotItem, QtCore.SIGNAL('viewChanged'), self.viewChanged)
#def __dtor__(self):
##print "Called plotWidget sip destructor"
#self.quit()
def quit(self):
self.plotItem.clear()
self.scene().clear()
def __getattr__(self, attr): ## implicitly wrap methods from plotItem
if hasattr(self.plotItem, attr):
m = getattr(self.plotItem, attr)
@ -41,3 +50,5 @@ class PlotWidget(GraphicsView):
def restoreState(self, state):
return self.plotItem.restoreState(state)
def getPlotItem(self):
return self.plotItem

View File

@ -4,7 +4,7 @@ import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
from pyqtgraph.ImageView import *
from numpy import random
from numpy import random, linspace
from PyQt4 import QtCore, QtGui
from scipy.ndimage import *
@ -17,14 +17,27 @@ win.setCentralWidget(imv)
win.show()
## Create random 3D data set
img = gaussian_filter(random.random((200, 200)), (5, 5)) * 5
data = random.random((100, 200, 200))
data += img
for i in range(data.shape[0]):
data[i] += exp(-(2.*i)/data.shape[0])
data += 10
img = gaussian_filter(random.normal(size=(200, 200)), (5, 5)) * 20 + 100
img = img[newaxis,:,:]
decay = exp(-linspace(0,0.3,100))[:,newaxis,newaxis]
data = random.normal(size=(100, 200, 200))
data += img * decay
#for i in range(data.shape[0]):
#data[i] += 10*exp(-(2.*i)/data.shape[0])
data += 2
## Add time-varying signal
sig = zeros(data.shape[0])
sig[30:] += exp(-linspace(1,10, 70))
sig[40:] += exp(-linspace(1,10, 60))
sig[70:] += exp(-linspace(1,10, 30))
sig = sig[:,newaxis,newaxis] * 3
data[:,50:60,50:60] += sig
## Display the data
imv.setImage(data)
imv.setImage(data, xvals=linspace(1., 3., data.shape[0]))
app.exec_()

View File

@ -34,18 +34,26 @@ rect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, 0, 1, 1))
rect.setPen(QtGui.QPen(QtGui.QColor(100, 200, 100)))
pw.addItem(rect)
pen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(255, 255, 255, 10)), 5)
pen.setCosmetic(True)
#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, 50)))
#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(pw, 1.5, 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)
pw.addItem(l2)
#pw2.addItem(l2)
#pw.addItem(l3)
pw3.plot(array([100000]*100))
@ -72,12 +80,14 @@ updateData()
pw.autoRange()
t = QtCore.QTimer()
QtCore.QObject.connect(t, QtCore.SIGNAL('timeout()'), updateData)
t.start(50)
for i in range(0, 5):
for j in range(0, 3):
yd, xd = rand(10000)
pw2.plot(yd*(j+1), xd, params={'iter': i, 'val': j})
app.exec_()
#app.exec_()

View File

@ -19,7 +19,7 @@ class Win(QtGui.QMainWindow):
pass
w = Win()
v = GraphicsView()
v = GraphicsView(useOpenGL=False)
v.invertY(True)
v.setAspectLocked(True)
v.enableMouse(True)
@ -72,6 +72,9 @@ elroi = EllipseROI([110, 10], [30, 20])
s.addItem(elroi)
croi = CircleROI([110, 50], [20, 20])
s.addItem(croi)
troi = PolygonROI([[0,0], [1,0], [0,1]])
s.addItem(troi)
def updateImg(roi):
global im1, im2, im3, im4, arr
@ -80,11 +83,11 @@ def updateImg(roi):
arr2 = roi.getArrayRegion(arr, img=im2)
im4.updateImage(arr2, autoRange=True)
roi.connect(QtCore.SIGNAL('regionChanged'), lambda: updateImg(roi))
roi2.connect(QtCore.SIGNAL('regionChanged'), lambda: updateImg(roi2))
croi.connect(QtCore.SIGNAL('regionChanged'), lambda: updateImg(croi))
elroi.connect(QtCore.SIGNAL('regionChanged'), lambda: updateImg(elroi))
mlroi.connect(QtCore.SIGNAL('regionChanged'), lambda: updateImg(mlroi))
roi.connect(roi, QtCore.SIGNAL('regionChanged'), lambda: updateImg(roi))
roi2.connect(roi2, QtCore.SIGNAL('regionChanged'), lambda: updateImg(roi2))
croi.connect(croi, QtCore.SIGNAL('regionChanged'), lambda: updateImg(croi))
elroi.connect(elroi, QtCore.SIGNAL('regionChanged'), lambda: updateImg(elroi))
mlroi.connect(mlroi, QtCore.SIGNAL('regionChanged'), lambda: updateImg(mlroi))
v.setRange(QtCore.QRect(-2, -2, 220, 220))

View File

@ -30,7 +30,30 @@ vb = ViewBox()
p1 = PlotCurveItem()
vb.addItem(p1)
vl.addWidget(gv)
rect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, 0, 1, 1))
class movableRect(QtGui.QGraphicsRectItem):
def __init__(self, *args):
QtGui.QGraphicsRectItem.__init__(self, *args)
self.setAcceptHoverEvents(True)
def hoverEnterEvent(self, ev):
self.savedPen = self.pen()
self.setPen(QtGui.QPen(QtGui.QColor(255, 255, 255)))
ev.ignore()
def hoverLeaveEvent(self, ev):
self.setPen(self.savedPen)
ev.ignore()
def mousePressEvent(self, ev):
if ev.button() == QtCore.Qt.LeftButton:
ev.accept()
self.pressDelta = self.mapToParent(ev.pos()) - self.pos()
else:
ev.ignore()
def mouseMoveEvent(self, ev):
self.setPos(self.mapToParent(ev.pos()) - self.pressDelta)
#rect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, 0, 1, 1))
rect = movableRect(QtCore.QRectF(0, 0, 1, 1))
rect.setPen(QtGui.QPen(QtGui.QColor(100, 200, 100)))
vb.addItem(rect)
@ -67,4 +90,4 @@ t = QtCore.QTimer()
QtCore.QObject.connect(t, QtCore.SIGNAL('timeout()'), updateData)
t.start(50)
app.exec_()
#app.exec_()

File diff suppressed because it is too large Load Diff

View File

@ -8,13 +8,16 @@ Distributed under MIT/X11 license. See license.txt for more infomation.
from PyQt4 import QtCore, QtGui
from PlotWidget import *
from ImageView import *
QAPP = None
class PlotWindow(QtGui.QMainWindow):
def __init__(self, title=None):
if QtGui.QApplication.instance() is None:
global QAPP
QAPP = QtGui.QApplication([])
QtGui.QMainWindow.__init__(self)
self.cw = PlotWidget()
self.setCentralWidget(self.cw)
for m in ['plot', 'autoRange', 'addItem', 'setLabel', 'clear']:
for m in ['plot', 'autoRange', 'addItem', 'removeItem', 'setLabel', 'clear']:
setattr(self, m, getattr(self.cw, m))
if title is not None:
self.setWindowTitle(title)
@ -22,10 +25,13 @@ class PlotWindow(QtGui.QMainWindow):
class ImageWindow(QtGui.QMainWindow):
def __init__(self, title=None):
if QtGui.QApplication.instance() is None:
global QAPP
QAPP = QtGui.QApplication([])
QtGui.QMainWindow.__init__(self)
self.cw = ImageView()
self.setCentralWidget(self.cw)
for m in ['setImage', 'autoRange', 'addItem']:
for m in ['setImage', 'autoRange', 'addItem', 'removeItem', 'blackLevel', 'whiteLevel', 'imageItem']:
setattr(self, m, getattr(self.cw, m))
if title is not None:
self.setWindowTitle(title)

View File

@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'plotConfigTemplate.ui'
#
# Created: Mon Mar 29 22:40:47 2010
# by: PyQt4 UI code generator 4.6
# Created: Sat Jul 17 00:28:43 2010
# by: PyQt4 UI code generator 4.7.2
#
# WARNING! All changes made in this file will be lost!
@ -12,7 +12,7 @@ from PyQt4 import QtCore, QtGui
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(210, 340)
Form.resize(250, 340)
Form.setMaximumSize(QtCore.QSize(250, 350))
self.gridLayout_3 = QtGui.QGridLayout(Form)
self.gridLayout_3.setMargin(0)
@ -187,6 +187,7 @@ class Ui_Form(object):
self.verticalLayout_3.addWidget(self.alphaGroup)
self.gridGroup = QtGui.QGroupBox(self.tab_3)
self.gridGroup.setCheckable(True)
self.gridGroup.setChecked(False)
self.gridGroup.setObjectName("gridGroup")
self.verticalLayout_4 = QtGui.QVBoxLayout(self.gridGroup)
self.verticalLayout_4.setObjectName("verticalLayout_4")
@ -227,6 +228,9 @@ class Ui_Form(object):
self.saveMaBtn = QtGui.QPushButton(self.tab_4)
self.saveMaBtn.setObjectName("saveMaBtn")
self.gridLayout_6.addWidget(self.saveMaBtn, 2, 0, 1, 1)
self.saveCsvBtn = QtGui.QPushButton(self.tab_4)
self.saveCsvBtn.setObjectName("saveCsvBtn")
self.gridLayout_6.addWidget(self.saveCsvBtn, 3, 0, 1, 1)
self.gridLayout_7.addLayout(self.gridLayout_6, 0, 1, 1, 1)
spacerItem2 = QtGui.QSpacerItem(59, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_7.addItem(spacerItem2, 0, 2, 1, 1)
@ -281,5 +285,6 @@ class Ui_Form(object):
self.saveSvgBtn.setText(QtGui.QApplication.translate("Form", "SVG", None, QtGui.QApplication.UnicodeUTF8))
self.saveImgBtn.setText(QtGui.QApplication.translate("Form", "Image", None, QtGui.QApplication.UnicodeUTF8))
self.saveMaBtn.setText(QtGui.QApplication.translate("Form", "MetaArray", None, QtGui.QApplication.UnicodeUTF8))
self.saveCsvBtn.setText(QtGui.QApplication.translate("Form", "CSV", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_4), QtGui.QApplication.translate("Form", "Save", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>210</width>
<width>250</width>
<height>340</height>
</rect>
</property>
@ -35,7 +35,7 @@
</size>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@ -419,6 +419,9 @@
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QSlider" name="gridAlphaSlider">
@ -514,6 +517,13 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="saveCsvBtn">
<property name="text">
<string>CSV</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2">

1726
widgets.py

File diff suppressed because it is too large Load Diff