We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`watershed_demo` fails on mouse click
## Description
```
[egor@host scikit-image]$ python viewer_examples/plugins/watershed_demo.py 
Watershed plugin
----------------
Use mouse to paint each region with a different label.
Press OK to display segmented image.
Traceback (most recent call last):
  File "/home/egor/.local/lib/python3.6/site-packages/matplotlib/cbook/__init__.py", line 388, in process
    proxy(*args, **kwargs)
  File "/home/egor/.local/lib/python3.6/site-packages/matplotlib/cbook/__init__.py", line 228, in __call__
    return mtd(*args, **kwargs)
  File "/home/egor/Workspace/_contrib/scikit-image/skimage/viewer/utils/canvas.py", line 75, in on_mouse_press
    self.active_tool.on_mouse_press(event)
  File "/home/egor/Workspace/_contrib/scikit-image/skimage/viewer/canvastools/painttool.py", line 149, in on_mouse_press
    self.update_overlay(event.xdata, event.ydata)
  File "/home/egor/Workspace/_contrib/scikit-image/skimage/viewer/canvastools/painttool.py", line 172, in update_overlay
    overlay[self.window.at(y, x)] = self.label
TypeError: slice indices must be integers or None or have an __index__ method
```

## Way to reproduce
[If reporting a bug, please include the following important information:]
- [x] Code example
- [x] Relevant images (if any)
- [x] Operating system and version: `Linux 4.14.49-1-lts #1 SMP Tue Jun 12 16:32:50 CEST 2018 x86_64 GNU/Linux`
- [x] Python version: 3.6.5
- [x] scikit-image version (run `skimage.__version__`): https://github.com/scikit-image/scikit-image/commit/18f97d864a9468555851aac08c731b6813db2091
- [x] matplotlib: 2.2.2



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `viewer_examples/plugins/watershed_demo.py`
Content:
```
1 import matplotlib.pyplot as plt
2 
3 from skimage import data
4 from skimage import filters
5 from skimage import morphology
6 from skimage.viewer import ImageViewer
7 from skimage.viewer.widgets import history
8 from skimage.viewer.plugins.labelplugin import LabelPainter
9 
10 
11 class OKCancelButtons(history.OKCancelButtons):
12 
13     def update_original_image(self):
14         # OKCancelButtons updates the original image with the filtered image
15         # by default. Override this method to update the overlay.
16         self.plugin._show_watershed()
17         self.plugin.close()
18 
19 
20 class WatershedPlugin(LabelPainter):
21 
22     def help(self):
23         helpstr = ("Watershed plugin",
24                    "----------------",
25                    "Use mouse to paint each region with a different label.",
26                    "Press OK to display segmented image.")
27         return '\n'.join(helpstr)
28 
29     def _show_watershed(self):
30         viewer = self.image_viewer
31         edge_image = filter.sobel(viewer.image)
32         labels = morphology.watershed(edge_image, self.paint_tool.overlay)
33         viewer.ax.imshow(labels, cmap=plt.cm.jet, alpha=0.5)
34         viewer.redraw()
35 
36 
37 image = data.coins()
38 plugin = WatershedPlugin()
39 plugin += OKCancelButtons()
40 
41 viewer = ImageViewer(image)
42 viewer += plugin
43 viewer.show()
44
```

