merged many new features from ACQ4

This commit is contained in:
Luke Campagnola 2013-02-10 17:45:16 -05:00
parent 0f0a9415af
commit 025f2e5575
8 changed files with 133 additions and 83 deletions

View File

@ -187,6 +187,7 @@ from .SRTTransform3D import SRTTransform3D
from .functions import *
from .graphicsWindows import *
from .SignalProxy import *
from .colormap import *
from .ptime import time

View File

@ -3,6 +3,25 @@ import scipy.interpolate
from pyqtgraph.Qt import QtGui, QtCore
class ColorMap(object):
"""
A ColorMap defines a relationship between a scalar value and a range of colors.
ColorMaps are commonly used for false-coloring monochromatic images, coloring
scatter-plot points, and coloring surface plots by height.
Each color map is defined by a set of colors, each corresponding to a
particular scalar value. For example:
| 0.0 -> black
| 0.2 -> red
| 0.6 -> yellow
| 1.0 -> white
The colors for intermediate values are determined by interpolating between
the two nearest colors in either RGB or HSV color space.
To provide user-defined color mappings, see :class:`GradientWidget <pyqtgraph.GradientWidget>`.
"""
## color interpolation modes
RGB = 1
@ -54,7 +73,16 @@ class ColorMap(object):
def map(self, data, mode='byte'):
"""
Return an array of colors corresponding to the values in *data*.
Data must be either a scalar position or an array (any shape) of positions.
The *mode* argument determines the type of data returned:
=========== ===============================================================
byte (default) Values are returned as 0-255 unsigned bytes.
float Values are returned as 0.0-1.0 floats.
qcolor Values are returned as an array of QColor objects.
=========== ===============================================================
"""
if isinstance(mode, basestring):
mode = self.enumMap[mode.lower()]
@ -80,16 +108,19 @@ class ColorMap(object):
return interp
def mapToQColor(self, data):
"""Convenience function; see :func:`map() <pyqtgraph.ColorMap.map>`."""
return self.map(data, mode=self.QCOLOR)
def mapToByte(self, data):
"""Convenience function; see :func:`map() <pyqtgraph.ColorMap.map>`."""
return self.map(data, mode=self.BYTE)
def mapToFloat(self, data):
"""Convenience function; see :func:`map() <pyqtgraph.ColorMap.map>`."""
return self.map(data, mode=self.FLOAT)
def getGradient(self, p1=None, p2=None):
"""Return a QLinearGradient object."""
"""Return a QLinearGradient object spanning from QPoints p1 to p2."""
if p1 == None:
p1 = QtCore.QPointF(0,0)
if p2 == None:
@ -119,7 +150,7 @@ class ColorMap(object):
return g
def getColors(self, mode=None):
"""Return list of all colors converted to the specified mode.
"""Return list of all color stops converted to the specified mode.
If mode is None, then no conversion is done."""
if isinstance(mode, basestring):
mode = self.enumMap[mode.lower()]
@ -158,75 +189,19 @@ class ColorMap(object):
self.stopsCache[mode] = (self.pos, color)
return self.stopsCache[mode]
#def getColor(self, x, toQColor=True):
#"""
#Return a color for a given value.
#============= ==================================================================
#**Arguments**
#x Value (position on gradient) of requested color.
#toQColor If true, returns a QColor object, else returns a (r,g,b,a) tuple.
#============= ==================================================================
#"""
#ticks = self.listTicks()
#if x <= ticks[0][1]:
#c = ticks[0][0].color
#if toQColor:
#return QtGui.QColor(c) # always copy colors before handing them out
#else:
#return (c.red(), c.green(), c.blue(), c.alpha())
#if x >= ticks[-1][1]:
#c = ticks[-1][0].color
#if toQColor:
#return QtGui.QColor(c) # always copy colors before handing them out
#else:
#return (c.red(), c.green(), c.blue(), c.alpha())
#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
#a = c1.alpha() * (1.-f) + c2.alpha() * f
#if toQColor:
#return QtGui.QColor(int(r), int(g), int(b), int(a))
#else:
#return (r,g,b,a)
#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)
#if toQColor:
#return c
#else:
#return (c.red(), c.green(), c.blue(), c.alpha())
def getLookupTable(self, start=0.0, stop=1.0, nPts=512, alpha=None, mode='byte'):
"""
Return an RGB(A) lookup table (ndarray).
============= ============================================================================
**Arguments**
nPts The number of points in the returned lookup table.
alpha True, False, or None - Specifies whether or not alpha values are included
in the table. If alpha is None, it will be automatically determined.
start The starting value in the lookup table (default=0.0)
stop The final value in the lookup table (default=1.0)
nPts The number of points in the returned lookup table.
alpha True, False, or None - Specifies whether or not alpha values are included
in the table. If alpha is None, it will be automatically determined.
mode Determines return type: 'byte' (0-255), 'float' (0.0-1.0), or 'qcolor'.
See :func:`map() <pyqtgraph.ColorMap.map>`.
============= ============================================================================
"""
if isinstance(mode, basestring):
@ -249,7 +224,9 @@ class ColorMap(object):
return np.any(self.color[:,3] != max)
def isMapTrivial(self):
"""Return True if the gradient has exactly two stops in it: black at 0.0 and white at 1.0"""
"""
Return True if the gradient has exactly two stops in it: black at 0.0 and white at 1.0.
"""
if len(self.pos) != 2:
return False
if self.pos[0] != 0.0 or self.pos[1] != 1.0:

