We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
VisPy isocurve incompatible with matplotlib 2.2.0
Matplotlib 2.2 is now out and the private contour api `from matplotlib import _cntr` has been removed. We knew this day would come. @QuLogic pointed this thread out on gitter: https://mail.python.org/pipermail/matplotlib-users/2018-March/001313.html

The TL;DR of that is that we can either copy the source from old mpl releases or we could try using skimage. I'm not a huge fan of adding such a huge (optional) dependency on to vispy, but as `isocurve.py` sits right now it uses the `_cntr` classes as an optional dependency so it shouldn't be a huge deal.

http://scikit-image.org/docs/dev/auto_examples/edges/plot_contours.html

As a quick hack I will try to make a PR in the next couple days to switch the import of `_cntr` to a try/except and use the slow contouring method if it isn't found. That should at least let our tests pass and give github users working code.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `vispy/visuals/isocurve.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright (c) Vispy Development Team. All Rights Reserved.
3 # Distributed under the (new) BSD License. See LICENSE.txt for more info.
4 
5 from __future__ import division
6 
7 import numpy as np
8 
9 from .line import LineVisual
10 from ..color import ColorArray
11 from ..color.colormap import _normalize, get_colormap
12 from ..geometry.isocurve import isocurve
13 from ..testing import has_matplotlib
14 
15 # checking for matplotlib
16 _HAS_MPL = has_matplotlib()
17 if _HAS_MPL:
18     try:
19         from matplotlib import _cntr as cntr
20     except ImportError:
21         import warnings
22         warnings.warn("VisPy is not yet compatible with matplotlib 2.2+")
23         _HAS_MPL = False
24         cntr = None
25 
26 
27 class IsocurveVisual(LineVisual):
28     """Displays an isocurve of a 2D scalar array.
29 
30     Parameters
31     ----------
32     data : ndarray | None
33         2D scalar array.
34     levels : ndarray, shape (Nlev,) | None
35         The levels at which the isocurve is constructed from "*data*".
36     color_lev : Color, colormap name, tuple, list or array
37         The color to use when drawing the line. If a list is given, it
38         must be of shape (Nlev), if an array is given, it must be of
39         shape (Nlev, ...). and provide one color per level (rgba, colorname).
40     clim : tuple
41         (min, max) limits to apply when mapping level values through a
42         colormap.
43     **kwargs : dict
44         Keyword arguments to pass to `LineVisual`.
45 
46     Notes
47     -----
48     """
49     def __init__(self, data=None, levels=None, color_lev=None, clim=None,
50                  **kwargs):
51         self._data = None
52         self._levels = levels
53         self._color_lev = color_lev
54         self._clim = clim
55         self._need_color_update = True
56         self._need_level_update = True
57         self._need_recompute = True
58         self._X = None
59         self._Y = None
60         self._iso = None
61         self._level_min = None
62         self._data_is_uniform = False
63         self._lc = None
64         self._cl = None
65         self._li = None
66         self._connect = None
67         self._verts = None
68         kwargs['method'] = 'gl'
69         kwargs['antialias'] = False
70         LineVisual.__init__(self, **kwargs)
71         if data is not None:
72             self.set_data(data)
73 
74     @property
75     def levels(self):
76         """ The threshold at which the isocurve is constructed from the
77         2D data.
78         """
79         return self._levels
80 
81     @levels.setter
82     def levels(self, levels):
83         self._levels = levels
84         self._need_level_update = True
85         self._need_recompute = True
86         self.update()
87 
88     @property
89     def color(self):
90         return self._color_lev
91 
92     @color.setter
93     def color(self, color):
94         self._color_lev = color
95         self._need_level_update = True
96         self._need_color_update = True
97         self.update()
98 
99     def set_data(self, data):
100         """ Set the scalar array data
101 
102         Parameters
103         ----------
104         data : ndarray
105             A 2D array of scalar values. The isocurve is constructed to show
106             all locations in the scalar field equal to ``self.levels``.
107         """
108         self._data = data
109 
110         # if using matplotlib isoline algorithm we have to check for meshgrid
111         # and we can setup the tracer object here
112         if _HAS_MPL:
113             if self._X is None or self._X.shape != data.shape:
114                 self._X, self._Y = np.meshgrid(np.arange(data.shape[1]),
115                                                np.arange(data.shape[0]))
116             self._iso = cntr.Cntr(self._X, self._Y, self._data.astype(float))
117 
118         if self._clim is None:
119             self._clim = (data.min(), data.max())
120 
121         # sanity check,
122         # should we raise an error here, since no isolines can be drawn?
123         # for now, _prepare_draw returns False if no isoline can be drawn
124         if self._data.min() != self._data.max():
125             self._data_is_uniform = False
126         else:
127             self._data_is_uniform = True
128 
129         self._need_recompute = True
130         self.update()
131 
132     def _get_verts_and_connect(self, paths):
133         """ retrieve vertices and connects from given paths-list
134         """
135         verts = np.vstack(paths)
136         gaps = np.add.accumulate(np.array([len(x) for x in paths])) - 1
137         connect = np.ones(gaps[-1], dtype=bool)
138         connect[gaps[:-1]] = False
139         return verts, connect
140 
141     def _compute_iso_line(self):
142         """ compute LineVisual vertices, connects and color-index
143         """
144         level_index = []
145         connects = []
146         verts = []
147 
148         # calculate which level are within data range
149         # this works for now and the existing examples, but should be tested
150         # thoroughly also with the data-sanity check in set_data-function
151         choice = np.nonzero((self.levels > self._data.min()) &
152                             (self._levels < self._data.max()))
153         levels_to_calc = np.array(self.levels)[choice]
154 
155         # save minimum level index
156         self._level_min = choice[0][0]
157 
158         for level in levels_to_calc:
159             # if we use matplotlib isoline algorithm we need to add half a
160             # pixel in both (x,y) dimensions because isolines are aligned to
161             # pixel centers
162             if _HAS_MPL:
163                 nlist = self._iso.trace(level, level, 0)
164                 paths = nlist[:len(nlist)//2]
165                 v, c = self._get_verts_and_connect(paths)
166                 v += np.array([0.5, 0.5])
167             else:
168                 paths = isocurve(self._data.astype(float).T, level,
169                                  extend_to_edge=True, connected=True)
170                 v, c = self._get_verts_and_connect(paths)
171 
172             level_index.append(v.shape[0])
173             connects.append(np.hstack((c, [False])))
174             verts.append(v)
175 
176         self._li = np.hstack(level_index)
177         self._connect = np.hstack(connects)
178         self._verts = np.vstack(verts)
179 
180     def _compute_iso_color(self):
181         """ compute LineVisual color from level index and corresponding color
182         """
183         level_color = []
184         colors = self._lc
185         for i, index in enumerate(self._li):
186             level_color.append(np.zeros((index, 4)) +
187                                colors[i+self._level_min])
188         self._cl = np.vstack(level_color)
189 
190     def _levels_to_colors(self):
191         # computes ColorArrays for given levels
192         # try _color_lev as colormap, except as everything else
193         try:
194             f_color_levs = get_colormap(self._color_lev)
195         except (KeyError, TypeError):
196             colors = ColorArray(self._color_lev).rgba
197         else:
198             lev = _normalize(self._levels, self._clim[0], self._clim[1])
199             # map function expects (Nlev,1)!
200             colors = f_color_levs.map(lev[:, np.newaxis])
201 
202         # broadcast to (nlev, 4) array
203         if len(colors) == 1:
204             colors = colors * np.ones((len(self._levels), 1))
205 
206         # detect color_lev/levels mismatch and raise error
207         if (len(colors) != len(self._levels)):
208             raise TypeError("Color/level mismatch. Color must be of shape "
209                             "(Nlev, ...) and provide one color per level")
210 
211         self._lc = colors
212 
213     def _prepare_draw(self, view):
214         if (self._data is None or self._levels is None or
215                 self._color_lev is None or self._data_is_uniform):
216             return False
217 
218         if self._need_level_update:
219             self._levels_to_colors()
220             self._need_level_update = False
221 
222         if self._need_recompute:
223             self._compute_iso_line()
224             self._compute_iso_color()
225             LineVisual.set_data(self, pos=self._verts, connect=self._connect,
226                                 color=self._cl)
227             self._need_recompute = False
228 
229         if self._need_color_update:
230             self._compute_iso_color()
231             LineVisual.set_data(self, color=self._cl)
232             self._need_color_update = False
233 
234         return LineVisual._prepare_draw(self, view)
235
```
--- 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/vispy/visuals/isocurve.py b/vispy/visuals/isocurve.py
--- a/vispy/visuals/isocurve.py
+++ b/vispy/visuals/isocurve.py
@@ -10,18 +10,16 @@
 from ..color import ColorArray
 from ..color.colormap import _normalize, get_colormap
 from ..geometry.isocurve import isocurve
-from ..testing import has_matplotlib
+from ..testing import has_skimage
 
-# checking for matplotlib
-_HAS_MPL = has_matplotlib()
-if _HAS_MPL:
+# checking for scikit-image
+_HAS_SKI = has_skimage()
+if _HAS_SKI:
     try:
-        from matplotlib import _cntr as cntr
+        from skimage.measure import find_contours
     except ImportError:
-        import warnings
-        warnings.warn("VisPy is not yet compatible with matplotlib 2.2+")
-        _HAS_MPL = False
-        cntr = None
+        _HAS_SKI = False
+        find_contours = None
 
 
 class IsocurveVisual(LineVisual):
@@ -55,9 +53,6 @@
         self._need_color_update = True
         self._need_level_update = True
         self._need_recompute = True
-        self._X = None
-        self._Y = None
-        self._iso = None
         self._level_min = None
         self._data_is_uniform = False
         self._lc = None
@@ -107,14 +102,6 @@
         """
         self._data = data
 
-        # if using matplotlib isoline algorithm we have to check for meshgrid
-        # and we can setup the tracer object here
-        if _HAS_MPL:
-            if self._X is None or self._X.shape != data.shape:
-                self._X, self._Y = np.meshgrid(np.arange(data.shape[1]),
-                                               np.arange(data.shape[0]))
-            self._iso = cntr.Cntr(self._X, self._Y, self._data.astype(float))
-
         if self._clim is None:
             self._clim = (data.min(), data.max())
 
@@ -156,13 +143,15 @@
         self._level_min = choice[0][0]
 
         for level in levels_to_calc:
-            # if we use matplotlib isoline algorithm we need to add half a
+            # if we use skimage isoline algorithm we need to add half a
             # pixel in both (x,y) dimensions because isolines are aligned to
             # pixel centers
-            if _HAS_MPL:
-                nlist = self._iso.trace(level, level, 0)
-                paths = nlist[:len(nlist)//2]
-                v, c = self._get_verts_and_connect(paths)
+            if _HAS_SKI:
+                contours = find_contours(self._data, level,
+                                         positive_orientation='high')
+                v, c = self._get_verts_and_connect(contours)
+                # swap row, column to column, row (x, y)
+                v[:, [0, 1]] = v[:, [1, 0]]
                 v += np.array([0.5, 0.5])
             else:
                 paths = isocurve(self._data.astype(float).T, level,

{"golden_diff": "diff --git a/vispy/visuals/isocurve.py b/vispy/visuals/isocurve.py\n--- a/vispy/visuals/isocurve.py\n+++ b/vispy/visuals/isocurve.py\n@@ -10,18 +10,16 @@\n from ..color import ColorArray\n from ..color.colormap import _normalize, get_colormap\n from ..geometry.isocurve import isocurve\n-from ..testing import has_matplotlib\n+from ..testing import has_skimage\n \n-# checking for matplotlib\n-_HAS_MPL = has_matplotlib()\n-if _HAS_MPL:\n+# checking for scikit-image\n+_HAS_SKI = has_skimage()\n+if _HAS_SKI:\n     try:\n-        from matplotlib import _cntr as cntr\n+        from skimage.measure import find_contours\n     except ImportError:\n-        import warnings\n-        warnings.warn(\"VisPy is not yet compatible with matplotlib 2.2+\")\n-        _HAS_MPL = False\n-        cntr = None\n+        _HAS_SKI = False\n+        find_contours = None\n \n \n class IsocurveVisual(LineVisual):\n@@ -55,9 +53,6 @@\n         self._need_color_update = True\n         self._need_level_update = True\n         self._need_recompute = True\n-        self._X = None\n-        self._Y = None\n-        self._iso = None\n         self._level_min = None\n         self._data_is_uniform = False\n         self._lc = None\n@@ -107,14 +102,6 @@\n         \"\"\"\n         self._data = data\n \n-        # if using matplotlib isoline algorithm we have to check for meshgrid\n-        # and we can setup the tracer object here\n-        if _HAS_MPL:\n-            if self._X is None or self._X.shape != data.shape:\n-                self._X, self._Y = np.meshgrid(np.arange(data.shape[1]),\n-                                               np.arange(data.shape[0]))\n-            self._iso = cntr.Cntr(self._X, self._Y, self._data.astype(float))\n-\n         if self._clim is None:\n             self._clim = (data.min(), data.max())\n \n@@ -156,13 +143,15 @@\n         self._level_min = choice[0][0]\n \n         for level in levels_to_calc:\n-            # if we use matplotlib isoline algorithm we need to add half a\n+            # if we use skimage isoline algorithm we need to add half a\n             # pixel in both (x,y) dimensions because isolines are aligned to\n             # pixel centers\n-            if _HAS_MPL:\n-                nlist = self._iso.trace(level, level, 0)\n-                paths = nlist[:len(nlist)//2]\n-                v, c = self._get_verts_and_connect(paths)\n+            if _HAS_SKI:\n+                contours = find_contours(self._data, level,\n+                                         positive_orientation='high')\n+                v, c = self._get_verts_and_connect(contours)\n+                # swap row, column to column, row (x, y)\n+                v[:, [0, 1]] = v[:, [1, 0]]\n                 v += np.array([0.5, 0.5])\n             else:\n                 paths = isocurve(self._data.astype(float).T, level,\n", "issue": "VisPy isocurve incompatible with matplotlib 2.2.0\nMatplotlib 2.2 is now out and the private contour api `from matplotlib import _cntr` has been removed. We knew this day would come. @QuLogic pointed this thread out on gitter: https://mail.python.org/pipermail/matplotlib-users/2018-March/001313.html\r\n\r\nThe TL;DR of that is that we can either copy the source from old mpl releases or we could try using skimage. I'm not a huge fan of adding such a huge (optional) dependency on to vispy, but as `isocurve.py` sits right now it uses the `_cntr` classes as an optional dependency so it shouldn't be a huge deal.\r\n\r\nhttp://scikit-image.org/docs/dev/auto_examples/edges/plot_contours.html\r\n\r\nAs a quick hack I will try to make a PR in the next couple days to switch the import of `_cntr` to a try/except and use the slow contouring method if it isn't found. That should at least let our tests pass and give github users working code.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) Vispy Development Team. All Rights Reserved.\n# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n\nfrom __future__ import division\n\nimport numpy as np\n\nfrom .line import LineVisual\nfrom ..color import ColorArray\nfrom ..color.colormap import _normalize, get_colormap\nfrom ..geometry.isocurve import isocurve\nfrom ..testing import has_matplotlib\n\n# checking for matplotlib\n_HAS_MPL = has_matplotlib()\nif _HAS_MPL:\n    try:\n        from matplotlib import _cntr as cntr\n    except ImportError:\n        import warnings\n        warnings.warn(\"VisPy is not yet compatible with matplotlib 2.2+\")\n        _HAS_MPL = False\n        cntr = None\n\n\nclass IsocurveVisual(LineVisual):\n    \"\"\"Displays an isocurve of a 2D scalar array.\n\n    Parameters\n    ----------\n    data : ndarray | None\n        2D scalar array.\n    levels : ndarray, shape (Nlev,) | None\n        The levels at which the isocurve is constructed from \"*data*\".\n    color_lev : Color, colormap name, tuple, list or array\n        The color to use when drawing the line. If a list is given, it\n        must be of shape (Nlev), if an array is given, it must be of\n        shape (Nlev, ...). and provide one color per level (rgba, colorname).\n    clim : tuple\n        (min, max) limits to apply when mapping level values through a\n        colormap.\n    **kwargs : dict\n        Keyword arguments to pass to `LineVisual`.\n\n    Notes\n    -----\n    \"\"\"\n    def __init__(self, data=None, levels=None, color_lev=None, clim=None,\n                 **kwargs):\n        self._data = None\n        self._levels = levels\n        self._color_lev = color_lev\n        self._clim = clim\n        self._need_color_update = True\n        self._need_level_update = True\n        self._need_recompute = True\n        self._X = None\n        self._Y = None\n        self._iso = None\n        self._level_min = None\n        self._data_is_uniform = False\n        self._lc = None\n        self._cl = None\n        self._li = None\n        self._connect = None\n        self._verts = None\n        kwargs['method'] = 'gl'\n        kwargs['antialias'] = False\n        LineVisual.__init__(self, **kwargs)\n        if data is not None:\n            self.set_data(data)\n\n    @property\n    def levels(self):\n        \"\"\" The threshold at which the isocurve is constructed from the\n        2D data.\n        \"\"\"\n        return self._levels\n\n    @levels.setter\n    def levels(self, levels):\n        self._levels = levels\n        self._need_level_update = True\n        self._need_recompute = True\n        self.update()\n\n    @property\n    def color(self):\n        return self._color_lev\n\n    @color.setter\n    def color(self, color):\n        self._color_lev = color\n        self._need_level_update = True\n        self._need_color_update = True\n        self.update()\n\n    def set_data(self, data):\n        \"\"\" Set the scalar array data\n\n        Parameters\n        ----------\n        data : ndarray\n            A 2D array of scalar values. The isocurve is constructed to show\n            all locations in the scalar field equal to ``self.levels``.\n        \"\"\"\n        self._data = data\n\n        # if using matplotlib isoline algorithm we have to check for meshgrid\n        # and we can setup the tracer object here\n        if _HAS_MPL:\n            if self._X is None or self._X.shape != data.shape:\n                self._X, self._Y = np.meshgrid(np.arange(data.shape[1]),\n                                               np.arange(data.shape[0]))\n            self._iso = cntr.Cntr(self._X, self._Y, self._data.astype(float))\n\n        if self._clim is None:\n            self._clim = (data.min(), data.max())\n\n        # sanity check,\n        # should we raise an error here, since no isolines can be drawn?\n        # for now, _prepare_draw returns False if no isoline can be drawn\n        if self._data.min() != self._data.max():\n            self._data_is_uniform = False\n        else:\n            self._data_is_uniform = True\n\n        self._need_recompute = True\n        self.update()\n\n    def _get_verts_and_connect(self, paths):\n        \"\"\" retrieve vertices and connects from given paths-list\n        \"\"\"\n        verts = np.vstack(paths)\n        gaps = np.add.accumulate(np.array([len(x) for x in paths])) - 1\n        connect = np.ones(gaps[-1], dtype=bool)\n        connect[gaps[:-1]] = False\n        return verts, connect\n\n    def _compute_iso_line(self):\n        \"\"\" compute LineVisual vertices, connects and color-index\n        \"\"\"\n        level_index = []\n        connects = []\n        verts = []\n\n        # calculate which level are within data range\n        # this works for now and the existing examples, but should be tested\n        # thoroughly also with the data-sanity check in set_data-function\n        choice = np.nonzero((self.levels > self._data.min()) &\n                            (self._levels < self._data.max()))\n        levels_to_calc = np.array(self.levels)[choice]\n\n        # save minimum level index\n        self._level_min = choice[0][0]\n\n        for level in levels_to_calc:\n            # if we use matplotlib isoline algorithm we need to add half a\n            # pixel in both (x,y) dimensions because isolines are aligned to\n            # pixel centers\n            if _HAS_MPL:\n                nlist = self._iso.trace(level, level, 0)\n                paths = nlist[:len(nlist)//2]\n                v, c = self._get_verts_and_connect(paths)\n                v += np.array([0.5, 0.5])\n            else:\n                paths = isocurve(self._data.astype(float).T, level,\n                                 extend_to_edge=True, connected=True)\n                v, c = self._get_verts_and_connect(paths)\n\n            level_index.append(v.shape[0])\n            connects.append(np.hstack((c, [False])))\n            verts.append(v)\n\n        self._li = np.hstack(level_index)\n        self._connect = np.hstack(connects)\n        self._verts = np.vstack(verts)\n\n    def _compute_iso_color(self):\n        \"\"\" compute LineVisual color from level index and corresponding color\n        \"\"\"\n        level_color = []\n        colors = self._lc\n        for i, index in enumerate(self._li):\n            level_color.append(np.zeros((index, 4)) +\n                               colors[i+self._level_min])\n        self._cl = np.vstack(level_color)\n\n    def _levels_to_colors(self):\n        # computes ColorArrays for given levels\n        # try _color_lev as colormap, except as everything else\n        try:\n            f_color_levs = get_colormap(self._color_lev)\n        except (KeyError, TypeError):\n            colors = ColorArray(self._color_lev).rgba\n        else:\n            lev = _normalize(self._levels, self._clim[0], self._clim[1])\n            # map function expects (Nlev,1)!\n            colors = f_color_levs.map(lev[:, np.newaxis])\n\n        # broadcast to (nlev, 4) array\n        if len(colors) == 1:\n            colors = colors * np.ones((len(self._levels), 1))\n\n        # detect color_lev/levels mismatch and raise error\n        if (len(colors) != len(self._levels)):\n            raise TypeError(\"Color/level mismatch. Color must be of shape \"\n                            \"(Nlev, ...) and provide one color per level\")\n\n        self._lc = colors\n\n    def _prepare_draw(self, view):\n        if (self._data is None or self._levels is None or\n                self._color_lev is None or self._data_is_uniform):\n            return False\n\n        if self._need_level_update:\n            self._levels_to_colors()\n            self._need_level_update = False\n\n        if self._need_recompute:\n            self._compute_iso_line()\n            self._compute_iso_color()\n            LineVisual.set_data(self, pos=self._verts, connect=self._connect,\n                                color=self._cl)\n            self._need_recompute = False\n\n        if self._need_color_update:\n            self._compute_iso_color()\n            LineVisual.set_data(self, color=self._cl)\n            self._need_color_update = False\n\n        return LineVisual._prepare_draw(self, view)\n", "path": "vispy/visuals/isocurve.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) Vispy Development Team. All Rights Reserved.\n# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n\nfrom __future__ import division\n\nimport numpy as np\n\nfrom .line import LineVisual\nfrom ..color import ColorArray\nfrom ..color.colormap import _normalize, get_colormap\nfrom ..geometry.isocurve import isocurve\nfrom ..testing import has_skimage\n\n# checking for scikit-image\n_HAS_SKI = has_skimage()\nif _HAS_SKI:\n    try:\n        from skimage.measure import find_contours\n    except ImportError:\n        _HAS_SKI = False\n        find_contours = None\n\n\nclass IsocurveVisual(LineVisual):\n    \"\"\"Displays an isocurve of a 2D scalar array.\n\n    Parameters\n    ----------\n    data : ndarray | None\n        2D scalar array.\n    levels : ndarray, shape (Nlev,) | None\n        The levels at which the isocurve is constructed from \"*data*\".\n    color_lev : Color, colormap name, tuple, list or array\n        The color to use when drawing the line. If a list is given, it\n        must be of shape (Nlev), if an array is given, it must be of\n        shape (Nlev, ...). and provide one color per level (rgba, colorname).\n    clim : tuple\n        (min, max) limits to apply when mapping level values through a\n        colormap.\n    **kwargs : dict\n        Keyword arguments to pass to `LineVisual`.\n\n    Notes\n    -----\n    \"\"\"\n    def __init__(self, data=None, levels=None, color_lev=None, clim=None,\n                 **kwargs):\n        self._data = None\n        self._levels = levels\n        self._color_lev = color_lev\n        self._clim = clim\n        self._need_color_update = True\n        self._need_level_update = True\n        self._need_recompute = True\n        self._level_min = None\n        self._data_is_uniform = False\n        self._lc = None\n        self._cl = None\n        self._li = None\n        self._connect = None\n        self._verts = None\n        kwargs['method'] = 'gl'\n        kwargs['antialias'] = False\n        LineVisual.__init__(self, **kwargs)\n        if data is not None:\n            self.set_data(data)\n\n    @property\n    def levels(self):\n        \"\"\" The threshold at which the isocurve is constructed from the\n        2D data.\n        \"\"\"\n        return self._levels\n\n    @levels.setter\n    def levels(self, levels):\n        self._levels = levels\n        self._need_level_update = True\n        self._need_recompute = True\n        self.update()\n\n    @property\n    def color(self):\n        return self._color_lev\n\n    @color.setter\n    def color(self, color):\n        self._color_lev = color\n        self._need_level_update = True\n        self._need_color_update = True\n        self.update()\n\n    def set_data(self, data):\n        \"\"\" Set the scalar array data\n\n        Parameters\n        ----------\n        data : ndarray\n            A 2D array of scalar values. The isocurve is constructed to show\n            all locations in the scalar field equal to ``self.levels``.\n        \"\"\"\n        self._data = data\n\n        if self._clim is None:\n            self._clim = (data.min(), data.max())\n\n        # sanity check,\n        # should we raise an error here, since no isolines can be drawn?\n        # for now, _prepare_draw returns False if no isoline can be drawn\n        if self._data.min() != self._data.max():\n            self._data_is_uniform = False\n        else:\n            self._data_is_uniform = True\n\n        self._need_recompute = True\n        self.update()\n\n    def _get_verts_and_connect(self, paths):\n        \"\"\" retrieve vertices and connects from given paths-list\n        \"\"\"\n        verts = np.vstack(paths)\n        gaps = np.add.accumulate(np.array([len(x) for x in paths])) - 1\n        connect = np.ones(gaps[-1], dtype=bool)\n        connect[gaps[:-1]] = False\n        return verts, connect\n\n    def _compute_iso_line(self):\n        \"\"\" compute LineVisual vertices, connects and color-index\n        \"\"\"\n        level_index = []\n        connects = []\n        verts = []\n\n        # calculate which level are within data range\n        # this works for now and the existing examples, but should be tested\n        # thoroughly also with the data-sanity check in set_data-function\n        choice = np.nonzero((self.levels > self._data.min()) &\n                            (self._levels < self._data.max()))\n        levels_to_calc = np.array(self.levels)[choice]\n\n        # save minimum level index\n        self._level_min = choice[0][0]\n\n        for level in levels_to_calc:\n            # if we use skimage isoline algorithm we need to add half a\n            # pixel in both (x,y) dimensions because isolines are aligned to\n            # pixel centers\n            if _HAS_SKI:\n                contours = find_contours(self._data, level,\n                                         positive_orientation='high')\n                v, c = self._get_verts_and_connect(contours)\n                # swap row, column to column, row (x, y)\n                v[:, [0, 1]] = v[:, [1, 0]]\n                v += np.array([0.5, 0.5])\n            else:\n                paths = isocurve(self._data.astype(float).T, level,\n                                 extend_to_edge=True, connected=True)\n                v, c = self._get_verts_and_connect(paths)\n\n            level_index.append(v.shape[0])\n            connects.append(np.hstack((c, [False])))\n            verts.append(v)\n\n        self._li = np.hstack(level_index)\n        self._connect = np.hstack(connects)\n        self._verts = np.vstack(verts)\n\n    def _compute_iso_color(self):\n        \"\"\" compute LineVisual color from level index and corresponding color\n        \"\"\"\n        level_color = []\n        colors = self._lc\n        for i, index in enumerate(self._li):\n            level_color.append(np.zeros((index, 4)) +\n                               colors[i+self._level_min])\n        self._cl = np.vstack(level_color)\n\n    def _levels_to_colors(self):\n        # computes ColorArrays for given levels\n        # try _color_lev as colormap, except as everything else\n        try:\n            f_color_levs = get_colormap(self._color_lev)\n        except (KeyError, TypeError):\n            colors = ColorArray(self._color_lev).rgba\n        else:\n            lev = _normalize(self._levels, self._clim[0], self._clim[1])\n            # map function expects (Nlev,1)!\n            colors = f_color_levs.map(lev[:, np.newaxis])\n\n        # broadcast to (nlev, 4) array\n        if len(colors) == 1:\n            colors = colors * np.ones((len(self._levels), 1))\n\n        # detect color_lev/levels mismatch and raise error\n        if (len(colors) != len(self._levels)):\n            raise TypeError(\"Color/level mismatch. Color must be of shape \"\n                            \"(Nlev, ...) and provide one color per level\")\n\n        self._lc = colors\n\n    def _prepare_draw(self, view):\n        if (self._data is None or self._levels is None or\n                self._color_lev is None or self._data_is_uniform):\n            return False\n\n        if self._need_level_update:\n            self._levels_to_colors()\n            self._need_level_update = False\n\n        if self._need_recompute:\n            self._compute_iso_line()\n            self._compute_iso_color()\n            LineVisual.set_data(self, pos=self._verts, connect=self._connect,\n                                color=self._cl)\n            self._need_recompute = False\n\n        if self._need_color_update:\n            self._compute_iso_color()\n            LineVisual.set_data(self, color=self._cl)\n            self._need_color_update = False\n\n        return LineVisual._prepare_draw(self, view)\n", "path": "vispy/visuals/isocurve.py"}]}