Repository: enthought/chaco

Issue:
ValueError when using PanTool with restrict_to_data and empty data source
This can come up when a plot's data sources contain empty arrays. None-empty data sources may be visible on screen, and the user may wish to pan based on that view. The empty data sources should not keep this from happening. Here's a minimal example.

``` python

import numpy as np

from chaco.array_plot_data import ArrayPlotData
from chaco.plot import Plot
from chaco.tools.pan_tool import PanTool

plot_data = ArrayPlotData()
plot = Plot(plot_data)
arr = np.arange(4.0)
plot_data.set_data("x", arr)
plot_data.set_data("y", arr)
plot_data.set_data("z", np.array([], np.float64)
plot.plot(('x', 'y'))
plot.plot(('z', 'z'))
tool = PanTool(plot, restrict_to_data=True)
plot.tools.append(tool)

```



Discussion:
I'm working on a fix.


Resolving patch:
diff --git a/chaco/tools/pan_tool.py b/chaco/tools/pan_tool.py
--- a/chaco/tools/pan_tool.py
+++ b/chaco/tools/pan_tool.py
@@ -199,16 +199,17 @@ def panning_mouse_move(self, event):
                 # values.  As a first approximation, we're just going to
                 # use a linear approximation, which works perfectly for
                 # linear mappers (which is used 99% of the time).
+                data = [arr for arr in
+                        (source.get_data() for source in mapper.range.sources)
+                        if arr.size > 0]
                 if domain_min is None:
                     if self.restrict_to_data:
-                        domain_min = min([source.get_data().min()
-                                          for source in mapper.range.sources])
+                        domain_min = min([arr.min() for arr in data])
                     else:
                         domain_min = -inf
                 if domain_max is None:
                     if self.restrict_to_data:
-                        domain_max = max([source.get_data().max()
-                                          for source in mapper.range.sources])
+                        domain_max = max([arr.max() for arr in data])
                     else:
                         domain_max = inf
 


Test patch:
diff --git a/chaco/tools/tests/__init__.py b/chaco/tools/tests/__init__.py
new file mode 100644
diff --git a/chaco/tools/tests/pan_tool_test_case.py b/chaco/tools/tests/pan_tool_test_case.py
new file mode 100644
--- /dev/null
+++ b/chaco/tools/tests/pan_tool_test_case.py
@@ -0,0 +1,41 @@
+import unittest
+
+import numpy as np
+
+from chaco.array_plot_data import ArrayPlotData
+from chaco.plot import Plot
+from chaco.tools.pan_tool import PanTool
+from enable.testing import EnableTestAssistant
+
+
+class PanToolTestCase(EnableTestAssistant, unittest.TestCase):
+
+    def test_restrict_to_data_with_empty_source(self):
+        # Regression test for #214.
+        plot_data = ArrayPlotData()
+        plot = Plot(plot_data)
+        arr = np.arange(4.0)
+        plot_data.set_data("x", arr)
+        plot_data.set_data("y", arr)
+        plot_data.set_data("z", np.array([], np.float64))
+        plot.plot(('x', 'y'))
+        plot.plot(('z', 'z'))
+        tool = PanTool(plot, restrict_to_data=True)
+        plot.tools.append(tool)
+
+        x_range = plot.x_mapper.range
+        y_range = plot.y_mapper.range
+
+        x_bounds = (x_range.low, x_range.high)
+        y_bounds = (y_range.low, y_range.high)
+        self.mouse_down(tool, 0.0, 0.0)
+        self.mouse_move(interactor=tool, x=1.0, y=1.0)
+        self.mouse_up(interactor=tool, x=1.0, y=1.0)
+        self.assertEqual((x_range.low, x_range.high), x_bounds)
+        self.assertEqual((y_range.low, y_range.high), y_bounds)
+
+
+
+if __name__ == '__main__':
+    import nose
+    nose.run()