Path: `skimage/viewer/canvastools/painttool.py`
Content:
```
1 import numpy as np
2 import matplotlib.pyplot as plt
3 import matplotlib.colors as mcolors
4 LABELS_CMAP = mcolors.ListedColormap(['white', 'red', 'dodgerblue', 'gold',
5                                       'greenyellow', 'blueviolet'])
6 from ...viewer.canvastools.base import CanvasToolBase
7 
8 
9 __all__ = ['PaintTool']
10 
11 
12 class PaintTool(CanvasToolBase):
13     """Widget for painting on top of a plot.
14 
15     Parameters
16     ----------
17     manager : Viewer or PlotPlugin.
18         Skimage viewer or plot plugin object.
19     overlay_shape : shape tuple
20         2D shape tuple used to initialize overlay image.
21     alpha : float (between [0, 1])
22         Opacity of overlay
23     on_move : function
24         Function called whenever a control handle is moved.
25         This function must accept the end points of line as the only argument.
26     on_release : function
27         Function called whenever the control handle is released.
28     on_enter : function
29         Function called whenever the "enter" key is pressed.
30     rect_props : dict
31         Properties for :class:`matplotlib.patches.Rectangle`. This class
32         redefines defaults in :class:`matplotlib.widgets.RectangleSelector`.
33 
34     Attributes
35     ----------
36     overlay : array
37         Overlay of painted labels displayed on top of image.
38     label : int
39         Current paint color.
40 
41     Examples
42     ----------
43     >>> from skimage.data import camera
44     >>> import matplotlib.pyplot as plt
45     >>> from skimage.viewer.canvastools import PaintTool
46     >>> import numpy as np
47 
48     >>> img = camera() #doctest: +SKIP
49 
50     >>> ax = plt.subplot(111) #doctest: +SKIP 
51     >>> plt.imshow(img, cmap=plt.cm.gray) #doctest: +SKIP
52     >>> p = PaintTool(ax,np.shape(img[:-1]),10,0.2) #doctest: +SKIP
53     >>> plt.show() #doctest: +SKIP
54 
55     >>> mask = p.overlay #doctest: +SKIP
56     >>> plt.imshow(mask,cmap=plt.cm.gray) #doctest: +SKIP
57     >>> plt.show() #doctest: +SKIP
58     """
59     def __init__(self, manager, overlay_shape, radius=5, alpha=0.3,
60                  on_move=None, on_release=None, on_enter=None,
61                  rect_props=None):
62         super(PaintTool, self).__init__(manager, on_move=on_move,
63                                         on_enter=on_enter,
64                                         on_release=on_release)
65 
66         props = dict(edgecolor='r', facecolor='0.7', alpha=0.5, animated=True)
67         props.update(rect_props if rect_props is not None else {})
68 
69         self.alpha = alpha
70         self.cmap = LABELS_CMAP
71         self._overlay_plot = None
72         self.shape = overlay_shape
73 
74         self._cursor = plt.Rectangle((0, 0), 0, 0, **props)
75         self._cursor.set_visible(False)
76         self.ax.add_patch(self._cursor)
77 
78         # `label` and `radius` can only be set after initializing `_cursor`
79         self.label = 1
80         self.radius = radius
81 
82         # Note that the order is important: Redraw cursor *after* overlay
83         self.artists = [self._overlay_plot, self._cursor]
84         self.manager.add_tool(self)
85 
86     @property
87     def label(self):
88         return self._label
89 
90     @label.setter
91     def label(self, value):
92         if value >= self.cmap.N:
93             raise ValueError('Maximum label value = %s' % len(self.cmap - 1))
94         self._label = value
95         self._cursor.set_edgecolor(self.cmap(value))
96 
97     @property
98     def radius(self):
99         return self._radius
100 
101     @radius.setter
102     def radius(self, r):
103         self._radius = r
104         self._width = 2 * r + 1
105         self._cursor.set_width(self._width)
106         self._cursor.set_height(self._width)
107         self.window = CenteredWindow(r, self._shape)
108 
109     @property
110     def overlay(self):
111         return self._overlay
112 
113     @overlay.setter
114     def overlay(self, image):
115         self._overlay = image
116         if image is None:
117             self.ax.images.remove(self._overlay_plot)
118             self._overlay_plot = None
119         elif self._overlay_plot is None:
120             props = dict(cmap=self.cmap, alpha=self.alpha,
121                          norm=mcolors.NoNorm(), animated=True)
122             self._overlay_plot = self.ax.imshow(image, **props)
123         else:
124             self._overlay_plot.set_data(image)
125         self.redraw()
126 
127     @property
128     def shape(self):
129         return self._shape
130 
131     @shape.setter
132     def shape(self, shape):
133         self._shape = shape
134         if not self._overlay_plot is None:
135             self._overlay_plot.set_extent((-0.5, shape[1] + 0.5,
136                                            shape[0] + 0.5, -0.5))
137             self.radius = self._radius
138         self.overlay = np.zeros(shape, dtype='uint8')
139 
140     def on_key_press(self, event):
141         if event.key == 'enter':
142             self.callback_on_enter(self.geometry)
143             self.redraw()
144 
145     def on_mouse_press(self, event):
146         if event.button != 1 or not self.ax.in_axes(event):
147             return
148         self.update_cursor(event.xdata, event.ydata)
149         self.update_overlay(event.xdata, event.ydata)
150 
151     def on_mouse_release(self, event):
152         if event.button != 1:
153             return
154         self.callback_on_release(self.geometry)
155 
156     def on_move(self, event):
157         if not self.ax.in_axes(event):
158             self._cursor.set_visible(False)
159             self.redraw() # make sure cursor is not visible
160             return
161         self._cursor.set_visible(True)
162 
163         self.update_cursor(event.xdata, event.ydata)
164         if event.button != 1:
165             self.redraw() # update cursor position
166             return
167         self.update_overlay(event.xdata, event.ydata)
168         self.callback_on_move(self.geometry)
169 
170     def update_overlay(self, x, y):
171         overlay = self.overlay
172         overlay[self.window.at(y, x)] = self.label
173         # Note that overlay calls `redraw`
174         self.overlay = overlay
175 
176     def update_cursor(self, x, y):
177         x = x - self.radius - 1
178         y = y - self.radius - 1
179         self._cursor.set_xy((x, y))
180 
181     @property
182     def geometry(self):
183         return self.overlay
184 
185 
186 class CenteredWindow(object):
187     """Window that create slices numpy arrays over 2D windows.
188 
189     Examples
190     --------
191     >>> a = np.arange(16).reshape(4, 4)
192     >>> w = CenteredWindow(1, a.shape)
193     >>> a[w.at(1, 1)]
194     array([[ 0,  1,  2],
195            [ 4,  5,  6],
196            [ 8,  9, 10]])
197     >>> a[w.at(0, 0)]
198     array([[0, 1],
199            [4, 5]])
200     >>> a[w.at(4, 3)]
201     array([[14, 15]])
202     """
203     def __init__(self, radius, array_shape):
204         self.radius = radius
205         self.array_shape = array_shape
206 
207     def at(self, row, col):
208         h, w = self.array_shape
209         r = self.radius
210         xmin = max(0, col - r)
211         xmax = min(w, col + r + 1)
212         ymin = max(0, row - r)
213         ymax = min(h, row + r + 1)
214         return [slice(ymin, ymax), slice(xmin, xmax)]
215 
216 
217 if __name__ == '__main__':  # pragma: no cover
218     np.testing.rundocs()
219     from ... import data
220     from ...viewer import ImageViewer
221 
222     image = data.camera()
223 
224     viewer = ImageViewer(image)
225     paint_tool = PaintTool(viewer, image.shape)
226     viewer.show()
227
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/skimage/viewer/canvastools/painttool.py b/skimage/viewer/canvastools/painttool.py
--- a/skimage/viewer/canvastools/painttool.py
+++ b/skimage/viewer/canvastools/painttool.py
@@ -206,12 +206,21 @@
 
     def at(self, row, col):
         h, w = self.array_shape
-        r = self.radius
+        r = round(self.radius)
+        # Note: the int() cast is necessary because row and col are np.float64,
+        # which does not get cast by round(), unlike a normal Python float:
+        # >>> round(4.5)
+        # 4
+        # >>> round(np.float64(4.5))
+        # 4.0
+        # >>> int(round(np.float64(4.5)))
+        # 4
+        row, col = int(round(row)), int(round(col))
         xmin = max(0, col - r)
         xmax = min(w, col + r + 1)
         ymin = max(0, row - r)
         ymax = min(h, row + r + 1)
-        return [slice(ymin, ymax), slice(xmin, xmax)]
+        return (slice(ymin, ymax), slice(xmin, xmax))
 
 
 if __name__ == '__main__':  # pragma: no cover
diff --git a/viewer_examples/plugins/watershed_demo.py b/viewer_examples/plugins/watershed_demo.py
--- a/viewer_examples/plugins/watershed_demo.py
+++ b/viewer_examples/plugins/watershed_demo.py
@@ -28,7 +28,7 @@
 
     def _show_watershed(self):
         viewer = self.image_viewer
-        edge_image = filter.sobel(viewer.image)
+        edge_image = filters.sobel(viewer.image)
         labels = morphology.watershed(edge_image, self.paint_tool.overlay)
         viewer.ax.imshow(labels, cmap=plt.cm.jet, alpha=0.5)
         viewer.redraw()

{"golden_diff": "diff --git a/skimage/viewer/canvastools/painttool.py b/skimage/viewer/canvastools/painttool.py\n--- a/skimage/viewer/canvastools/painttool.py\n+++ b/skimage/viewer/canvastools/painttool.py\n@@ -206,12 +206,21 @@\n \n     def at(self, row, col):\n         h, w = self.array_shape\n-        r = self.radius\n+        r = round(self.radius)\n+        # Note: the int() cast is necessary because row and col are np.float64,\n+        # which does not get cast by round(), unlike a normal Python float:\n+        # >>> round(4.5)\n+        # 4\n+        # >>> round(np.float64(4.5))\n+        # 4.0\n+        # >>> int(round(np.float64(4.5)))\n+        # 4\n+        row, col = int(round(row)), int(round(col))\n         xmin = max(0, col - r)\n         xmax = min(w, col + r + 1)\n         ymin = max(0, row - r)\n         ymax = min(h, row + r + 1)\n-        return [slice(ymin, ymax), slice(xmin, xmax)]\n+        return (slice(ymin, ymax), slice(xmin, xmax))\n \n \n if __name__ == '__main__':  # pragma: no cover\ndiff --git a/viewer_examples/plugins/watershed_demo.py b/viewer_examples/plugins/watershed_demo.py\n--- a/viewer_examples/plugins/watershed_demo.py\n+++ b/viewer_examples/plugins/watershed_demo.py\n@@ -28,7 +28,7 @@\n \n     def _show_watershed(self):\n         viewer = self.image_viewer\n-        edge_image = filter.sobel(viewer.image)\n+        edge_image = filters.sobel(viewer.image)\n         labels = morphology.watershed(edge_image, self.paint_tool.overlay)\n         viewer.ax.imshow(labels, cmap=plt.cm.jet, alpha=0.5)\n         viewer.redraw()\n", "issue": "`watershed_demo` fails on mouse click\n## Description\r\n```\r\n[egor@host scikit-image]$ python viewer_examples/plugins/watershed_demo.py \r\nWatershed plugin\r\n----------------\r\nUse mouse to paint each region with a different label.\r\nPress OK to display segmented image.\r\nTraceback (most recent call last):\r\n  File \"/home/egor/.local/lib/python3.6/site-packages/matplotlib/cbook/__init__.py\", line 388, in process\r\n    proxy(*args, **kwargs)\r\n  File \"/home/egor/.local/lib/python3.6/site-packages/matplotlib/cbook/__init__.py\", line 228, in __call__\r\n    return mtd(*args, **kwargs)\r\n  File \"/home/egor/Workspace/_contrib/scikit-image/skimage/viewer/utils/canvas.py\", line 75, in on_mouse_press\r\n    self.active_tool.on_mouse_press(event)\r\n  File \"/home/egor/Workspace/_contrib/scikit-image/skimage/viewer/canvastools/painttool.py\", line 149, in on_mouse_press\r\n    self.update_overlay(event.xdata, event.ydata)\r\n  File \"/home/egor/Workspace/_contrib/scikit-image/skimage/viewer/canvastools/painttool.py\", line 172, in update_overlay\r\n    overlay[self.window.at(y, x)] = self.label\r\nTypeError: slice indices must be integers or None or have an __index__ method\r\n```\r\n\r\n## Way to reproduce\r\n[If reporting a bug, please include the following important information:]\r\n- [x] Code example\r\n- [x] Relevant images (if any)\r\n- [x] Operating system and version: `Linux 4.14.49-1-lts #1 SMP Tue Jun 12 16:32:50 CEST 2018 x86_64 GNU/Linux`\r\n- [x] Python version: 3.6.5\r\n- [x] scikit-image version (run `skimage.__version__`): https://github.com/scikit-image/scikit-image/commit/18f97d864a9468555851aac08c731b6813db2091\r\n- [x] matplotlib: 2.2.2\r\n\r\n\n", "before_files": [{"content": "import matplotlib.pyplot as plt\n\nfrom skimage import data\nfrom skimage import filters\nfrom skimage import morphology\nfrom skimage.viewer import ImageViewer\nfrom skimage.viewer.widgets import history\nfrom skimage.viewer.plugins.labelplugin import LabelPainter\n\n\nclass OKCancelButtons(history.OKCancelButtons):\n\n    def update_original_image(self):\n        # OKCancelButtons updates the original image with the filtered image\n        # by default. Override this method to update the overlay.\n        self.plugin._show_watershed()\n        self.plugin.close()\n\n\nclass WatershedPlugin(LabelPainter):\n\n    def help(self):\n        helpstr = (\"Watershed plugin\",\n                   \"----------------\",\n                   \"Use mouse to paint each region with a different label.\",\n                   \"Press OK to display segmented image.\")\n        return '\\n'.join(helpstr)\n\n    def _show_watershed(self):\n        viewer = self.image_viewer\n        edge_image = filter.sobel(viewer.image)\n        labels = morphology.watershed(edge_image, self.paint_tool.overlay)\n        viewer.ax.imshow(labels, cmap=plt.cm.jet, alpha=0.5)\n        viewer.redraw()\n\n\nimage = data.coins()\nplugin = WatershedPlugin()\nplugin += OKCancelButtons()\n\nviewer = ImageViewer(image)\nviewer += plugin\nviewer.show()\n", "path": "viewer_examples/plugins/watershed_demo.py"}, {"content": "import numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib.colors as mcolors\nLABELS_CMAP = mcolors.ListedColormap(['white', 'red', 'dodgerblue', 'gold',\n                                      'greenyellow', 'blueviolet'])\nfrom ...viewer.canvastools.base import CanvasToolBase\n\n\n__all__ = ['PaintTool']\n\n\nclass PaintTool(CanvasToolBase):\n    \"\"\"Widget for painting on top of a plot.\n\n    Parameters\n    ----------\n    manager : Viewer or PlotPlugin.\n        Skimage viewer or plot plugin object.\n    overlay_shape : shape tuple\n        2D shape tuple used to initialize overlay image.\n    alpha : float (between [0, 1])\n        Opacity of overlay\n    on_move : function\n        Function called whenever a control handle is moved.\n        This function must accept the end points of line as the only argument.\n    on_release : function\n        Function called whenever the control handle is released.\n    on_enter : function\n        Function called whenever the \"enter\" key is pressed.\n    rect_props : dict\n        Properties for :class:`matplotlib.patches.Rectangle`. This class\n        redefines defaults in :class:`matplotlib.widgets.RectangleSelector`.\n\n    Attributes\n    ----------\n    overlay : array\n        Overlay of painted labels displayed on top of image.\n    label : int\n        Current paint color.\n\n    Examples\n    ----------\n    >>> from skimage.data import camera\n    >>> import matplotlib.pyplot as plt\n    >>> from skimage.viewer.canvastools import PaintTool\n    >>> import numpy as np\n\n    >>> img = camera() #doctest: +SKIP\n\n    >>> ax = plt.subplot(111) #doctest: +SKIP \n    >>> plt.imshow(img, cmap=plt.cm.gray) #doctest: +SKIP\n    >>> p = PaintTool(ax,np.shape(img[:-1]),10,0.2) #doctest: +SKIP\n    >>> plt.show() #doctest: +SKIP\n\n    >>> mask = p.overlay #doctest: +SKIP\n    >>> plt.imshow(mask,cmap=plt.cm.gray) #doctest: +SKIP\n    >>> plt.show() #doctest: +SKIP\n    \"\"\"\n    def __init__(self, manager, overlay_shape, radius=5, alpha=0.3,\n                 on_move=None, on_release=None, on_enter=None,\n                 rect_props=None):\n        super(PaintTool, self).__init__(manager, on_move=on_move,\n                                        on_enter=on_enter,\n                                        on_release=on_release)\n\n        props = dict(edgecolor='r', facecolor='0.7', alpha=0.5, animated=True)\n        props.update(rect_props if rect_props is not None else {})\n\n        self.alpha = alpha\n        self.cmap = LABELS_CMAP\n        self._overlay_plot = None\n        self.shape = overlay_shape\n\n        self._cursor = plt.Rectangle((0, 0), 0, 0, **props)\n        self._cursor.set_visible(False)\n        self.ax.add_patch(self._cursor)\n\n        # `label` and `radius` can only be set after initializing `_cursor`\n        self.label = 1\n        self.radius = radius\n\n        # Note that the order is important: Redraw cursor *after* overlay\n        self.artists = [self._overlay_plot, self._cursor]\n        self.manager.add_tool(self)\n\n    @property\n    def label(self):\n        return self._label\n\n    @label.setter\n    def label(self, value):\n        if value >= self.cmap.N:\n            raise ValueError('Maximum label value = %s' % len(self.cmap - 1))\n        self._label = value\n        self._cursor.set_edgecolor(self.cmap(value))\n\n    @property\n    def radius(self):\n        return self._radius\n\n    @radius.setter\n    def radius(self, r):\n        self._radius = r\n        self._width = 2 * r + 1\n        self._cursor.set_width(self._width)\n        self._cursor.set_height(self._width)\n        self.window = CenteredWindow(r, self._shape)\n\n    @property\n    def overlay(self):\n        return self._overlay\n\n    @overlay.setter\n    def overlay(self, image):\n        self._overlay = image\n        if image is None:\n            self.ax.images.remove(self._overlay_plot)\n            self._overlay_plot = None\n        elif self._overlay_plot is None:\n            props = dict(cmap=self.cmap, alpha=self.alpha,\n                         norm=mcolors.NoNorm(), animated=True)\n            self._overlay_plot = self.ax.imshow(image, **props)\n        else:\n            self._overlay_plot.set_data(image)\n        self.redraw()\n\n    @property\n    def shape(self):\n        return self._shape\n\n    @shape.setter\n    def shape(self, shape):\n        self._shape = shape\n        if not self._overlay_plot is None:\n            self._overlay_plot.set_extent((-0.5, shape[1] + 0.5,\n                                           shape[0] + 0.5, -0.5))\n            self.radius = self._radius\n        self.overlay = np.zeros(shape, dtype='uint8')\n\n    def on_key_press(self, event):\n        if event.key == 'enter':\n            self.callback_on_enter(self.geometry)\n            self.redraw()\n\n    def on_mouse_press(self, event):\n        if event.button != 1 or not self.ax.in_axes(event):\n            return\n        self.update_cursor(event.xdata, event.ydata)\n        self.update_overlay(event.xdata, event.ydata)\n\n    def on_mouse_release(self, event):\n        if event.button != 1:\n            return\n        self.callback_on_release(self.geometry)\n\n    def on_move(self, event):\n        if not self.ax.in_axes(event):\n            self._cursor.set_visible(False)\n            self.redraw() # make sure cursor is not visible\n            return\n        self._cursor.set_visible(True)\n\n        self.update_cursor(event.xdata, event.ydata)\n        if event.button != 1:\n            self.redraw() # update cursor position\n            return\n        self.update_overlay(event.xdata, event.ydata)\n        self.callback_on_move(self.geometry)\n\n    def update_overlay(self, x, y):\n        overlay = self.overlay\n        overlay[self.window.at(y, x)] = self.label\n        # Note that overlay calls `redraw`\n        self.overlay = overlay\n\n    def update_cursor(self, x, y):\n        x = x - self.radius - 1\n        y = y - self.radius - 1\n        self._cursor.set_xy((x, y))\n\n    @property\n    def geometry(self):\n        return self.overlay\n\n\nclass CenteredWindow(object):\n    \"\"\"Window that create slices numpy arrays over 2D windows.\n\n    Examples\n    --------\n    >>> a = np.arange(16).reshape(4, 4)\n    >>> w = CenteredWindow(1, a.shape)\n    >>> a[w.at(1, 1)]\n    array([[ 0,  1,  2],\n           [ 4,  5,  6],\n           [ 8,  9, 10]])\n    >>> a[w.at(0, 0)]\n    array([[0, 1],\n           [4, 5]])\n    >>> a[w.at(4, 3)]\n    array([[14, 15]])\n    \"\"\"\n    def __init__(self, radius, array_shape):\n        self.radius = radius\n        self.array_shape = array_shape\n\n    def at(self, row, col):\n        h, w = self.array_shape\n        r = self.radius\n        xmin = max(0, col - r)\n        xmax = min(w, col + r + 1)\n        ymin = max(0, row - r)\n        ymax = min(h, row + r + 1)\n        return [slice(ymin, ymax), slice(xmin, xmax)]\n\n\nif __name__ == '__main__':  # pragma: no cover\n    np.testing.rundocs()\n    from ... import data\n    from ...viewer import ImageViewer\n\n    image = data.camera()\n\n    viewer = ImageViewer(image)\n    paint_tool = PaintTool(viewer, image.shape)\n    viewer.show()\n", "path": "skimage/viewer/canvastools/painttool.py"}], "after_files": [{"content": "import matplotlib.pyplot as plt\n\nfrom skimage import data\nfrom skimage import filters\nfrom skimage import morphology\nfrom skimage.viewer import ImageViewer\nfrom skimage.viewer.widgets import history\nfrom skimage.viewer.plugins.labelplugin import LabelPainter\n\n\nclass OKCancelButtons(history.OKCancelButtons):\n\n    def update_original_image(self):\n        # OKCancelButtons updates the original image with the filtered image\n        # by default. Override this method to update the overlay.\n        self.plugin._show_watershed()\n        self.plugin.close()\n\n\nclass WatershedPlugin(LabelPainter):\n\n    def help(self):\n        helpstr = (\"Watershed plugin\",\n                   \"----------------\",\n                   \"Use mouse to paint each region with a different label.\",\n                   \"Press OK to display segmented image.\")\n        return '\\n'.join(helpstr)\n\n    def _show_watershed(self):\n        viewer = self.image_viewer\n        edge_image = filters.sobel(viewer.image)\n        labels = morphology.watershed(edge_image, self.paint_tool.overlay)\n        viewer.ax.imshow(labels, cmap=plt.cm.jet, alpha=0.5)\n        viewer.redraw()\n\n\nimage = data.coins()\nplugin = WatershedPlugin()\nplugin += OKCancelButtons()\n\nviewer = ImageViewer(image)\nviewer += plugin\nviewer.show()\n", "path": "viewer_examples/plugins/watershed_demo.py"}, {"content": "import numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib.colors as mcolors\nLABELS_CMAP = mcolors.ListedColormap(['white', 'red', 'dodgerblue', 'gold',\n                                      'greenyellow', 'blueviolet'])\nfrom ...viewer.canvastools.base import CanvasToolBase\n\n\n__all__ = ['PaintTool']\n\n\nclass PaintTool(CanvasToolBase):\n    \"\"\"Widget for painting on top of a plot.\n\n    Parameters\n    ----------\n    manager : Viewer or PlotPlugin.\n        Skimage viewer or plot plugin object.\n    overlay_shape : shape tuple\n        2D shape tuple used to initialize overlay image.\n    alpha : float (between [0, 1])\n        Opacity of overlay\n    on_move : function\n        Function called whenever a control handle is moved.\n        This function must accept the end points of line as the only argument.\n    on_release : function\n        Function called whenever the control handle is released.\n    on_enter : function\n        Function called whenever the \"enter\" key is pressed.\n    rect_props : dict\n        Properties for :class:`matplotlib.patches.Rectangle`. This class\n        redefines defaults in :class:`matplotlib.widgets.RectangleSelector`.\n\n    Attributes\n    ----------\n    overlay : array\n        Overlay of painted labels displayed on top of image.\n    label : int\n        Current paint color.\n\n    Examples\n    ----------\n    >>> from skimage.data import camera\n    >>> import matplotlib.pyplot as plt\n    >>> from skimage.viewer.canvastools import PaintTool\n    >>> import numpy as np\n\n    >>> img = camera() #doctest: +SKIP\n\n    >>> ax = plt.subplot(111) #doctest: +SKIP \n    >>> plt.imshow(img, cmap=plt.cm.gray) #doctest: +SKIP\n    >>> p = PaintTool(ax,np.shape(img[:-1]),10,0.2) #doctest: +SKIP\n    >>> plt.show() #doctest: +SKIP\n\n    >>> mask = p.overlay #doctest: +SKIP\n    >>> plt.imshow(mask,cmap=plt.cm.gray) #doctest: +SKIP\n    >>> plt.show() #doctest: +SKIP\n    \"\"\"\n    def __init__(self, manager, overlay_shape, radius=5, alpha=0.3,\n                 on_move=None, on_release=None, on_enter=None,\n                 rect_props=None):\n        super(PaintTool, self).__init__(manager, on_move=on_move,\n                                        on_enter=on_enter,\n                                        on_release=on_release)\n\n        props = dict(edgecolor='r', facecolor='0.7', alpha=0.5, animated=True)\n        props.update(rect_props if rect_props is not None else {})\n\n        self.alpha = alpha\n        self.cmap = LABELS_CMAP\n        self._overlay_plot = None\n        self.shape = overlay_shape\n\n        self._cursor = plt.Rectangle((0, 0), 0, 0, **props)\n        self._cursor.set_visible(False)\n        self.ax.add_patch(self._cursor)\n\n        # `label` and `radius` can only be set after initializing `_cursor`\n        self.label = 1\n        self.radius = radius\n\n        # Note that the order is important: Redraw cursor *after* overlay\n        self.artists = [self._overlay_plot, self._cursor]\n        self.manager.add_tool(self)\n\n    @property\n    def label(self):\n        return self._label\n\n    @label.setter\n    def label(self, value):\n        if value >= self.cmap.N:\n            raise ValueError('Maximum label value = %s' % len(self.cmap - 1))\n        self._label = value\n        self._cursor.set_edgecolor(self.cmap(value))\n\n    @property\n    def radius(self):\n        return self._radius\n\n    @radius.setter\n    def radius(self, r):\n        self._radius = r\n        self._width = 2 * r + 1\n        self._cursor.set_width(self._width)\n        self._cursor.set_height(self._width)\n        self.window = CenteredWindow(r, self._shape)\n\n    @property\n    def overlay(self):\n        return self._overlay\n\n    @overlay.setter\n    def overlay(self, image):\n        self._overlay = image\n        if image is None:\n            self.ax.images.remove(self._overlay_plot)\n            self._overlay_plot = None\n        elif self._overlay_plot is None:\n            props = dict(cmap=self.cmap, alpha=self.alpha,\n                         norm=mcolors.NoNorm(), animated=True)\n            self._overlay_plot = self.ax.imshow(image, **props)\n        else:\n            self._overlay_plot.set_data(image)\n        self.redraw()\n\n    @property\n    def shape(self):\n        return self._shape\n\n    @shape.setter\n    def shape(self, shape):\n        self._shape = shape\n        if not self._overlay_plot is None:\n            self._overlay_plot.set_extent((-0.5, shape[1] + 0.5,\n                                           shape[0] + 0.5, -0.5))\n            self.radius = self._radius\n        self.overlay = np.zeros(shape, dtype='uint8')\n\n    def on_key_press(self, event):\n        if event.key == 'enter':\n            self.callback_on_enter(self.geometry)\n            self.redraw()\n\n    def on_mouse_press(self, event):\n        if event.button != 1 or not self.ax.in_axes(event):\n            return\n        self.update_cursor(event.xdata, event.ydata)\n        self.update_overlay(event.xdata, event.ydata)\n\n    def on_mouse_release(self, event):\n        if event.button != 1:\n            return\n        self.callback_on_release(self.geometry)\n\n    def on_move(self, event):\n        if not self.ax.in_axes(event):\n            self._cursor.set_visible(False)\n            self.redraw() # make sure cursor is not visible\n            return\n        self._cursor.set_visible(True)\n\n        self.update_cursor(event.xdata, event.ydata)\n        if event.button != 1:\n            self.redraw() # update cursor position\n            return\n        self.update_overlay(event.xdata, event.ydata)\n        self.callback_on_move(self.geometry)\n\n    def update_overlay(self, x, y):\n        overlay = self.overlay\n        overlay[self.window.at(y, x)] = self.label\n        # Note that overlay calls `redraw`\n        self.overlay = overlay\n\n    def update_cursor(self, x, y):\n        x = x - self.radius - 1\n        y = y - self.radius - 1\n        self._cursor.set_xy((x, y))\n\n    @property\n    def geometry(self):\n        return self.overlay\n\n\nclass CenteredWindow(object):\n    \"\"\"Window that create slices numpy arrays over 2D windows.\n\n    Examples\n    --------\n    >>> a = np.arange(16).reshape(4, 4)\n    >>> w = CenteredWindow(1, a.shape)\n    >>> a[w.at(1, 1)]\n    array([[ 0,  1,  2],\n           [ 4,  5,  6],\n           [ 8,  9, 10]])\n    >>> a[w.at(0, 0)]\n    array([[0, 1],\n           [4, 5]])\n    >>> a[w.at(4, 3)]\n    array([[14, 15]])\n    \"\"\"\n    def __init__(self, radius, array_shape):\n        self.radius = radius\n        self.array_shape = array_shape\n\n    def at(self, row, col):\n        h, w = self.array_shape\n        r = round(self.radius)\n        # Note: the int() cast is necessary because row and col are np.float64,\n        # which does not get cast by round(), unlike a normal Python float:\n        # >>> round(4.5)\n        # 4\n        # >>> round(np.float64(4.5))\n        # 4.0\n        # >>> int(round(np.float64(4.5)))\n        # 4\n        row, col = int(round(row)), int(round(col))\n        xmin = max(0, col - r)\n        xmax = min(w, col + r + 1)\n        ymin = max(0, row - r)\n        ymax = min(h, row + r + 1)\n        return (slice(ymin, ymax), slice(xmin, xmax))\n\n\nif __name__ == '__main__':  # pragma: no cover\n    np.testing.rundocs()\n    from ... import data\n    from ...viewer import ImageViewer\n\n    image = data.camera()\n\n    viewer = ImageViewer(image)\n    paint_tool = PaintTool(viewer, image.shape)\n    viewer.show()\n", "path": "skimage/viewer/canvastools/painttool.py"}]}