merge from inp, removed print statement

This commit is contained in:
Luke Campagnola 2013-02-24 11:37:17 -05:00
commit 21dff0525a
13 changed files with 133 additions and 30 deletions

View File

@ -17,7 +17,7 @@ Pyqtgraph makes it very easy to visualize data from the command line. Observe::
import pyqtgraph as pg
pg.plot(data) # data can be a list of values or a numpy array
The example above would open a window displaying a line plot of the data given. The call to :func:`pg.plot <pyqtgraph.plot>` returns a handle to the :class:`plot widget <pyqtgraph.PlotWidget>` that is created, allowing more data to be added to the same window.
The example above would open a window displaying a line plot of the data given. The call to :func:`pg.plot <pyqtgraph.plot>` returns a handle to the :class:`plot widget <pyqtgraph.PlotWidget>` that is created, allowing more data to be added to the same window. **Note:** interactive plotting from the python prompt is only available with PyQt; PySide does not run the Qt event loop while the interactive prompt is running. If you wish to use pyqtgraph interactively with PySide, see the 'console' :ref:`example <examples>`.
Further examples::

View File

@ -66,6 +66,12 @@ Signals, Slots, and Events
[ to be continued.. please post a request on the pyqtgraph forum if you'd like to read more ]
Qt detects and reacts to user interaction by executing its *event loop*.
- what happens in the event loop?
- when do I need to use QApplication.exec_() ?
- what control do I have over event loop execution? (QApplication.processEvents)
GraphicsView and GraphicsItems
------------------------------
@ -79,8 +85,8 @@ Mouse and Keyboard Input
------------------------
QTimer, the Event Loop, and Multi-Threading
-------------------------------------------
QTimer, Multi-Threading
-----------------------
Multi-threading vs Multi-processing in Qt

View File

@ -62,7 +62,7 @@ w.addItem(p3)
## Animated example
## compute surface vertex data
cols = 100
cols = 90
rows = 100
x = np.linspace(-8, 8, cols+1).reshape(cols+1,1)
y = np.linspace(-8, 8, rows+1).reshape(1,rows+1)

View File

@ -1,4 +1,15 @@
# -*- coding: utf-8 -*-
"""
This example demonstrates the use of ImageView, which is a high-level widget for
displaying and analyzing 2D and 3D data. ImageView provides:
1. A zoomable region (ViewBox) for displaying the image
2. A combination histogram and gradient editor (HistogramLUTItem) for
controlling the visual appearance of the image
3. A timeline for selecting the currently displayed frame (for 3D data only).
4. Tools for very basic analysis of image data (see ROI and Norm buttons)
"""
## Add path to library (just for examples; you do not need this)
import initExample
@ -22,9 +33,6 @@ img = img[np.newaxis,:,:]
decay = np.exp(-np.linspace(0,0.3,100))[:,np.newaxis,np.newaxis]
data = np.random.normal(size=(100, 200, 200))
data += img * decay
#for i in range(data.shape[0]):
#data[i] += 10*exp(-(2.*i)/data.shape[0])
data += 2
## Add time-varying signal
@ -37,7 +45,7 @@ sig = sig[:,np.newaxis,np.newaxis] * 3
data[:,50:60,50:60] += sig
## Display the data
## Display the data and assign each frame a time value from 1.0 to 3.0
imv.setImage(data, xvals=np.linspace(1., 3., data.shape[0]))
## Start Qt event loop unless running in interactive mode.

View File

@ -66,6 +66,7 @@ for i in range(0, 5):
## Test large numbers
curve = pw3.plot(np.random.normal(size=100)*1e0, clickable=True)
curve.curve.setClickable(True)
curve.setPen('w') ## white pen
curve.setShadowPen(pg.mkPen((70,70,30), width=6, cosmetic=True))

View File

@ -22,7 +22,7 @@ class PlotData(object):
self.maxVals = {} ## cache for max/min
self.minVals = {}
def addFields(self, fields):
def addFields(self, **fields):
for f in fields:
if f not in self.fields:
self.fields[f] = None

View File

@ -212,6 +212,19 @@ class Dock(QtGui.QWidget, DockDrop):
def __repr__(self):
return "<Dock %s %s>" % (self.name(), self.stretch())
## PySide bug: We need to explicitly redefine these methods
## or else drag/drop events will not be delivered.
def dragEnterEvent(self, *args):
DockDrop.dragEnterEvent(self, *args)
def dragMoveEvent(self, *args):
DockDrop.dragMoveEvent(self, *args)
def dragLeaveEvent(self, *args):
DockDrop.dragLeaveEvent(self, *args)
def dropEvent(self, *args):
DockDrop.dropEvent(self, *args)
class DockLabel(VerticalLabel):

View File

@ -301,5 +301,19 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
self.home.removeTempArea(self)
#self.close()
## PySide bug: We need to explicitly redefine these methods
## or else drag/drop events will not be delivered.
def dragEnterEvent(self, *args):
DockDrop.dragEnterEvent(self, *args)
def dragMoveEvent(self, *args):
DockDrop.dragMoveEvent(self, *args)
def dragLeaveEvent(self, *args):
DockDrop.dragLeaveEvent(self, *args)
def dropEvent(self, *args):
DockDrop.dropEvent(self, *args)

View File

@ -84,8 +84,41 @@ class ArrowItem(QtGui.QGraphicsPathItem):
def paint(self, p, *args):
p.setRenderHint(QtGui.QPainter.Antialiasing)
QtGui.QGraphicsPathItem.paint(self, p, *args)
#p.setPen(fn.mkPen('r'))
#p.setBrush(fn.mkBrush(None))
#p.drawRect(self.boundingRect())
def shape(self):
#if not self.opts['pxMode']:
#return QtGui.QGraphicsPathItem.shape(self)
return self.path
return self.path
## dataBounds and pixelPadding methods are provided to ensure ViewBox can
## properly auto-range
def dataBounds(self, ax, frac, orthoRange=None):
pw = 0
pen = self.pen()
if not pen.isCosmetic():
pw = pen.width() * 0.7072
if self.opts['pxMode']:
return [0,0]
else:
br = self.boundingRect()
if ax == 0:
return [br.left()-pw, br.right()+pw]
else:
return [br.top()-pw, br.bottom()+pw]
def pixelPadding(self):
pad = 0
if self.opts['pxMode']:
br = self.boundingRect()
pad += (br.width()**2 + br.height()**2) ** 0.5
pen = self.pen()
if pen.isCosmetic():
pad += max(1, pen.width()) * 0.7072
return pad

View File

@ -336,7 +336,7 @@ class ViewBox(GraphicsWidget):
print("make qrectf failed:", self.state['targetRange'])
raise
def setRange(self, rect=None, xRange=None, yRange=None, padding=0.02, update=True, disableAutoRange=True):
def setRange(self, rect=None, xRange=None, yRange=None, padding=None, update=True, disableAutoRange=True):
"""
Set the visible range of the ViewBox.
Must specify at least one of *range*, *xRange*, or *yRange*.
@ -347,7 +347,8 @@ class ViewBox(GraphicsWidget):
*xRange* (min,max) The range that should be visible along the x-axis.
*yRange* (min,max) The range that should be visible along the y-axis.
*padding* (float) Expand the view by a fraction of the requested range.
By default, this value is 0.02 (2%)
By default, this value is set between 0.02 and 0.1 depending on
the size of the ViewBox.
============= =====================================================================
"""
@ -367,6 +368,10 @@ class ViewBox(GraphicsWidget):
changed = [False, False]
for ax, range in changes.items():
if padding is None:
xpad = self.suggestPadding(ax)
else:
xpad = padding
mn = min(range)
mx = max(range)
if mn == mx: ## If we requested 0 range, try to preserve previous scale. Otherwise just pick an arbitrary scale.
@ -375,11 +380,11 @@ class ViewBox(GraphicsWidget):
dy = 1
mn -= dy*0.5
mx += dy*0.5
padding = 0.0
xpad = 0.0
if any(np.isnan([mn, mx])) or any(np.isinf([mn, mx])):
raise Exception("Not setting range [%s, %s]" % (str(mn), str(mx)))
p = (mx-mn) * padding
p = (mx-mn) * xpad
mn -= p
mx += p
@ -412,34 +417,53 @@ class ViewBox(GraphicsWidget):
elif changed[1] and self.state['autoVisibleOnly'][0]:
self.updateAutoRange()
def setYRange(self, min, max, padding=0.02, update=True):
def setYRange(self, min, max, padding=None, 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.
(by default, this value is between 0.02 and 0.1 depending on the size of the ViewBox)
"""
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=None, 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.
(by default, this value is between 0.02 and 0.1 depending on the size of the ViewBox)
"""
self.setRange(xRange=[min, max], update=update, padding=padding)
def autoRange(self, padding=0.02, item=None):
def autoRange(self, padding=None, items=None, item=None):
"""
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.
=========== ============================================================
Arguments
padding The fraction of the total data range to add on to the final
visible range. By default, this value is set between 0.02
and 0.1 depending on the size of the ViewBox.
items If specified, this is a list of items to consider when
determining the visible range.
=========== ============================================================
"""
if item is None:
bounds = self.childrenBoundingRect()
bounds = self.childrenBoundingRect(items=items)
else:
print "Warning: ViewBox.autoRange(item=__) is deprecated. Use 'items' argument instead."
bounds = self.mapFromItemToView(item, item.boundingRect()).boundingRect()
if bounds is not None:
self.setRange(bounds, padding=padding)
def suggestPadding(self, axis):
l = self.width() if axis==0 else self.height()
if l > 0:
padding = np.clip(1./(l**0.5), 0.02, 0.1)
else:
padding = 0.02
return padding
def scaleBy(self, s, center=None):
"""
@ -577,12 +601,10 @@ class ViewBox(GraphicsWidget):
w2 = (targetRect[ax][1]-targetRect[ax][0]) / 2.
childRange[ax] = [x-w2, x+w2]
else:
l = self.width() if ax==0 else self.height()
if l > 0:
padding = np.clip(1./(l**0.5), 0.02, 0.1)
wp = (xr[1] - xr[0]) * padding
childRange[ax][0] -= wp
childRange[ax][1] += wp
padding = self.suggestPadding(ax)
wp = (xr[1] - xr[0]) * padding
childRange[ax][0] -= wp
childRange[ax][1] += wp
targetRect[ax] = childRange[ax]
args['xRange' if ax == 0 else 'yRange'] = targetRect[ax]
if len(args) == 0:
@ -995,13 +1017,14 @@ class ViewBox(GraphicsWidget):
def childrenBounds(self, frac=None, orthoRange=(None,None)):
def childrenBounds(self, frac=None, orthoRange=(None,None), items=None):
"""Return the bounding range of all children.
[[xmin, xmax], [ymin, ymax]]
Values may be None if there are no specific bounds for an axis.
"""
prof = debug.Profiler('updateAutoRange', disabled=True)
items = self.addedItems
if items is None:
items = self.addedItems
## measure pixel dimensions in view box
px, py = [v.length() if v is not None else 0 for v in self.childGroup.pixelVectors()]

View File

@ -205,7 +205,12 @@ class ImageView(QtGui.QWidget):
*axes* Dictionary indicating the interpretation for each axis.
This is only needed to override the default guess. Format is::
{'t':0, 'x':1, 'y':2, 'c':3};
{'t':0, 'x':1, 'y':2, 'c':3};
*pos* Change the position of the displayed image
*scale* Change the scale of the displayed image
*transform* Set the transform of the dispalyed image. This option overrides *pos*
and *scale*.
============== =======================================================================
"""
prof = debug.Profiler('ImageView.setImage', disabled=True)

View File

@ -436,7 +436,7 @@ class MeshData(object):
elif self._faceColorsIndexedByFaces is not None:
names.append('_faceColorsIndexedByFaces')
state = {n:getattr(self, n) for n in names}
state = dict([(n,getattr(self, n)) for n in names])
return pickle.dumps(state)
def restore(self, state):

View File

@ -127,8 +127,8 @@ class GLSurfacePlotItem(GLMeshItem):
def generateFaces(self):
cols = self._z.shape[0]-1
rows = self._z.shape[1]-1
cols = self._z.shape[1]-1
rows = self._z.shape[0]-1
faces = np.empty((cols*rows*2, 3), dtype=np.uint)
rowtemplate1 = np.arange(cols).reshape(cols, 1) + np.array([[0, 1, cols+1]])
rowtemplate2 = np.arange(cols).reshape(cols, 1) + np.array([[cols+1, 1, cols+2]])