From 412e1d2ec8c907430a1e2e21d4ceec1c26997213 Mon Sep 17 00:00:00 2001
From: Luke Campagnola <luke.campagnola@gmail.com>
Date: Wed, 20 Feb 2013 11:13:50 -0500
Subject: [PATCH] doc updates ViewBox: made padding more consistent for all
 auto-ranging methods, deprecated autoRange(item=) in favor of
 autoRange(items=)

---
 doc/source/how_to_use.rst                  |  2 +-
 doc/source/qtcrashcourse.rst               | 10 +++-
 examples/ImageView.py                      | 16 +++++--
 examples/PlotWidget.py                     |  1 +
 pyqtgraph/PlotData.py                      |  2 +-
 pyqtgraph/graphicsItems/ViewBox/ViewBox.py | 55 +++++++++++++++-------
 6 files changed, 62 insertions(+), 24 deletions(-)

diff --git a/doc/source/how_to_use.rst b/doc/source/how_to_use.rst
index 53a3d2b0..0e00af59 100644
--- a/doc/source/how_to_use.rst
+++ b/doc/source/how_to_use.rst
@@ -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::
     
diff --git a/doc/source/qtcrashcourse.rst b/doc/source/qtcrashcourse.rst
index ca2da797..23a561b9 100644
--- a/doc/source/qtcrashcourse.rst
+++ b/doc/source/qtcrashcourse.rst
@@ -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
diff --git a/examples/ImageView.py b/examples/ImageView.py
index 5edae00b..f11ce0f7 100644
--- a/examples/ImageView.py
+++ b/examples/ImageView.py
@@ -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.
diff --git a/examples/PlotWidget.py b/examples/PlotWidget.py
index 3cca8f7a..2aa118f2 100644
--- a/examples/PlotWidget.py
+++ b/examples/PlotWidget.py
@@ -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))
 
diff --git a/pyqtgraph/PlotData.py b/pyqtgraph/PlotData.py
index 18531c14..0bf13ca8 100644
--- a/pyqtgraph/PlotData.py
+++ b/pyqtgraph/PlotData.py
@@ -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
diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py
index ce1d61f9..b562132c 100644
--- a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py
+++ b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py
@@ -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()]
-- 
GitLab