Repository: enthought/chaco

Issue:
"Lasso" tool is broken with NumPy 1.10
The regression.py and scatter.py demos work with NumPy 1.8, but on NumPy 1.10 they produce the following output:

```
Traceback (most recent call last):
  File "build/bdist.macosx-10.6-x86_64/egg/enable/qt4/base_window.py", line 225, in mouseReleaseEvent
  File "build/bdist.macosx-10.6-x86_64/egg/enable/qt4/base_window.py", line 114, in mouseReleaseEvent
  File "build/bdist.macosx-10.6-x86_64/egg/enable/abstract_window.py", line 348, in _handle_mouse_event
  File "build/bdist.macosx-10.6-x86_64/egg/enable/component.py", line 918, in dispatch
  File "build/bdist.macosx-10.6-x86_64/egg/enable/component.py", line 958, in _new_dispatch
  File "build/bdist.macosx-10.6-x86_64/egg/enable/container.py", line 514, in _dispatch_stateful_event
  File "build/bdist.macosx-10.6-x86_64/egg/enable/component.py", line 918, in dispatch
  File "build/bdist.macosx-10.6-x86_64/egg/enable/component.py", line 946, in _new_dispatch
  File "build/bdist.macosx-10.6-x86_64/egg/enable/interactor.py", line 94, in dispatch
  File "build/bdist.macosx-10.6-x86_64/egg/enable/interactor.py", line 110, in _dispatch_stateful_event
  File "build/bdist.macosx-10.6-x86_64/egg/chaco/tools/lasso_selection.py", line 159, in selecting_left_up
  File "build/bdist.macosx-10.6-x86_64/egg/chaco/tools/lasso_selection.py", line 172, in selecting_mouse_up
  File "build/bdist.macosx-10.6-x86_64/egg/chaco/tools/lasso_selection.py", line 274, in _update_selection
TypeError: ufunc 'bitwise_or' output (typecode 'i') could not be coerced to provided output parameter (typecode '?') according to the casting rule ''same_kind''
```

This is with Chaco "4.6.0.dev123-1" and NumPy "1.10.4-1".  Demos in question are here:

http://docs.enthought.com/chaco/user_manual/annotated_examples.html#regression-py



Discussion:
On NumPy 1.7.1, this is also observed:

/Users/acollette/Documents/development/irig/.devenv/lib/python2.7/site-packages/chaco/tools/lasso_selection.py:274: DeprecationWarning: Implicitly casting between incompatible kinds. In a future numpy release, this will raise an error. Use casting="unsafe" if this is intentional.

Underlying issue is with enable/kiva/agg wrapping code where `points_in_polygon` returns an array of int.  Two-phase fix should be:
- a band-aid in Chaco where we do `astype(bool)`.
- a proper fix in kiva where we return an array of dtype bool form `points_in_polygon`


Resolving patch:
diff --git a/chaco/tools/lasso_selection.py b/chaco/tools/lasso_selection.py
--- a/chaco/tools/lasso_selection.py
+++ b/chaco/tools/lasso_selection.py
@@ -254,7 +254,8 @@ def _update_selection(self):
         if self.selection_datasource is None:
             return
 
-        selected_mask = zeros(self.selection_datasource._data.shape, dtype=numpy.bool)
+        selected_mask = zeros(self.selection_datasource._data.shape,
+                              dtype=numpy.bool)
         data = self._get_data()
 
         # Compose the selection mask from the cached selections first, then
@@ -262,21 +263,25 @@ def _update_selection(self):
         # for the active selection
 
         for selection in self._previous_selections:
-            selected_mask |= (points_in_polygon(data, selection, False))
+            selected_mask |= points_in_polygon(
+                data, selection, False).astype(bool, copy=False)
+
+        active_selection = points_in_polygon(
+            data, self._active_selection, False).astype(bool, copy=False)
 
         if self.selection_mode == 'exclude':
-            selected_mask |= (points_in_polygon(data, self._active_selection, False))
-            selected_mask = 1 - selected_mask
+            # XXX I think this should be "set difference"? - CJW
+            selected_mask |= active_selection
+            selected_mask = ~selected_mask
 
         elif self.selection_mode == 'invert':
-            selected_mask = -1 * (selected_mask -points_in_polygon(data, self._active_selection, False))
+            selected_mask ^= active_selection
         else:
-            selected_mask |= (points_in_polygon(data, self._active_selection, False))
+            selected_mask |= active_selection
 
         if sometrue(selected_mask != self.selection_datasource.metadata[self.metadata_name]):
             self.selection_datasource.metadata[self.metadata_name] = selected_mask
             self.selection_changed = True
-        return
 
     def _map_screen(self, points):
         """ Maps a point in data space to a point in screen space on the plot.
@@ -319,5 +324,3 @@ def _get_plot(self):
     def _set_plot(self, val):
         self._plot = val
         return
-
-


Test patch: