Commit a80f150b authored by Luke Campagnola's avatar Luke Campagnola
Browse files

merge with inp

parents 4cec9ff0 22bc2333
...@@ -10,5 +10,7 @@ Contents: ...@@ -10,5 +10,7 @@ Contents:
graphicsItems/index graphicsItems/index
widgets/index widgets/index
3dgraphics/index 3dgraphics/index
colormap
parametertree/index parametertree/index
graphicsscene/index graphicsscene/index
flowchart/index
ColorMap
========
.. autoclass:: pyqtgraph.ColorMap
:members:
.. automethod:: pyqtgraph.ColorMap.__init__
...@@ -91,6 +91,8 @@ Mesh Generation Functions ...@@ -91,6 +91,8 @@ Mesh Generation Functions
Miscellaneous Functions Miscellaneous Functions
----------------------- -----------------------
.. autofunction:: pyqtgraph.arrayToQPath
.. autofunction:: pyqtgraph.pseudoScatter .. autofunction:: pyqtgraph.pseudoScatter
.. autofunction:: pyqtgraph.systemInfo .. autofunction:: pyqtgraph.systemInfo
......
GraphItem
=========
.. autoclass:: pyqtgraph.GraphItem
:members:
.. automethod:: pyqtgraph.GraphItem.__init__
...@@ -12,6 +12,7 @@ Contents: ...@@ -12,6 +12,7 @@ Contents:
plotdataitem plotdataitem
plotitem plotitem
imageitem imageitem
graphitem
viewbox viewbox
linearregionitem linearregionitem
infiniteline infiniteline
......
...@@ -15,6 +15,7 @@ Contents: ...@@ -15,6 +15,7 @@ Contents:
mouse_interaction mouse_interaction
how_to_use how_to_use
installation installation
qtcrashcourse
plotting plotting
images images
3dgraphics 3dgraphics
......
...@@ -3,20 +3,76 @@ Qt Crash Course ...@@ -3,20 +3,76 @@ Qt Crash Course
Pyqtgraph makes extensive use of Qt for generating nearly all of its visual output and interfaces. Qt's documentation is very well written and we encourage all pyqtgraph developers to familiarize themselves with it. The purpose of this section is to provide an introduction to programming with Qt (using either PyQt or PySide) for the pyqtgraph developer. Pyqtgraph makes extensive use of Qt for generating nearly all of its visual output and interfaces. Qt's documentation is very well written and we encourage all pyqtgraph developers to familiarize themselves with it. The purpose of this section is to provide an introduction to programming with Qt (using either PyQt or PySide) for the pyqtgraph developer.
QWidgets and Layouts QWidgets and Layouts
-------------------- --------------------
A Qt GUI is almost always composed of a few basic components:
* A window. This is often provided by QMainWindow, but note that all QWidgets can be displayed in their window by simply calling widget.show() if the widget does not have a parent.
* Multiple QWidget instances such as QPushButton, QLabel, QComboBox, etc.
* QLayout instances (optional, but strongly encouraged) which automatically manage the positioning of widgets to allow the GUI to resize in a usable way.
Pyqtgraph fits into this scheme by providing its own QWidget subclasses to be inserted into your GUI.
Example::
from PyQt4 import QtGui # (the example applies equally well to PySide)
import pyqtgraph as pg
## Always start by initializing Qt (only once per application)
app = QtGui.QApplication([])
## Define a top-level widget to hold everything
w = QtGui.QWidget()
## Create some widgets to be placed inside
btn = QtGui.QPushButton('press me')
text = QtGui.QLineEdit('enter text')
listw = QtGui.QListWidget()
plot = pg.PlotWidget()
## Create a grid layout to manage the widgets size and position
layout = QtGui.QGridLayout()
w.setLayout(layout)
## Add widgets to the layout in their proper positions
layout.addWidget(btn, 0, 0) # button goes in upper-left
layout.addWidget(text, 1, 0) # text edit goes in middle-left
layout.addWidget(listw, 2, 0) # list widget goes in bottom-left
layout.addWidget(plot, 0, 1, 3, 1) # plot goes on right side, spanning 3 rows
## Display the widget as a new window
w.show()
## Start the Qt event loop
app.exec_()
More complex interfaces may be designed graphically using Qt Designer, which allows you to simply drag widgets into your window to define its appearance.
Naming Conventions
------------------
Virtually every class in pyqtgraph is an extension of base classes provided by Qt. When reading the documentation, remember that all of Qt's classes start with the letter 'Q', whereas pyqtgraph's classes do not. When reading through the methods for any class, it is often helpful to see which Qt base classes are used and look through the Qt documentation as well.
Most of Qt's classes define signals which can be difficult to tell apart from regular methods. Almost all signals explicity defined by pyqtgraph are named beginning with 'sig' to indicate that these signals are not defined at the Qt level.
In most cases, classes which end in 'Widget' are subclassed from QWidget and can therefore be used as a GUI element in a Qt window. Classes which end in 'Item' are subclasses of QGraphicsItem and can only be displayed within a QGraphicsView instance (such as GraphicsLayoutWidget or PlotWidget).
Signals, Slots, and Events Signals, Slots, and Events
-------------------------- --------------------------
[ to be continued.. please post a request on the pyqtgraph forum if you'd like to read more ]
GraphicsView and GraphicsItems GraphicsView and GraphicsItems
------------------------------ ------------------------------
Coordinate Systems Coordinate Systems and Transformations
------------------ --------------------------------------
Mouse and Keyboard Input Mouse and Keyboard Input
...@@ -26,3 +82,7 @@ Mouse and Keyboard Input ...@@ -26,3 +82,7 @@ Mouse and Keyboard Input
QTimer, the Event Loop, and Multi-Threading QTimer, the Event Loop, and Multi-Threading
------------------------------------------- -------------------------------------------
Multi-threading vs Multi-processing in Qt
-----------------------------------------
ColorMapWidget
==============
.. autoclass:: pyqtgraph.ColorMapWidget
:members:
.. automethod:: pyqtgraph.ColorMapWidget.__init__
.. automethod:: pyqtgraph.widgets.ColorMapWidget.ColorMapParameter.setFields
.. automethod:: pyqtgraph.widgets.ColorMapWidget.ColorMapParameter.map
\ No newline at end of file
...@@ -17,6 +17,8 @@ Contents: ...@@ -17,6 +17,8 @@ Contents:
gradientwidget gradientwidget
histogramlutwidget histogramlutwidget
parametertree parametertree
colormapwidget
scatterplotwidget
graphicsview graphicsview
rawimagewidget rawimagewidget
datatreewidget datatreewidget
......
ScatterPlotWidget
=================
.. autoclass:: pyqtgraph.ScatterPlotWidget
:members:
.. automethod:: pyqtgraph.ScatterPlotWidget.__init__
...@@ -27,6 +27,7 @@ examples = OrderedDict([ ...@@ -27,6 +27,7 @@ examples = OrderedDict([
('Scatter Plot', 'ScatterPlot.py'), ('Scatter Plot', 'ScatterPlot.py'),
#('PlotItem', 'PlotItem.py'), #('PlotItem', 'PlotItem.py'),
('IsocurveItem', 'isocurve.py'), ('IsocurveItem', 'isocurve.py'),
('GraphItem', 'GraphItem.py'),
('ImageItem - video', 'ImageItem.py'), ('ImageItem - video', 'ImageItem.py'),
('ImageItem - draw', 'Draw.py'), ('ImageItem - draw', 'Draw.py'),
('Region-of-Interest', 'ROIExamples.py'), ('Region-of-Interest', 'ROIExamples.py'),
......
...@@ -4,7 +4,7 @@ PyQtGraph - Scientific Graphics and GUI Library for Python ...@@ -4,7 +4,7 @@ PyQtGraph - Scientific Graphics and GUI Library for Python
www.pyqtgraph.org www.pyqtgraph.org
""" """
__version__ = '0.9.5' __version__ = None
### import all the goodies and add some helper functions for easy CLI use ### import all the goodies and add some helper functions for easy CLI use
...@@ -187,6 +187,7 @@ from .SRTTransform3D import SRTTransform3D ...@@ -187,6 +187,7 @@ from .SRTTransform3D import SRTTransform3D
from .functions import * from .functions import *
from .graphicsWindows import * from .graphicsWindows import *
from .SignalProxy import * from .SignalProxy import *
from .colormap import *
from .ptime import time from .ptime import time
......
...@@ -3,6 +3,25 @@ import scipy.interpolate ...@@ -3,6 +3,25 @@ import scipy.interpolate
from pyqtgraph.Qt import QtGui, QtCore from pyqtgraph.Qt import QtGui, QtCore
class ColorMap(object): 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 ## color interpolation modes
RGB = 1 RGB = 1
...@@ -54,7 +73,16 @@ class ColorMap(object): ...@@ -54,7 +73,16 @@ class ColorMap(object):
def map(self, data, mode='byte'): 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. 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): if isinstance(mode, basestring):
mode = self.enumMap[mode.lower()] mode = self.enumMap[mode.lower()]
...@@ -80,16 +108,19 @@ class ColorMap(object): ...@@ -80,16 +108,19 @@ class ColorMap(object):
return interp return interp
def mapToQColor(self, data): def mapToQColor(self, data):
"""Convenience function; see :func:`map() <pyqtgraph.ColorMap.map>`."""
return self.map(data, mode=self.QCOLOR) return self.map(data, mode=self.QCOLOR)
def mapToByte(self, data): def mapToByte(self, data):
"""Convenience function; see :func:`map() <pyqtgraph.ColorMap.map>`."""
return self.map(data, mode=self.BYTE) return self.map(data, mode=self.BYTE)
def mapToFloat(self, data): def mapToFloat(self, data):
"""Convenience function; see :func:`map() <pyqtgraph.ColorMap.map>`."""
return self.map(data, mode=self.FLOAT) return self.map(data, mode=self.FLOAT)
def getGradient(self, p1=None, p2=None): def getGradient(self, p1=None, p2=None):
"""Return a QLinearGradient object.""" """Return a QLinearGradient object spanning from QPoints p1 to p2."""
if p1 == None: if p1 == None:
p1 = QtCore.QPointF(0,0) p1 = QtCore.QPointF(0,0)
if p2 == None: if p2 == None:
...@@ -119,7 +150,7 @@ class ColorMap(object): ...@@ -119,7 +150,7 @@ class ColorMap(object):
return g return g
def getColors(self, mode=None): 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 mode is None, then no conversion is done."""
if isinstance(mode, basestring): if isinstance(mode, basestring):
mode = self.enumMap[mode.lower()] mode = self.enumMap[mode.lower()]
...@@ -158,75 +189,19 @@ class ColorMap(object): ...@@ -158,75 +189,19 @@ class ColorMap(object):
self.stopsCache[mode] = (self.pos, color) self.stopsCache[mode] = (self.pos, color)
return self.stopsCache[mode] 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'): def getLookupTable(self, start=0.0, stop=1.0, nPts=512, alpha=None, mode='byte'):
""" """
Return an RGB(A) lookup table (ndarray). Return an RGB(A) lookup table (ndarray).
============= ============================================================================ ============= ============================================================================
**Arguments** **Arguments**
nPts The number of points in the returned lookup table. start The starting value in the lookup table (default=0.0)
alpha True, False, or None - Specifies whether or not alpha values are included stop The final value in the lookup table (default=1.0)
in the table. If alpha is None, it will be automatically determined. 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): if isinstance(mode, basestring):
...@@ -249,7 +224,9 @@ class ColorMap(object): ...@@ -249,7 +224,9 @@ class ColorMap(object):
return np.any(self.color[:,3] != max) return np.any(self.color[:,3] != max)
def isMapTrivial(self): 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: if len(self.pos) != 2:
return False return False
if self.pos[0] != 0.0 or self.pos[1] != 1.0: if self.pos[0] != 0.0 or self.pos[1] != 1.0:
......
...@@ -566,8 +566,8 @@ def transformCoordinates(tr, coords, transpose=False): ...@@ -566,8 +566,8 @@ def transformCoordinates(tr, coords, transpose=False):
def solve3DTransform(points1, points2): def solve3DTransform(points1, points2):
""" """
Find a 3D transformation matrix that maps points1 onto points2 Find a 3D transformation matrix that maps points1 onto points2.
points must be specified as a list of 4 Vectors. Points must be specified as a list of 4 Vectors.
""" """
if not HAVE_SCIPY: if not HAVE_SCIPY:
raise Exception("This function depends on the scipy library, but it does not appear to be importable.") 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): ...@@ -583,8 +583,8 @@ def solve3DTransform(points1, points2):
def solveBilinearTransform(points1, points2): def solveBilinearTransform(points1, points2):
""" """
Find a bilinear transformation matrix (2x4) that maps points1 onto 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. Points must be specified as a list of 4 Vector, Point, QPointF, etc.
To use this matrix to map a point [x,y]:: To use this matrix to map a point [x,y]::
......
...@@ -8,8 +8,9 @@ __all__ = ['GraphItem'] ...@@ -8,8 +8,9 @@ __all__ = ['GraphItem']
class GraphItem(GraphicsObject): class GraphItem(GraphicsObject):
"""A GraphItem displays graph information (as in 'graph theory', not 'graphics') as """A GraphItem displays graph information as
a set of nodes connected by lines. a set of nodes connected by lines (as in 'graph theory', not 'graphics').
Useful for drawing networks, trees, etc.
""" """
def __init__(self, **kwds): def __init__(self, **kwds):
...@@ -28,19 +29,24 @@ class GraphItem(GraphicsObject): ...@@ -28,19 +29,24 @@ class GraphItem(GraphicsObject):
============ ========================================================= ============ =========================================================
Arguments 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 adj (M,2) array of connection data. Each row contains indexes
of two nodes that are connected. of two nodes that are connected.
pen The pen to use when drawing lines between connected pen The pen to use when drawing lines between connected
nodes. May be one of: nodes. May be one of:
* QPen * QPen
* a single argument to pass to pg.mkPen * a single argument to pass to pg.mkPen
* a record array of length M * 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) * None (to disable connection drawing)
* 'default' to use the default foreground color. * 'default' to use the default foreground color.
symbolPen The pen used for drawing nodes. 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, to affect the appearance of nodes (symbol, size, brush,
etc.) etc.)
============ ========================================================= ============ =========================================================
......
...@@ -204,7 +204,8 @@ class GraphicsItem(object): ...@@ -204,7 +204,8 @@ class GraphicsItem(object):
return tuple(map(Point, self._pixelVectorCache[1])) ## return a *copy* return tuple(map(Point, self._pixelVectorCache[1])) ## return a *copy*
## check global cache ## check global cache
key = (dt.m11(), dt.m21(), dt.m31(), dt.m12(), dt.m22(), dt.m32(), dt.m31(), dt.m32()) #key = (dt.m11(), dt.m21(), dt.m31(), dt.m12(), dt.m22(), dt.m32(), dt.m31(), dt.m32())
key = (dt.m11(), dt.m21(), dt.m12(), dt.m22())
pv = self._pixelVectorGlobalCache.get(key, None) pv = self._pixelVectorGlobalCache.get(key, None)
if direction is None and pv is not None: if direction is None and pv is not None:
self._pixelVectorCache = [dt, pv] self._pixelVectorCache = [dt, pv]
......
...@@ -472,8 +472,8 @@ class ScatterPlotItem(GraphicsObject): ...@@ -472,8 +472,8 @@ class ScatterPlotItem(GraphicsObject):
if isinstance(symbol, np.ndarray) or isinstance(symbol, list): if isinstance(symbol, np.ndarray) or isinstance(symbol, list):
symbols = symbol symbols = symbol
if kargs['mask'] is not None: if mask is not None:
symbols = symbols[kargs['mask']] symbols = symbols[mask]
if len(symbols) != len(dataSet): if len(symbols) != len(dataSet):
raise Exception("Number of symbols does not match number of points (%d != %d)" % (len(symbols), len(dataSet))) raise Exception("Number of symbols does not match number of points (%d != %d)" % (len(symbols), len(dataSet)))
dataSet['symbol'] = symbols dataSet['symbol'] = symbols
...@@ -554,6 +554,7 @@ class ScatterPlotItem(GraphicsObject): ...@@ -554,6 +554,7 @@ class ScatterPlotItem(GraphicsObject):
#rec['fragCoords'] = self.fragmentAtlas.getSymbolCoords(*self.getSpotOpts(rec)) #rec['fragCoords'] = self.fragmentAtlas.getSymbolCoords(*self.getSpotOpts(rec))
if invalidate: if invalidate:
self.invalidate() self.invalidate()
self.informViewBoundsChanged()
def getSpotOpts(self, recs, scale=1.0): def getSpotOpts(self, recs, scale=1.0):
if recs.ndim == 0: if recs.ndim == 0:
...@@ -671,6 +672,7 @@ class ScatterPlotItem(GraphicsObject): ...@@ -671,6 +672,7 @@ class ScatterPlotItem(GraphicsObject):
GraphicsObject.viewTransformChanged(self) GraphicsObject.viewTransformChanged(self)
self.bounds = [None, None] self.bounds = [None, None]
self.fragments = None self.fragments = None
self.informViewBoundsChanged()
def generateFragments(self): def generateFragments(self):
tr = self.deviceTransform() tr = self.deviceTransform()
......
...@@ -298,9 +298,11 @@ class ViewBox(GraphicsWidget): ...@@ -298,9 +298,11 @@ class ViewBox(GraphicsWidget):
def resizeEvent(self, ev): def resizeEvent(self, ev):
#self.setRange(self.range, padding=0) #self.setRange(self.range, padding=0)
#self.updateAutoRange() #self.updateAutoRange()
self._itemBoundsCache.clear()
self.updateMatrix() self.updateMatrix()
self.sigStateChanged.emit(self) self.sigStateChanged.emit(self)
self.background.setRect(self.rect()) self.background.setRect(self.rect())
#self.linkedXChanged()