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

documentation updates

parent 61ea0361
...@@ -51,3 +51,21 @@ SI Unit Conversion Functions ...@@ -51,3 +51,21 @@ SI Unit Conversion Functions
.. autofunction:: pyqtgraph.siEval .. autofunction:: pyqtgraph.siEval
Image Preparation Functions
---------------------------
.. autofunction:: pyqtgraph.makeARGB
.. autofunction:: pyqtgraph.makeQImage
Mesh Generation Functions
-------------------------
.. autofunction:: pyqtgraph.isocurve
.. autofunction:: pyqtgraph.isosurface
Internals - Extensions to Qt's GraphicsView Internals - Extensions to Qt's GraphicsView
================================ ===========================================
* GraphicsView * GraphicsView
* GraphicsScene (mouse events) * GraphicsScene (mouse events)
......
...@@ -740,13 +740,13 @@ def rescaleData(data, scale, offset): ...@@ -740,13 +740,13 @@ def rescaleData(data, scale, offset):
def isocurve(data, level): def isocurve(data, level):
""" """
Generate isocurve from 2D data using marching squares algorithm. Generate isocurve from 2D data using marching squares algorithm.
*data* 2D numpy array of scalar values *data* 2D numpy array of scalar values
*level* The level at which to generate an isosurface *level* The level at which to generate an isosurface
This function is SLOW; plenty of room for optimization here. This function is SLOW; plenty of room for optimization here.
""" """
sideTable = [ sideTable = [
[], [],
...@@ -820,7 +820,7 @@ def isocurve(data, level): ...@@ -820,7 +820,7 @@ def isocurve(data, level):
def isosurface(data, level): def isosurface(data, level):
""" """
Generate isosurface from volumetric data using marching tetrahedra algorithm. Generate isosurface from volumetric data using marching cubes algorithm.
See Paul Bourke, "Polygonising a Scalar Field" See Paul Bourke, "Polygonising a Scalar Field"
(http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/) (http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/)
...@@ -1196,60 +1196,3 @@ def isosurface(data, level): ...@@ -1196,60 +1196,3 @@ def isosurface(data, level):
return facets return facets
## code has moved to opengl/MeshData.py
#def meshNormals(data):
#"""
#Return list of normal vectors and list of faces which reference the normals
#data must be list of triangles; each triangle is a list of three points
#[ [(x,y,z), (x,y,z), (x,y,z)], ...]
#Return values are
#normals: [(x,y,z), ...]
#faces: [(n1, n2, n3), ...]
#"""
#normals = []
#points = {}
#for i, face in enumerate(data):
### compute face normal
#pts = [QtGui.QVector3D(*x) for x in face]
#norm = QtGui.QVector3D.crossProduct(pts[1]-pts[0], pts[2]-pts[0])
#normals.append(norm)
### remember each point was associated with this normal
#for p in face:
#p = tuple(map(lambda x: np.round(x, 8), p))
#if p not in points:
#points[p] = []
#points[p].append(i)
### compute averages
#avgLookup = {}
#avgNorms = []
#for k,v in points.iteritems():
#norms = [normals[i] for i in v]
#a = norms[0]
#if len(v) > 1:
#for n in norms[1:]:
#a = a + n
#a = a / len(v)
#avgLookup[k] = len(avgNorms)
#avgNorms.append(a)
### generate return array
#faces = []
#for i, face in enumerate(data):
#f = []
#for p in face:
#p = tuple(map(lambda x: np.round(x, 8), p))
#f.append(avgLookup[p])
#faces.append(tuple(f))
#return avgNorms, faces
...@@ -6,6 +6,7 @@ __all__ = ['GraphicsLayout'] ...@@ -6,6 +6,7 @@ __all__ = ['GraphicsLayout']
class GraphicsLayout(GraphicsWidget): class GraphicsLayout(GraphicsWidget):
""" """
Used for laying out GraphicsWidgets in a grid. Used for laying out GraphicsWidgets in a grid.
This is usually created automatically as part of a :class:`GraphicsWindow <pyqtgraph.GraphicsWindow>` or :class:`GraphicsLayoutWidget <pyqtgraph.GraphicsLayoutWidget>`.
""" """
...@@ -33,29 +34,54 @@ class GraphicsLayout(GraphicsWidget): ...@@ -33,29 +34,54 @@ class GraphicsLayout(GraphicsWidget):
return self.currentCol-colspan return self.currentCol-colspan
def nextCol(self, *args, **kargs): def nextCol(self, *args, **kargs):
"""Advance to next column for automatic item placement"""
return self.nextColumn(*args, **kargs) return self.nextColumn(*args, **kargs)
def addPlot(self, row=None, col=None, rowspan=1, colspan=1, **kargs): def addPlot(self, row=None, col=None, rowspan=1, colspan=1, **kargs):
"""
Create a PlotItem and place it in the next available cell (or in the cell specified)
All extra keyword arguments are passed to :func:`PlotItem.__init__ <pyqtgraph.PlotItem.__init__>`
Returns the created item.
"""
plot = PlotItem(**kargs) plot = PlotItem(**kargs)
self.addItem(plot, row, col, rowspan, colspan) self.addItem(plot, row, col, rowspan, colspan)
return plot return plot
def addViewBox(self, row=None, col=None, rowspan=1, colspan=1, **kargs): def addViewBox(self, row=None, col=None, rowspan=1, colspan=1, **kargs):
"""
Create a ViewBox and place it in the next available cell (or in the cell specified)
All extra keyword arguments are passed to :func:`ViewBox.__init__ <pyqtgraph.ViewBox.__init__>`
Returns the created item.
"""
vb = ViewBox(**kargs) vb = ViewBox(**kargs)
self.addItem(vb, row, col, rowspan, colspan) self.addItem(vb, row, col, rowspan, colspan)
return vb return vb
def addLabel(self, text=' ', row=None, col=None, rowspan=1, colspan=1, **kargs): def addLabel(self, text=' ', row=None, col=None, rowspan=1, colspan=1, **kargs):
"""
Create a LabelItem with *text* and place it in the next available cell (or in the cell specified)
All extra keyword arguments are passed to :func:`LabelItem.__init__ <pyqtgraph.LabelItem.__init__>`
Returns the created item.
"""
text = LabelItem(text, **kargs) text = LabelItem(text, **kargs)
self.addItem(text, row, col, rowspan, colspan) self.addItem(text, row, col, rowspan, colspan)
return text return text
def addLayout(self, row=None, col=None, rowspan=1, colspan=1, **kargs): def addLayout(self, row=None, col=None, rowspan=1, colspan=1, **kargs):
"""
Create an empty GraphicsLayout and place it in the next available cell (or in the cell specified)
All extra keyword arguments are passed to :func:`GraphicsLayout.__init__ <pyqtgraph.GraphicsLayout.__init__>`
Returns the created item.
"""
layout = GraphicsLayout(**kargs) layout = GraphicsLayout(**kargs)
self.addItem(layout, row, col, rowspan, colspan) self.addItem(layout, row, col, rowspan, colspan)
return layout return layout
def addItem(self, item, row=None, col=None, rowspan=1, colspan=1): def addItem(self, item, row=None, col=None, rowspan=1, colspan=1):
"""
Add an item to the layout and place it in the next available cell (or in the cell specified).
The item must be an instance of a QGraphicsWidget subclass.
"""
if row is None: if row is None:
row = self.currentRow row = self.currentRow
if col is None: if col is None:
...@@ -69,6 +95,7 @@ class GraphicsLayout(GraphicsWidget): ...@@ -69,6 +95,7 @@ class GraphicsLayout(GraphicsWidget):
self.layout.addItem(item, row, col, rowspan, colspan) self.layout.addItem(item, row, col, rowspan, colspan)
def getItem(self, row, col): def getItem(self, row, col):
"""Return the item in (*row*, *col*)"""
return self.row[row][col] return self.row[row][col]
def boundingRect(self): def boundingRect(self):
...@@ -89,6 +116,7 @@ class GraphicsLayout(GraphicsWidget): ...@@ -89,6 +116,7 @@ class GraphicsLayout(GraphicsWidget):
raise Exception("Could not determine index of item " + str(item)) raise Exception("Could not determine index of item " + str(item))
def removeItem(self, item): def removeItem(self, item):
"""Remove *item* from the layout."""
ind = self.itemIndex(item) ind = self.itemIndex(item)
self.layout.removeAt(ind) self.layout.removeAt(ind)
self.scene().removeItem(item) self.scene().removeItem(item)
......
...@@ -55,24 +55,35 @@ except: ...@@ -55,24 +55,35 @@ except:
class PlotItem(GraphicsWidget): class PlotItem(GraphicsWidget):
sigYRangeChanged = QtCore.Signal(object, object)
sigXRangeChanged = QtCore.Signal(object, object)
sigRangeChanged = QtCore.Signal(object, object)
""" """
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.
Use plot(...) to create a new PlotDataItem and add it to the view. Use :func:`plot() <pyqtgraph.PlotItem.plot>` to create a new PlotDataItem and add it to the view.
Use addItem(...) add any QGraphicsItem to the view Use :func:`addItem() <pyqtgraph.PlotItem.addItem>` to add any QGraphicsItem to the view
This class wraps several methods from its internal ViewBox: This class wraps several methods from its internal ViewBox:
setXRange, setYRange, setXLink, setYLink, :func:`setXRange <pyqtgraph.ViewBox.setXRange>`,
setRange, autoRange, viewRect, setMouseEnabled, :func:`setYRange <pyqtgraph.ViewBox.setYRange>`,
enableAutoRange, disableAutoRange, setAspectLocked, :func:`setRange <pyqtgraph.ViewBox.setRange>`,
register, unregister. :func:`autoRange <pyqtgraph.ViewBox.autoRange>`,
:func:`setXLink <pyqtgraph.ViewBox.setXLink>`,
:func:`setYLink <pyqtgraph.ViewBox.setYLink>`,
:func:`viewRect <pyqtgraph.ViewBox.viewRect>`,
:func:`setMouseEnabled <pyqtgraph.ViewBox.setMouseEnabled>`,
:func:`enableAutoRange <pyqtgraph.ViewBox.enableAutoRange>`,
:func:`disableAutoRange <pyqtgraph.ViewBox.disableAutoRange>`,
:func:`setAspectLocked <pyqtgraph.ViewBox.setAspectLocked>`,
:func:`register <pyqtgraph.ViewBox.register>`,
:func:`unregister <pyqtgraph.ViewBox.unregister>`
The ViewBox itself can be accessed by calling getVewBox() The ViewBox itself can be accessed by calling :func:`getViewBox() <pyqtgraph.PlotItem.getViewBox>`
""" """
sigRangeChanged = QtCore.Signal(object, object) ## Emitted when the ViewBox range has changed
sigYRangeChanged = QtCore.Signal(object, object) ## Emitted when the ViewBox Y range has changed
sigXRangeChanged = QtCore.Signal(object, object) ## Emitted when the ViewBox X range has changed
lastFileDir = None lastFileDir = None
managers = {} managers = {}
...@@ -81,14 +92,18 @@ class PlotItem(GraphicsWidget): ...@@ -81,14 +92,18 @@ class PlotItem(GraphicsWidget):
Create a new PlotItem. All arguments are optional. Create a new PlotItem. All arguments are optional.
Any extra keyword arguments are passed to PlotItem.plot(). Any extra keyword arguments are passed to PlotItem.plot().
Arguments: ============= ==========================================================================================
*title* - Title to display at the top of the item. Html is allowed. **Arguments**
*labels* - A dictionary specifying the axis labels to display. *title* Title to display at the top of the item. Html is allowed.
{'left': (args), 'bottom': (args), ...} *labels* A dictionary specifying the axis labels to display::
The name of each axis and the corresponding arguments are passed to PlotItem.setLabel()
Optionally, PlotItem my also be initialized with the keyword arguments left, {'left': (args), 'bottom': (args), ...}
right, top, or bottom to achieve the same effect.
*name* - Registers a name for this view so that others may link to it The name of each axis and the corresponding arguments are passed to PlotItem.setLabel()
Optionally, PlotItem my also be initialized with the keyword arguments left,
right, top, or bottom to achieve the same effect.
*name* Registers a name for this view so that others may link to it
============= ==========================================================================================
""" """
...@@ -165,7 +180,7 @@ class PlotItem(GraphicsWidget): ...@@ -165,7 +180,7 @@ class PlotItem(GraphicsWidget):
'setXRange', 'setYRange', 'setXLink', 'setYLink', 'setXRange', 'setYRange', 'setXLink', 'setYLink',
'setRange', 'autoRange', 'viewRect', 'setMouseEnabled', 'setRange', 'autoRange', 'viewRect', 'setMouseEnabled',
'enableAutoRange', 'disableAutoRange', 'setAspectLocked', 'enableAutoRange', 'disableAutoRange', 'setAspectLocked',
'register', 'unregister']: 'register', 'unregister']: ## NOTE: If you update this list, please update the class docstring as well.
setattr(self, m, getattr(self.vb, m)) setattr(self, m, getattr(self.vb, m))
self.items = [] self.items = []
...@@ -779,7 +794,7 @@ class PlotItem(GraphicsWidget): ...@@ -779,7 +794,7 @@ class PlotItem(GraphicsWidget):
def plot(self, *args, **kargs): def plot(self, *args, **kargs):
""" """
Add and return a new plot. Add and return a new plot.
See PlotDataItem.__init__ for data arguments See :func:`PlotDataItem.__init__ <pyqtgraph.PlotDataItem.__init__>` for data arguments
Extra allowed arguments are: Extra allowed arguments are:
clear - clear all plots before displaying new data clear - clear all plots before displaying new data
...@@ -1262,13 +1277,16 @@ class PlotItem(GraphicsWidget): ...@@ -1262,13 +1277,16 @@ class PlotItem(GraphicsWidget):
def setLabel(self, axis, text=None, units=None, unitPrefix=None, **args): def setLabel(self, axis, text=None, units=None, unitPrefix=None, **args):
""" """
Set the label for an axis. Basic HTML formatting is allowed. Set the label for an axis. Basic HTML formatting is allowed.
Arguments:
axis - must be one of 'left', 'bottom', 'right', or 'top' ============= =================================================================
text - text to display along the axis. HTML allowed. **Arguments**
units - units to display after the title. If units are given, axis must be one of 'left', 'bottom', 'right', or 'top'
then an SI prefix will be automatically appended text text to display along the axis. HTML allowed.
and the axis values will be scaled accordingly. units units to display after the title. If units are given,
(ie, use 'V' instead of 'mV'; 'm' will be added automatically) then an SI prefix will be automatically appended
and the axis values will be scaled accordingly.
(ie, use 'V' instead of 'mV'; 'm' will be added automatically)
============= =================================================================
""" """
self.getScale(axis).setLabel(text=text, units=units, **args) self.getScale(axis).setLabel(text=text, units=units, **args)
......
...@@ -28,6 +28,15 @@ class ChildGroup(ItemGroup): ...@@ -28,6 +28,15 @@ class ChildGroup(ItemGroup):
class ViewBox(GraphicsWidget): class ViewBox(GraphicsWidget):
""" """
Box that allows internal scaling/panning of children by mouse drag. Box that allows internal scaling/panning of children by mouse drag.
This class is usually created automatically as part of a :class:`PlotItem <pyqtgraph.PlotItem>` or :class:`Canvas <pyqtgraph.canvas.Canvas>` or with :func:`GraphicsLayout.addViewBox() <pyqtgraph.GraphicsLayout.addViewBox>`.
Features:
- Scaling contents by mouse or auto-scale when contents change
- View linking--multiple views display the same data ranges
- Configurable by context menu
- Item coordinate mapping methods
Not really compatible with GraphicsView having the same functionality. Not really compatible with GraphicsView having the same functionality.
""" """
...@@ -53,6 +62,21 @@ class ViewBox(GraphicsWidget): ...@@ -53,6 +62,21 @@ class ViewBox(GraphicsWidget):
def __init__(self, parent=None, border=None, lockAspect=False, enableMouse=True, invertY=False, name=None): def __init__(self, parent=None, border=None, lockAspect=False, enableMouse=True, invertY=False, name=None):
"""
============= =============================================================
**Arguments**
*parent* (QGraphicsWidget) Optional parent widget
*border* (QPen) Do draw a border around the view, give any
single argument accepted by :func:`mkPen <pyqtgraph.mkPen>`
*lockAspect* (False or float) The aspect ratio to lock the view
coorinates to. (or False to allow the ratio to change)
*enableMouse* (bool) Whether mouse can be used to scale/pan the view
*invertY* (bool) See :func:`invertY <pyqtgraph.ViewBox.invertY>`
============= =============================================================
"""
GraphicsWidget.__init__(self, parent) GraphicsWidget.__init__(self, parent)
self.name = None self.name = None
self.linksBlocked = False self.linksBlocked = False
...@@ -112,7 +136,7 @@ class ViewBox(GraphicsWidget): ...@@ -112,7 +136,7 @@ class ViewBox(GraphicsWidget):
self.setAspectLocked(lockAspect) self.setAspectLocked(lockAspect)
self.border = border self.border = fn.mkPen(border)
self.menu = ViewBoxMenu(self) self.menu = ViewBoxMenu(self)
self.register(name) self.register(name)
...@@ -134,6 +158,9 @@ class ViewBox(GraphicsWidget): ...@@ -134,6 +158,9 @@ class ViewBox(GraphicsWidget):
ViewBox.updateAllViewLists() ViewBox.updateAllViewLists()
def unregister(self): def unregister(self):
"""
Remove this ViewBox forom the list of linkable views. (see :func:`register() <pyqtgraph.ViewBox.register>`)
"""
del ViewBox.AllViews[self] del ViewBox.AllViews[self]
if self.name is not None: if self.name is not None:
del ViewBox.NamedViews[self.name] del ViewBox.NamedViews[self.name]
...@@ -165,6 +192,11 @@ class ViewBox(GraphicsWidget): ...@@ -165,6 +192,11 @@ class ViewBox(GraphicsWidget):
def setMouseMode(self, mode): def setMouseMode(self, mode):
"""
Set the mouse interaction mode. *mode* must be either ViewBox.PanMode or ViewBox.RectMode.
In PanMode, the left mouse button pans the view and the right button scales.
In RectMode, the left button draws a rectangle which updates the visible region (this mode is more suitable for single-button mice)
"""
if mode not in [ViewBox.PanMode, ViewBox.RectMode]: if mode not in [ViewBox.PanMode, ViewBox.RectMode]:
raise Exception("Mode must be ViewBox.PanMode or ViewBox.RectMode") raise Exception("Mode must be ViewBox.PanMode or ViewBox.RectMode")
self.state['mouseMode'] = mode self.state['mouseMode'] = mode
...@@ -188,6 +220,10 @@ class ViewBox(GraphicsWidget): ...@@ -188,6 +220,10 @@ class ViewBox(GraphicsWidget):
return self.childGroup return self.childGroup
def setMouseEnabled(self, x=None, y=None): def setMouseEnabled(self, x=None, y=None):
"""
Set whether each axis is enabled for mouse interaction. *x*, *y* arguments must be True or False.
This allows the user to pan/scale one axis of the view while leaving the other axis unchanged.
"""
if x is not None: if x is not None:
self.state['mouseEnabled'][0] = x self.state['mouseEnabled'][0] = x
if y is not None: if y is not None:
...@@ -198,6 +234,10 @@ class ViewBox(GraphicsWidget): ...@@ -198,6 +234,10 @@ class ViewBox(GraphicsWidget):
return self.state['mouseEnabled'][:] return self.state['mouseEnabled'][:]
def addItem(self, item, ignoreBounds=False): def addItem(self, item, ignoreBounds=False):
"""
Add a QGraphicsItem to this view. The view will include this item when determining how to set its range
automatically unless *ignoreBounds* is True.
"""
if item.zValue() < self.zValue(): if item.zValue() < self.zValue():
item.setZValue(self.zValue()+1) item.setZValue(self.zValue()+1)
item.setParentItem(self.childGroup) item.setParentItem(self.childGroup)
...@@ -207,6 +247,7 @@ class ViewBox(GraphicsWidget): ...@@ -207,6 +247,7 @@ class ViewBox(GraphicsWidget):
#print "addItem:", item, item.boundingRect() #print "addItem:", item, item.boundingRect()
def removeItem(self, item): def removeItem(self, item):
"""Remove an item from this view."""
try: try:
self.addedItems.remove(item) self.addedItems.remove(item)
except: except:
...@@ -223,6 +264,7 @@ class ViewBox(GraphicsWidget): ...@@ -223,6 +264,7 @@ class ViewBox(GraphicsWidget):
#self.linkedYChanged() #self.linkedYChanged()
def viewRange(self): def viewRange(self):
"""Return a the view's visible range as a list: [[xmin, xmax], [ymin, ymax]]"""
return [x[:] for x in self.state['viewRange']] ## return copy return [x[:] for x in self.state['viewRange']] ## return copy
def viewRect(self): def viewRect(self):
...@@ -261,12 +303,14 @@ class ViewBox(GraphicsWidget): ...@@ -261,12 +303,14 @@ class ViewBox(GraphicsWidget):
Set the visible range of the ViewBox. Set the visible range of the ViewBox.
Must specify at least one of *range*, *xRange*, or *yRange*. Must specify at least one of *range*, *xRange*, or *yRange*.
Arguments: ============= =====================================================================
*rect* (QRectF) - The full range that should be visible in the view box. **Arguments**
*xRange* (min,max) - The range that should be visible along the x-axis. *rect* (QRectF) The full range that should be visible in the view box.
*yRange* (min,max) - The range that should be visible along the y-axis. *xRange* (min,max) The range that should be visible along the x-axis.
*padding* (float) - Expand the view by a fraction of the requested range *yRange* (min,max) The range that should be visible along the y-axis.
By default, this value is 0.02 (2%) *padding* (float) Expand the view by a fraction of the requested range.
By default, this value is 0.02 (2%)
============= =====================================================================
""" """
changes = {} changes = {}
...@@ -326,14 +370,24 @@ class ViewBox(GraphicsWidget): ...@@ -326,14 +370,24 @@ class ViewBox(GraphicsWidget):
def setYRange(self, min, max, padding=0.02, update=True): def setYRange(self, min, max, padding=0.02, update=True):
"""
Set the visible Y range of the view to [*min*, *max*].
The *padding* argument causes the range to be set larger by the fraction specified.
"""
self.setRange(yRange=[min, max], update=update, padding=padding) self.setRange(yRange=[min, max], update=update, padding=padding)
def setXRange(self, min, max, padding=0.02, update=True): def setXRange(self, min, max, padding=0.02, update=True):
"""
Set the visible X range of the view to [*min*, *max*].
The *padding* argument causes the range to be set larger by the fraction specified.
"""
self.setRange(xRange=[min, max], update=update, padding=padding) self.setRange(xRange=[min, max], update=update, padding=padding)
def autoRange(self, padding=0.02): def autoRange(self, padding=0.02):
""" """
Set the range of the view box to make all children visible. Set the range of the view box to make all children visible.
Note that this is not the same as enableAutoRange, which causes the view to
automatically auto-range whenever its contents are changed.
""" """
bounds = self.childrenBoundingRect() bounds = self.childrenBoundingRect()
if bounds is not None: if bounds is not None:
...@@ -404,6 +458,7 @@ class ViewBox(GraphicsWidget): ...@@ -404,6 +458,7 @@ class ViewBox(GraphicsWidget):
self.sigStateChanged.emit(self) self.sigStateChanged.emit(self)
def disableAutoRange(self, axis=None): def disableAutoRange(self, axis=None):
"""Disables auto-range. (See enableAutoRange)"""
self.enableAutoRange(axis, enable=False) self.enableAutoRange(axis, enable=False)
def autoRangeEnabled(self): def autoRangeEnabled(self):
...@@ -433,9 +488,11 @@ class ViewBox(GraphicsWidget): ...@@ -433,9 +488,11 @@ class ViewBox(GraphicsWidget):
self.setRange(tr, padding=0, disableAutoRange=False) self.setRange(tr, padding=0, disableAutoRange=False)
def setXLink(self, view): def setXLink(self, view):
"""Link this view's X axis to another view. (see LinkView)"""
self.linkView(self.XAxis, view) self.linkView(self.XAxis, view)