Commit 661e4411 authored by Luke Campagnola's avatar Luke Campagnola
Browse files

Numerous fixes

added scatter plots
parent dbcdf7ec
...@@ -163,10 +163,16 @@ class TickSlider(QtGui.QGraphicsView): ...@@ -163,10 +163,16 @@ class TickSlider(QtGui.QGraphicsView):
class GradientWidget(TickSlider): class GradientWidget(TickSlider):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
TickSlider.__init__(self, *args, **kargs) TickSlider.__init__(self, *args, **kargs)
self.currentTick = None
self.currentTickColor = None
self.rectSize = 15 self.rectSize = 15
self.gradRect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, -self.rectSize, 100, self.rectSize)) self.gradRect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, -self.rectSize, 100, self.rectSize))
self.colorMode = 'rgb' self.colorMode = 'rgb'
self.colorDialog = QtGui.QColorDialog()
self.colorDialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, 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('rejected()'), 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)
...@@ -200,16 +206,27 @@ class GradientWidget(TickSlider): ...@@ -200,16 +206,27 @@ class GradientWidget(TickSlider):
self.gradRect.setRect(0, -self.rectSize, newLen, self.rectSize) self.gradRect.setRect(0, -self.rectSize, newLen, self.rectSize)
self.updateGradient() self.updateGradient()
def currentColorChanged(self, color):
if color.isValid() and self.currentTick is not None:
self.setTickColor(self.currentTick, color)
self.updateGradient()
def currentColorRejected(self):
self.setTickColor(self.currentTick, self.currentTickColor)
self.updateGradient()
def tickClicked(self, tick, ev): def tickClicked(self, tick, ev):
if ev.button() == QtCore.Qt.LeftButton: if ev.button() == QtCore.Qt.LeftButton:
if not tick.colorChangeAllowed: if not tick.colorChangeAllowed:
return return
color = QtGui.QColorDialog.getColor(tick.color, None, "Select Color", QtGui.QColorDialog.ShowAlphaChannel) self.currentTick = tick
if color.isValid(): self.currentTickColor = tick.color
self.setTickColor(tick, color) self.colorDialog.setCurrentColor(tick.color)
self.updateGradient() self.colorDialog.open()
#color = QtGui.QColorDialog.getColor(tick.color, self, "Select Color", QtGui.QColorDialog.ShowAlphaChannel)
#if color.isValid():
#self.setTickColor(tick, color)
#self.updateGradient()
elif ev.button() == QtCore.Qt.RightButton: elif ev.button() == QtCore.Qt.RightButton:
if not tick.removeAllowed: if not tick.removeAllowed:
return return
...@@ -267,7 +284,8 @@ class GradientWidget(TickSlider): ...@@ -267,7 +284,8 @@ class GradientWidget(TickSlider):
r = c1.red() * (1.-f) + c2.red() * f r = c1.red() * (1.-f) + c2.red() * f
g = c1.green() * (1.-f) + c2.green() * f g = c1.green() * (1.-f) + c2.green() * f
b = c1.blue() * (1.-f) + c2.blue() * f b = c1.blue() * (1.-f) + c2.blue() * f
return QtGui.QColor(r, g, b) a = c1.alpha() * (1.-f) + c2.alpha() * f
return QtGui.QColor(r, g, b,a)
elif self.colorMode == 'hsv': elif self.colorMode == 'hsv':
h1,s1,v1,_ = c1.getHsv() h1,s1,v1,_ = c1.getHsv()
h2,s2,v2,_ = c2.getHsv() h2,s2,v2,_ = c2.getHsv()
...@@ -292,6 +310,43 @@ class GradientWidget(TickSlider): ...@@ -292,6 +310,43 @@ class GradientWidget(TickSlider):
t.removeAllowed = True t.removeAllowed = True
return t return t
def saveState(self):
ticks = []
for t in self.ticks:
c = t.color
ticks.append((self.ticks[t], (c.red(), c.green(), c.blue(), c.alpha())))
state = {'mode': self.colorMode, 'ticks': ticks}
return state
def restoreState(self, state):
self.setColorMode(state['mode'])
for t in self.ticks.keys():
self.removeTick(t)
for t in state['ticks']:
c = QtGui.QColor(*t[1])
self.addTick(t[0], c)
self.updateGradient()
class BlackWhiteSlider(GradientWidget):
def __init__(self, parent):
GradientWidget.__init__(self, parent)
self.getTick(0).colorChangeAllowed = False
self.getTick(1).colorChangeAllowed = False
self.allowAdd = False
self.setTickColor(self.getTick(1), QtGui.QColor(255,255,255))
self.setOrientation('right')
def getLevels(self):
return (self.tickValue(0), self.tickValue(1))
def setLevels(self, black, white):
self.setTickValue(0, black)
self.setTickValue(1, white)
class GammaWidget(TickSlider): class GammaWidget(TickSlider):
pass pass
...@@ -361,4 +416,31 @@ class Tick(QtGui.QGraphicsPolygonItem): ...@@ -361,4 +416,31 @@ class Tick(QtGui.QGraphicsPolygonItem):
#self.view.tickChanged(self) #self.view.tickChanged(self)
if __name__ == '__main__':
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)
\ No newline at end of file
# -*- 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)
...@@ -27,6 +27,8 @@ class GraphicsView(QtGui.QGraphicsView): ...@@ -27,6 +27,8 @@ class GraphicsView(QtGui.QGraphicsView):
enabled via enableMouse().""" enabled via enableMouse()."""
QtGui.QGraphicsView.__init__(self, parent) QtGui.QGraphicsView.__init__(self, parent)
if 'linux' in sys.platform: ## linux has bugs in opengl implementation
useOpenGL = False
self.useOpenGL(useOpenGL) self.useOpenGL(useOpenGL)
palette = QtGui.QPalette() palette = QtGui.QPalette()
...@@ -139,6 +141,7 @@ class GraphicsView(QtGui.QGraphicsView): ...@@ -139,6 +141,7 @@ 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)
if propagate: if propagate:
for v in self.lockedViewports: for v in self.lockedViewports:
...@@ -190,7 +193,6 @@ class GraphicsView(QtGui.QGraphicsView): ...@@ -190,7 +193,6 @@ 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)
self.emit(QtCore.SIGNAL('viewChanged'), self.range)
def lockXRange(self, v1): def lockXRange(self, v1):
......
...@@ -18,8 +18,9 @@ from graphicsItems import * ...@@ -18,8 +18,9 @@ from graphicsItems import *
from widgets import ROI from widgets import ROI
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
import sys import sys
from numpy import ndarray #from numpy import ndarray
import ptime import ptime
import numpy as np
from SignalProxy import proxyConnect from SignalProxy import proxyConnect
...@@ -52,7 +53,7 @@ class ImageView(QtGui.QWidget): ...@@ -52,7 +53,7 @@ class ImageView(QtGui.QWidget):
self.ui.graphicsView.invertY() self.ui.graphicsView.invertY()
self.ui.graphicsView.enableMouse() self.ui.graphicsView.enableMouse()
self. ticks = [t[0] for t in self.ui.gradientWidget.listTicks()] self.ticks = [t[0] for t in self.ui.gradientWidget.listTicks()]
self.ticks[0].colorChangeAllowed = False self.ticks[0].colorChangeAllowed = False
self.ticks[1].colorChangeAllowed = False self.ticks[1].colorChangeAllowed = False
self.ui.gradientWidget.allowAdd = False self.ui.gradientWidget.allowAdd = False
...@@ -301,14 +302,14 @@ class ImageView(QtGui.QWidget): ...@@ -301,14 +302,14 @@ class ImageView(QtGui.QWidget):
axes = (1, 2) axes = (1, 2)
else: else:
return return
data = self.roi.getArrayRegion(image.view(ndarray), self.imageItem, axes) data = self.roi.getArrayRegion(image.view(np.ndarray), self.imageItem, axes)
if data is not None: if data is not None:
while data.ndim > 1: while data.ndim > 1:
data = data.mean(axis=1) data = data.mean(axis=1)
self.roiCurve.setData(y=data, x=self.tVals) self.roiCurve.setData(y=data, x=self.tVals)
#self.ui.roiPlot.replot() #self.ui.roiPlot.replot()
def setImage(self, img, autoRange=True, autoLevels=True, levels=None, axes=None, xvals=None): def setImage(self, img, autoRange=True, autoLevels=True, levels=None, axes=None, xvals=None, pos=None, scale=None):
"""Set the image to be displayed in the widget. """Set the image to be displayed in the widget.
Options are: Options are:
img: ndarray; the image to be displayed. img: ndarray; the image to be displayed.
...@@ -319,16 +320,19 @@ class ImageView(QtGui.QWidget): ...@@ -319,16 +320,19 @@ class ImageView(QtGui.QWidget):
This is only needed to override the default guess. This is only needed to override the default guess.
""" """
if not isinstance(img, 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
if xvals is not None: if xvals is not None:
self.tVals = xvals self.tVals = xvals
elif hasattr(img, 'xvals'): elif hasattr(img, 'xvals'):
self.tVals = img.xvals(0) try:
self.tVals = img.xvals(0)
except:
self.tVals = np.arange(img.shape[0])
else: else:
self.tVals = arange(img.shape[0]) self.tVals = np.arange(img.shape[0])
#self.ui.timeSlider.setValue(0) #self.ui.timeSlider.setValue(0)
#self.ui.normStartSlider.setValue(0) #self.ui.normStartSlider.setValue(0)
#self.ui.timeSlider.setMaximum(img.shape[0]-1) #self.ui.timeSlider.setMaximum(img.shape[0]-1)
...@@ -346,13 +350,13 @@ class ImageView(QtGui.QWidget): ...@@ -346,13 +350,13 @@ class ImageView(QtGui.QWidget):
self.imageDisp = None self.imageDisp = None
if autoRange:
self.autoRange()
if autoLevels: if autoLevels:
self.autoLevels() self.autoLevels()
if levels is not None: if levels is not None:
self.levelMax = levels[1] self.levelMax = levels[1]
self.levelMin = levels[0] self.levelMin = levels[0]
self.currentIndex = 0
self.updateImage() self.updateImage()
if self.ui.roiBtn.isChecked(): if self.ui.roiBtn.isChecked():
self.roiChanged() self.roiChanged()
...@@ -361,6 +365,7 @@ class ImageView(QtGui.QWidget): ...@@ -361,6 +365,7 @@ class ImageView(QtGui.QWidget):
if self.axes['t'] is not None: if self.axes['t'] is not None:
#self.ui.roiPlot.show() #self.ui.roiPlot.show()
self.ui.roiPlot.setXRange(self.tVals.min(), self.tVals.max()) self.ui.roiPlot.setXRange(self.tVals.min(), self.tVals.max())
self.timeLine.setValue(0)
#self.ui.roiPlot.setMouseEnabled(False, False) #self.ui.roiPlot.setMouseEnabled(False, False)
if len(self.tVals) > 1: if len(self.tVals) > 1:
start = self.tVals.min() start = self.tVals.min()
...@@ -376,6 +381,14 @@ class ImageView(QtGui.QWidget): ...@@ -376,6 +381,14 @@ class ImageView(QtGui.QWidget):
#else: #else:
#self.ui.roiPlot.hide() #self.ui.roiPlot.hide()
self.imageItem.resetTransform()
if scale is not None:
self.imageItem.scale(*scale)
if scale is not None:
self.imageItem.setPos(*pos)
if autoRange:
self.autoRange()
self.roiClicked() self.roiClicked()
...@@ -389,10 +402,12 @@ class ImageView(QtGui.QWidget): ...@@ -389,10 +402,12 @@ class ImageView(QtGui.QWidget):
self.ui.gradientWidget.setTickValue(self.ticks[1], 1.0) self.ui.gradientWidget.setTickValue(self.ticks[1], 1.0)
self.imageItem.setLevels(white=self.whiteLevel(), black=self.blackLevel()) self.imageItem.setLevels(white=self.whiteLevel(), black=self.blackLevel())
def autoRange(self): def autoRange(self):
image = self.getProcessedImage() image = self.getProcessedImage()
self.ui.graphicsView.setRange(QtCore.QRectF(0, 0, image.shape[self.axes['x']], image.shape[self.axes['y']]), padding=0., lockAspect=True) #self.ui.graphicsView.setRange(QtCore.QRectF(0, 0, image.shape[self.axes['x']], image.shape[self.axes['y']]), padding=0., lockAspect=True)
self.ui.graphicsView.setRange(self.imageItem.sceneBoundingRect(), padding=0., lockAspect=True)
def getProcessedImage(self): def getProcessedImage(self):
if self.imageDisp is None: if self.imageDisp is None:
...@@ -408,7 +423,7 @@ class ImageView(QtGui.QWidget): ...@@ -408,7 +423,7 @@ class ImageView(QtGui.QWidget):
return image return image
div = self.ui.normDivideRadio.isChecked() div = self.ui.normDivideRadio.isChecked()
norm = image.view(ndarray).copy() norm = image.view(np.ndarray).copy()
#if div: #if div:
#norm = ones(image.shape) #norm = ones(image.shape)
#else: #else:
...@@ -498,7 +513,7 @@ class ImageView(QtGui.QWidget): ...@@ -498,7 +513,7 @@ class ImageView(QtGui.QWidget):
return (0,0) return (0,0)
totTime = xv[-1] + (xv[-1]-xv[-2]) totTime = xv[-1] + (xv[-1]-xv[-2])
#t = f * totTime #t = f * totTime
inds = argwhere(xv < t) inds = np.argwhere(xv < t)
if len(inds) < 1: if len(inds) < 1:
return (0,t) return (0,t)
ind = inds[-1,0] ind = inds[-1,0]
......
This diff is collapsed.
...@@ -23,6 +23,7 @@ from PyQt4 import QtGui, QtCore, QtSvg ...@@ -23,6 +23,7 @@ from PyQt4 import QtGui, QtCore, QtSvg
#from ObjectWorkaround import * #from ObjectWorkaround import *
#tryWorkaround(QtCore, QtGui) #tryWorkaround(QtCore, QtGui)
import weakref import weakref
import numpy as np
try: try:
from WidgetGroup import * from WidgetGroup import *
...@@ -37,8 +38,6 @@ except: ...@@ -37,8 +38,6 @@ except:
HAVE_METAARRAY = False HAVE_METAARRAY = False
class PlotItem(QtGui.QGraphicsWidget): class PlotItem(QtGui.QGraphicsWidget):
"""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
...@@ -132,6 +131,7 @@ class PlotItem(QtGui.QGraphicsWidget): ...@@ -132,6 +131,7 @@ class PlotItem(QtGui.QGraphicsWidget):
self.items = [] self.items = []
self.curves = [] self.curves = []
self.dataItems = []
self.paramList = {} self.paramList = {}
self.avgCurves = {} self.avgCurves = {}
...@@ -436,7 +436,7 @@ class PlotItem(QtGui.QGraphicsWidget): ...@@ -436,7 +436,7 @@ class PlotItem(QtGui.QGraphicsWidget):
self.vb.setMouseEnabled(*state) self.vb.setMouseEnabled(*state)
def xRangeChanged(self, _, range): def xRangeChanged(self, _, range):
if any(isnan(range)) or any(isinf(range)): if any(np.isnan(range)) or any(np.isinf(range)):
raise Exception("yRange invalid: %s. Signal came from %s" % (str(range), str(self.sender()))) raise Exception("yRange invalid: %s. Signal came from %s" % (str(range), str(self.sender())))
self.ctrl.xMinText.setText('%0.5g' % range[0]) self.ctrl.xMinText.setText('%0.5g' % range[0])
self.ctrl.xMaxText.setText('%0.5g' % range[1]) self.ctrl.xMaxText.setText('%0.5g' % range[1])
...@@ -455,7 +455,7 @@ class PlotItem(QtGui.QGraphicsWidget): ...@@ -455,7 +455,7 @@ class PlotItem(QtGui.QGraphicsWidget):
self.emit(QtCore.SIGNAL('xRangeChanged'), self, range) self.emit(QtCore.SIGNAL('xRangeChanged'), self, range)
def yRangeChanged(self, _, range): def yRangeChanged(self, _, range):
if any(isnan(range)) or any(isinf(range)): if any(np.isnan(range)) or any(np.isinf(range)):
raise Exception("yRange invalid: %s. Signal came from %s" % (str(range), str(self.sender()))) raise Exception("yRange invalid: %s. Signal came from %s" % (str(range), str(self.sender())))
self.ctrl.yMinText.setText('%0.5g' % range[0]) self.ctrl.yMinText.setText('%0.5g' % range[0])
self.ctrl.yMaxText.setText('%0.5g' % range[1]) self.ctrl.yMaxText.setText('%0.5g' % range[1])
...@@ -545,6 +545,9 @@ class PlotItem(QtGui.QGraphicsWidget): ...@@ -545,6 +545,9 @@ class PlotItem(QtGui.QGraphicsWidget):
if not item in self.items: if not item in self.items:
return return
self.items.remove(item) self.items.remove(item)
if item in self.dataItems:
self.dataItems.remove(item)
if item.scene() is not None: if item.scene() is not None:
self.vb.removeItem(item) self.vb.removeItem(item)
if item in self.curves: if item in self.curves:
...@@ -571,12 +574,12 @@ class PlotItem(QtGui.QGraphicsWidget): ...@@ -571,12 +574,12 @@ class PlotItem(QtGui.QGraphicsWidget):
params = {} params = {}
if HAVE_METAARRAY and isinstance(data, MetaArray): if HAVE_METAARRAY and isinstance(data, MetaArray):
curve = self._plotMetaArray(data, x=x) curve = self._plotMetaArray(data, x=x)
elif isinstance(data, ndarray): elif isinstance(data, np.ndarray):
curve = self._plotArray(data, x=x) curve = self._plotArray(data, x=x)
elif isinstance(data, list): elif isinstance(data, list):
if x is not None: if x is not None:
x = array(x) x = np.array(x)
curve = self._plotArray(array(data), x=x) curve = self._plotArray(np.array(data), x=x)
elif data is None: elif data is None:
curve = PlotCurveItem() curve = PlotCurveItem()
else: else:
...@@ -589,6 +592,10 @@ class PlotItem(QtGui.QGraphicsWidget): ...@@ -589,6 +592,10 @@ class PlotItem(QtGui.QGraphicsWidget):
return curve return curve
def addDataItem(self, item):
self.addItem(item)
self.dataItems.append(item)
def addCurve(self, c, params=None): def addCurve(self, c, params=None):
if params is None: if params is None:
params = {} params = {}
...@@ -622,7 +629,7 @@ class PlotItem(QtGui.QGraphicsWidget): ...@@ -622,7 +629,7 @@ class PlotItem(QtGui.QGraphicsWidget):
percentScale = [self.ctrl.xAutoPercentSpin.value(), self.ctrl.yAutoPercentSpin.value()][ax] * 0.01 percentScale = [self.ctrl.xAutoPercentSpin.value(), self.ctrl.yAutoPercentSpin.value()][ax] * 0.01
mn = None mn = None
mx = None mx = None
for c in self.curves + [c[1] for c in self.avgCurves.values()]: for c in self.curves + [c[1] for c in self.avgCurves.values()] + self.dataItems:
if not c.isVisible(): if not c.isVisible():
continue continue
cmn, cmx = c.getRange(ax, percentScale) cmn, cmx = c.getRange(ax, percentScale)
...@@ -630,7 +637,7 @@ class PlotItem(QtGui.QGraphicsWidget): ...@@ -630,7 +637,7 @@ class PlotItem(QtGui.QGraphicsWidget):
mn = cmn mn = cmn
if mx is None or cmx > mx: if mx is None or cmx > mx:
mx = cmx mx = cmx
if mn is None or mx is None or any(isnan([mn, mx])) or any(isinf([mn, mx])): if mn is None or mx is None or any(np.isnan([mn, mx])) or any(np.isinf([mn, mx])):
continue continue
if mn == mx: if mn == mx:
mn -= 1 mn -= 1
...@@ -1013,7 +1020,7 @@ class PlotItem(QtGui.QGraphicsWidget): ...@@ -1013,7 +1020,7 @@ class PlotItem(QtGui.QGraphicsWidget):
else: else:
xv = x xv = x
c = PlotCurveItem() c = PlotCurveItem()
c.setData(x=xv, y=arr.view(ndarray)) c.setData(x=xv, y=arr.view(np.ndarray))
if autoLabel: if autoLabel:
name = arr._info[0].get('name', None) name = arr._info[0].get('name', None)
......
...@@ -20,7 +20,10 @@ class Point(QtCore.QPointF): ...@@ -20,7 +20,10 @@ class Point(QtCore.QPointF):
def __init__(self, *args): def __init__(self, *args):
if len(args) == 1: if len(args) == 1:
if hasattr(args[0], '__getitem__'): if isinstance(args[0], QtCore.QSizeF):
QtCore.QPointF.__init__(self, float(args[0].width()), float(args[0].height()))
return
elif hasattr(args[0], '__getitem__'):
QtCore.QPointF.__init__(self, float(args[0][0]), float(args[0][1])) QtCore.QPointF.__init__(self, float(args[0][0]), float(args[0][1]))
return return
elif type(args[0]) in [float, int]: elif type(args[0]) in [float, int]:
...@@ -31,6 +34,9 @@ class Point(QtCore.QPointF): ...@@ -31,6 +34,9 @@ class Point(QtCore.QPointF):
return return
QtCore.QPointF.__init__(self, *args) QtCore.QPointF.__init__(self, *args)