View File

@ -566,8 +566,8 @@ def transformCoordinates(tr, coords, transpose=False):
def solve3DTransform(points1, points2):
"""
Find a 3D transformation matrix that maps points1 onto points2
points must be specified as a list of 4 Vectors.
Find a 3D transformation matrix that maps points1 onto points2.
Points must be specified as a list of 4 Vectors.
"""
if not HAVE_SCIPY:
raise Exception("This function depends on the scipy library, but it does not appear to be importable.")
@ -583,8 +583,8 @@ def solve3DTransform(points1, points2):
def solveBilinearTransform(points1, points2):
"""
Find a bilinear transformation matrix (2x4) that maps points1 onto points2
points must be specified as a list of 4 Vector, Point, QPointF, etc.
Find a bilinear transformation matrix (2x4) that maps points1 onto points2.
Points must be specified as a list of 4 Vector, Point, QPointF, etc.
To use this matrix to map a point [x,y]::

View File

@ -8,8 +8,9 @@ __all__ = ['GraphItem']
class GraphItem(GraphicsObject):
"""A GraphItem displays graph information (as in 'graph theory', not 'graphics') as
a set of nodes connected by lines.
"""A GraphItem displays graph information as
a set of nodes connected by lines (as in 'graph theory', not 'graphics').
Useful for drawing networks, trees, etc.
"""
def __init__(self, **kwds):
@ -28,19 +29,24 @@ class GraphItem(GraphicsObject):
============ =========================================================
Arguments
pos (N,2) array of the positions of each node in the graph
pos (N,2) array of the positions of each node in the graph.
adj (M,2) array of connection data. Each row contains indexes
of two nodes that are connected.
pen The pen to use when drawing lines between connected
nodes. May be one of:
* QPen
* a single argument to pass to pg.mkPen
* a record array of length M
with fields (red, green, blue, alpha, width).
with fields (red, green, blue, alpha, width). Note
that using this option may have a significant performance
cost.
* None (to disable connection drawing)
* 'default' to use the default foreground color.
symbolPen The pen used for drawing nodes.
**opts All other keyword arguments are given to ScatterPlotItem
``**opts`` All other keyword arguments are given to
:func:`ScatterPlotItem.setData() <pyqtgraph.ScatterPlotItem.setData>`
to affect the appearance of nodes (symbol, size, brush,
etc.)
============ =========================================================

View File

@ -14,10 +14,20 @@ class WidgetParameterItem(ParameterItem):
"""
ParameterTree item with:
- label in second column for displaying value
- simple widget for editing value (displayed instead of label when item is selected)
- button that resets value to default
- provides SpinBox, CheckBox, LineEdit, and ColorButton types
* label in second column for displaying value
* simple widget for editing value (displayed instead of label when item is selected)
* button that resets value to default
================= =============================================================
Registered Types:
int Displays a :class:`SpinBox <pyqtgraph.SpinBox>` in integer
mode.
float Displays a :class:`SpinBox <pyqtgraph.SpinBox>`.
bool Displays a QCheckBox
str Displays a QLineEdit
color Displays a :class:`ColorButton <pyqtgraph.ColorButton>`
colormap Displays a :class:`GradientWidget <pyqtgraph.GradientWidget>`
================= =============================================================
This class can be subclassed by overriding makeWidget() to provide a custom widget.
"""

