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):
class GradientWidget(TickSlider):
def __init__(self, *args, **kargs):
TickSlider.__init__(self, *args, **kargs)
self.currentTick = None
self.currentTickColor = None
self.rectSize = 15
self.gradRect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, -self.rectSize, 100, self.rectSize))
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.scene.addItem(self.gradRect)
......@@ -200,16 +206,27 @@ class GradientWidget(TickSlider):
self.gradRect.setRect(0, -self.rectSize, newLen, self.rectSize)
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):
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()
self.currentTick = tick
self.currentTickColor = tick.color
self.colorDialog.setCurrentColor(tick.color)
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:
if not tick.removeAllowed:
return
......@@ -267,7 +284,8 @@ class GradientWidget(TickSlider):
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)
a = c1.alpha() * (1.-f) + c2.alpha() * f
return QtGui.QColor(r, g, b,a)
elif self.colorMode == 'hsv':
h1,s1,v1,_ = c1.getHsv()
h2,s2,v2,_ = c2.getHsv()
......@@ -292,6 +310,43 @@ class GradientWidget(TickSlider):
t.removeAllowed = True
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):
pass
......@@ -361,4 +416,31 @@ class Tick(QtGui.QGraphicsPolygonItem):
#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):
enabled via enableMouse()."""
QtGui.QGraphicsView.__init__(self, parent)
if 'linux' in sys.platform: ## linux has bugs in opengl implementation
useOpenGL = False
self.useOpenGL(useOpenGL)
palette = QtGui.QPalette()
......@@ -139,6 +141,7 @@ class GraphicsView(QtGui.QGraphicsView):
#print " translate:", st
self.setMatrix(m)
self.currentScale = scale
self.emit(QtCore.SIGNAL('viewChanged'), self.range)
if propagate:
for v in self.lockedViewports:
......@@ -190,7 +193,6 @@ class GraphicsView(QtGui.QGraphicsView):
#print "New Range:", self.range
self.centralWidget.setGeometry(self.range)
self.updateMatrix(propagate)
self.emit(QtCore.SIGNAL('viewChanged'), self.range)
def lockXRange(self, v1):
......
......@@ -18,8 +18,9 @@ from graphicsItems import *
from widgets import ROI
from PyQt4 import QtCore, QtGui
import sys
from numpy import ndarray
#from numpy import ndarray
import ptime
import numpy as np
from SignalProxy import proxyConnect
......@@ -52,7 +53,7 @@ class ImageView(QtGui.QWidget):
self.ui.graphicsView.invertY()
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[1].colorChangeAllowed = False
self.ui.gradientWidget.allowAdd = False
......@@ -301,14 +302,14 @@ class ImageView(QtGui.QWidget):
axes = (1, 2)
else:
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:
while data.ndim > 1:
data = data.mean(axis=1)
self.roiCurve.setData(y=data, x=self.tVals)
#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.
Options are:
img: ndarray; the image to be displayed.
......@@ -319,16 +320,19 @@ class ImageView(QtGui.QWidget):
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.")
self.image = img
if xvals is not None:
self.tVals = 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:
self.tVals = arange(img.shape[0])
self.tVals = np.arange(img.shape[0])
#self.ui.timeSlider.setValue(0)
#self.ui.normStartSlider.setValue(0)
#self.ui.timeSlider.setMaximum(img.shape[0]-1)
......@@ -346,13 +350,13 @@ class ImageView(QtGui.QWidget):
self.imageDisp = None
if autoRange:
self.autoRange()
if autoLevels:
self.autoLevels()
if levels is not None:
self.levelMax = levels[1]
self.levelMin = levels[0]
self.currentIndex = 0
self.updateImage()
if self.ui.roiBtn.isChecked():
self.roiChanged()
......@@ -361,6 +365,7 @@ class ImageView(QtGui.QWidget):
if self.axes['t'] is not None:
#self.ui.roiPlot.show()
self.ui.roiPlot.setXRange(self.tVals.min(), self.tVals.max())
self.timeLine.setValue(0)
#self.ui.roiPlot.setMouseEnabled(False, False)
if len(self.tVals) > 1:
start = self.tVals.min()
......@@ -376,6 +381,14 @@ class ImageView(QtGui.QWidget):
#else:
#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()
......@@ -389,10 +402,12 @@ class ImageView(QtGui.QWidget):
self.ui.gradientWidget.setTickValue(self.ticks[1], 1.0)
self.imageItem.setLevels(white=self.whiteLevel(), black=self.blackLevel())
def autoRange(self):
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):
if self.imageDisp is None:
......@@ -408,7 +423,7 @@ class ImageView(QtGui.QWidget):
return image
div = self.ui.normDivideRadio.isChecked()
norm = image.view(ndarray).copy()
norm = image.view(np.ndarray).copy()
#if div:
#norm = ones(image.shape)
#else:
......@@ -498,7 +513,7 @@ class ImageView(QtGui.QWidget):
return (0,0)
totTime = xv[-1] + (xv[-1]-xv[-2])
#t = f * totTime
inds = argwhere(xv < t)
inds = np.argwhere(xv < t)
if len(inds) < 1:
return (0,t)
ind = inds[-1,0]
......
#
# The Python Imaging Library.
# $Id$
#
# the Image class wrapper
#
# partial release history:
# 1995-09-09 fl Created
# 1996-03-11 fl PIL release 0.0 (proof of concept)
# 1996-04-30 fl PIL release 0.1b1
# 1999-07-28 fl PIL release 1.0 final
# 2000-06-07 fl PIL release 1.1
# 2000-10-20 fl PIL release 1.1.1
# 2001-05-07 fl PIL release 1.1.2
# 2002-03-15 fl PIL release 1.1.3
# 2003-05-10 fl PIL release 1.1.4
# 2005-03-28 fl PIL release 1.1.5
# 2006-12-02 fl PIL release 1.1.6
# 2009-11-15 fl PIL release 1.1.7
#
# Copyright (c) 1997-2009 by Secret Labs AB. All rights reserved.
# Copyright (c) 1995-2009 by Fredrik Lundh.
#
# See the README file for information on usage and redistribution.
#
VERSION = "1.1.7"
try:
import warnings
except ImportError:
warnings = None
class _imaging_not_installed:
# module placeholder
def __getattr__(self, id):
raise ImportError("The _imaging C module is not installed")
try:
# give Tk a chance to set up the environment, in case we're
# using an _imaging module linked against libtcl/libtk (use
# __import__ to hide this from naive packagers; we don't really
# depend on Tk unless ImageTk is used, and that module already
# imports Tkinter)
__import__("FixTk")
except ImportError:
pass
try:
# If the _imaging C module is not present, you can still use
# the "open" function to identify files, but you cannot load
# them. Note that other modules should not refer to _imaging
# directly; import Image and use the Image.core variable instead.
import _imaging
core = _imaging
del _imaging
except ImportError, v:
core = _imaging_not_installed()
if str(v)[:20] == "Module use of python" and warnings:
# The _imaging C module is present, but not compiled for
# the right version (windows only). Print a warning, if
# possible.
warnings.warn(
"The _imaging extension was built for another version "
"of Python; most PIL functions will be disabled",
RuntimeWarning
)
import ImageMode
import ImagePalette
import os, string, sys
# type stuff
from types import IntType, StringType, TupleType
try:
UnicodeStringType = type(unicode(""))
##
# (Internal) Checks if an object is a string. If the current
# Python version supports Unicode, this checks for both 8-bit
# and Unicode strings.
def isStringType(t):
return isinstance(t, StringType) or isinstance(t, UnicodeStringType)
except NameError:
def isStringType(t):
return isinstance(t, StringType)
##
# (Internal) Checks if an object is a tuple.
def isTupleType(t):
return isinstance(t, TupleType)
##
# (Internal) Checks if an object is an image object.
def isImageType(t):
return hasattr(t, "im")
##
# (Internal) Checks if an object is a string, and that it points to a
# directory.
def isDirectory(f):
return isStringType(f) and os.path.isdir(f)
from operator import isNumberType, isSequenceType
#
# Debug level
DEBUG = 0
#
# Constants (also defined in _imagingmodule.c!)
NONE = 0
# transpose
FLIP_LEFT_RIGHT = 0
FLIP_TOP_BOTTOM = 1
ROTATE_90 = 2
ROTATE_180 = 3
ROTATE_270 = 4
# transforms
AFFINE = 0
EXTENT = 1
PERSPECTIVE = 2
QUAD = 3
MESH = 4
# resampling filters
NONE = 0
NEAREST = 0
ANTIALIAS = 1 # 3-lobed lanczos
LINEAR = BILINEAR = 2
CUBIC = BICUBIC = 3
# dithers
NONE = 0
NEAREST = 0
ORDERED = 1 # Not yet implemented
RASTERIZE = 2 # Not yet implemented
FLOYDSTEINBERG = 3 # default
# palettes/quantizers
WEB = 0
ADAPTIVE = 1
# categories
NORMAL = 0
SEQUENCE = 1
CONTAINER = 2
# --------------------------------------------------------------------
# Registries
ID = []
OPEN = {}
MIME = {}
SAVE = {}
EXTENSION = {}
# --------------------------------------------------------------------
# Modes supported by this version
_MODEINFO = {
# NOTE: this table will be removed in future versions. use
# getmode* functions or ImageMode descriptors instead.
# official modes
"1": ("L", "L", ("1",)),
"L": ("L", "L", ("L",)),
"I": ("L", "I", ("I",)),
"F": ("L", "F", ("F",)),
"P": ("RGB", "L", ("P",)),
"RGB": ("RGB", "L", ("R", "G", "B")),
"RGBX": ("RGB", "L", ("R", "G", "B", "X")),
"RGBA": ("RGB", "L", ("R", "G", "B", "A")),
"CMYK": ("RGB", "L", ("C", "M", "Y", "K")),
"YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")),
# Experimental modes include I;16, I;16L, I;16B, RGBa, BGR;15, and
# BGR;24. Use these modes only if you know exactly what you're
# doing...
}
try:
byteorder = sys.byteorder
except AttributeError:
import struct
if struct.unpack("h", "\0\1")[0] == 1:
byteorder = "big"
else:
byteorder = "little"
if byteorder == 'little':
_ENDIAN = '<'
else:
_ENDIAN = '>'
_MODE_CONV = {
# official modes
"1": ('|b1', None), # broken
"L": ('|u1', None),
"I": (_ENDIAN + 'i4', None),
"I;16": ('%su2' % _ENDIAN, None),
"F": (_ENDIAN + 'f4', None),
"P": ('|u1', None),
"RGB": ('|u1', 3),
"RGBX": ('|u1', 4),
"RGBA": ('|u1', 4),
"CMYK": ('|u1', 4),
"YCbCr": ('|u1', 4),
}
def _conv_type_shape(im):
shape = im.size[1], im.size[0]
typ, extra = _MODE_CONV[im.mode]
if extra is None:
return shape, typ
else:
return shape+(extra,), typ
MODES = _MODEINFO.keys()
MODES.sort()
# raw modes that may be memory mapped. NOTE: if you change this, you
# may have to modify the stride calculation in map.c too!
_MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16L", "I;16B")
##
# Gets the "base" mode for given mode. This function returns "L" for
# images that contain grayscale data, and "RGB" for images that
# contain color data.
#
# @param mode Input mode.
# @return "L" or "RGB".
# @exception KeyError If the input mode was not a standard mode.
def getmodebase(mode):
return ImageMode.getmode(mode).basemode
##
# Gets the storage type mode. Given a mode, this function returns a
# single-layer mode suitable for storing individual bands.
#
# @param mode Input mode.
# @return "L", "I", or "F".
# @exception KeyError If the input mode was not a standard mode.
def getmodetype(mode):
return ImageMode.getmode(mode).basetype
##
# Gets a list of individual band names. Given a mode, this function
# returns a tuple containing the names of individual bands (use
# {@link #getmodetype} to get the mode used to store each individual
# band.
#
# @param mode Input mode.
# @return A tuple containing band names. The length of the tuple
# gives the number of bands in an image of the given mode.
# @exception KeyError If the input mode was not a standard mode.
def getmodebandnames(mode):
return ImageMode.getmode(mode).bands
##
# Gets the number of individual bands for this mode.
#
# @param mode Input mode.
# @return The number of bands in this mode.
# @exception KeyError If the input mode was not a standard mode.
def getmodebands(mode):
return len(ImageMode.getmode(mode).bands)
# --------------------------------------------------------------------
# Helpers
_initialized = 0
##
# Explicitly loads standard file format drivers.
def preinit():
"Load standard file format drivers."
global _initialized
if _initialized >= 1:
return
try:
import BmpImagePlugin
except ImportError:
pass
try:
import GifImagePlugin
except ImportError:
pass
try:
import JpegImagePlugin
except ImportError:
pass
try:
import PpmImagePlugin
except ImportError:
pass
try:
import PngImagePlugin