View File

@ -9,9 +9,14 @@ __all__ = ['ColorMapWidget']
class ColorMapWidget(ptree.ParameterTree):
"""
This class provides a widget allowing the user to customize color mapping
for multi-column data.
"""
for multi-column data. Given a list of field names, the user may specify
multiple criteria for assigning colors to each record in a numpy record array.
Multiple criteria are evaluated and combined into a single color for each
record by user-defined compositing methods.
For simpler color mapping using a single gradient editor, see
:class:`GradientWidget <pyqtgraph.GradientWidget>`
"""
sigColorMapChanged = QtCore.Signal(object)
def __init__(self):
@ -51,6 +56,25 @@ class ColorMapParameter(ptree.types.GroupParameter):
return self.fields.keys()
def setFields(self, fields):
"""
Set the list of fields to be used by the mapper.
The format of *fields* is::
[ (fieldName, {options}), ... ]
============== ============================================================
Field Options:
mode Either 'range' or 'enum' (default is range). For 'range',
The user may specify a gradient of colors to be applied
linearly across a specific range of values. For 'enum',
the user specifies a single color for each unique value
(see *values* option).
units String indicating the units of the data for this field.
values List of unique values for which the user may assign a
color when mode=='enum'.
============== ============================================================
"""
self.fields = OrderedDict(fields)
#self.fields = fields
#self.fields.sort()
@ -58,6 +82,18 @@ class ColorMapParameter(ptree.types.GroupParameter):
self.setAddList(names)
def map(self, data, mode='byte'):
"""
Return an array of colors corresponding to *data*.
========= =================================================================
Arguments
data A numpy record array where the fields in data.dtype match those
defined by a prior call to setFields().
mode Either 'byte' or 'float'. For 'byte', the method returns an array
of dtype ubyte with values scaled 0-255. For 'float', colors are
returned as 0.0-1.0 float values.
========= =================================================================
"""
colors = np.zeros((len(data),4))
for item in self.children():
if not item['Enabled']:

View File

@ -9,11 +9,27 @@ __all__ = ['TickSlider', 'GradientWidget', 'BlackWhiteSlider']
class GradientWidget(GraphicsView):
"""
Widget displaying an editable color gradient. The user may add, move, recolor,
or remove colors from the gradient. Additionally, a context menu allows the
user to select from pre-defined gradients.
"""
sigGradientChanged = QtCore.Signal(object)
sigGradientChangeFinished = QtCore.Signal(object)
def __init__(self, parent=None, orientation='bottom', *args, **kargs):
"""
The *orientation* argument may be 'bottom', 'top', 'left', or 'right'
indicating whether the gradient is displayed horizontally (top, bottom)
or vertically (left, right) and on what side of the gradient the editable
ticks will appear.
All other arguments are passed to
:func:`GradientEditorItem.__init__ <pyqtgraph.GradientEditorItem.__init__>`.
Note: For convenience, this class wraps methods from
:class:`GradientEditorItem <pyqtgraph.GradientEditorItem>`.
"""
GraphicsView.__init__(self, parent, useOpenGL=False, background=None)
self.maxDim = 31
kargs['tickPen'] = 'k'
@ -32,6 +48,8 @@ class GradientWidget(GraphicsView):
#self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent, True)
def setOrientation(self, ort):
"""Set the orientation of the widget. May be one of 'bottom', 'top',
'left', or 'right'."""
self.item.setOrientation(ort)
self.orientation = ort
self.setMaxDim()

View File

@ -57,7 +57,9 @@ class ScatterPlotWidget(QtGui.QSplitter):
def setFields(self, fields):
"""
Set the list of field names/units to be processed.
Format is: [(name, units), ...]
The format of *fields* is the same as used by
:func:`ColorMapWidget.setFields <pyqtgraph.widgets.ColorMapWidget.ColorMapParameter.setFields>`
"""
self.fields = OrderedDict(fields)
self.fieldList.clear()