We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
vispy.plot.image fails on float64 textures


--- 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/image.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright (c) 2014, Vispy Development Team.
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 .. import gloo
10 from .transforms import STTransform, NullTransform
11 from .modular_mesh import ModularMesh
12 from .components import (TextureComponent, VertexTextureCoordinateComponent,
13                          TextureCoordinateComponent)
14 
15 
16 class ImageVisual(ModularMesh):
17     """Visual subclass displaying an image.
18 
19     Parameters
20     ----------
21     data : (height, width, 4) ubyte array
22         ImageVisual data.
23     method : str
24         Selects method of rendering image in case of non-linear transforms.
25         Each method produces similar results, but may trade efficiency
26         and accuracy. If the transform is linear, this parameter is ignored
27         and a single quad is drawn around the area of the image.
28 
29             * 'subdivide': ImageVisual is represented as a grid of triangles
30               with texture coordinates linearly mapped.
31             * 'impostor': ImageVisual is represented as a quad covering the 
32               entire view, with texture coordinates determined by the 
33               transform. This produces the best transformation results, but may
34               be slow.
35 
36     grid: tuple (rows, cols)
37         If method='subdivide', this tuple determines the number of rows and
38         columns in the image grid.
39     """
40     def __init__(self, data, method='subdivide', grid=(10, 10), **kwargs):
41         super(ImageVisual, self).__init__(**kwargs)
42 
43         self._data = None
44 
45         # maps from quad coordinates to texture coordinates
46         self._tex_transform = STTransform()
47 
48         self._texture = None
49         self._interpolation = 'nearest'
50         self.set_data(data)
51         self.set_gl_options(cull_face=('front_and_back',))
52 
53         self.method = method
54         self.grid = grid
55 
56     def set_data(self, image=None, **kwds):
57         if image is not None:
58             self._data = image
59             self._texture = None
60         super(ImageVisual, self).set_data(**kwds)
61 
62     @property
63     def interpolation(self):
64         return self._interpolation
65 
66     @interpolation.setter
67     def interpolation(self, interp):
68         self._interpolation = interp
69         self.update()
70 
71     @property
72     def size(self):
73         return self._data.shape[:2][::-1]
74 
75     def _build_data(self, transforms):
76         # Construct complete data array with position and optionally color
77         if transforms.get_full_transform().Linear:
78             method = 'subdivide'
79             grid = (1, 1)
80         else:
81             method = self.method
82             grid = self.grid
83 
84         # TODO: subdivision and impostor modes should be handled by new
85         # components?
86         if method == 'subdivide':
87             # quads cover area of image as closely as possible
88             w = 1.0 / grid[1]
89             h = 1.0 / grid[0]
90 
91             quad = np.array([[0, 0, 0], [w, 0, 0], [w, h, 0],
92                              [0, 0, 0], [w, h, 0], [0, h, 0]],
93                             dtype=np.float32)
94             quads = np.empty((grid[1], grid[0], 6, 3), dtype=np.float32)
95             quads[:] = quad
96 
97             mgrid = np.mgrid[0.:grid[1], 0.:grid[0]].transpose(1, 2, 0)
98             mgrid = mgrid[:, :, np.newaxis, :]
99             mgrid[..., 0] *= w
100             mgrid[..., 1] *= h
101 
102             quads[..., :2] += mgrid
103             tex_coords = quads.reshape(grid[1]*grid[0]*6, 3)
104             vertices = tex_coords.copy()
105             vertices[..., 0] *= self._data.shape[1]
106             vertices[..., 1] *= self._data.shape[0]
107             ModularMesh.set_data(self, pos=vertices)
108             coords = np.ascontiguousarray(tex_coords[:, :2])
109             tex_coord_comp = TextureCoordinateComponent(coords)
110         elif method == 'impostor':
111             # quad covers entire view; frag. shader will deal with image shape
112             quad = np.array([[-1, -1, 0], [1, -1, 0], [1, 1, 0],
113                              [-1, -1, 0], [1, 1, 0], [-1, 1, 0]],
114                             dtype=np.float32)
115             ModularMesh.set_data(self, pos=quad)
116 
117             self._tex_transform.scale = (1./self._data.shape[0],
118                                          1./self._data.shape[1])
119             ctr = transforms.get_full_transform().inverse
120             total_transform = self._tex_transform * ctr
121             tex_coord_comp = VertexTextureCoordinateComponent(total_transform)
122             tr = NullTransform()
123             self._program.vert['map_local_to_nd'] = tr
124         else:
125             raise ValueError("Unknown image draw method '%s'" % method)
126 
127         data = self._data
128         self._texture = gloo.Texture2D(data)
129         self._texture.interpolation = self._interpolation
130 
131         self.color_components = [TextureComponent(self._texture,
132                                                   tex_coord_comp)]
133 
134     def _activate_transform(self, transforms=None):
135         # this is handled in _build_data instead.
136         pass
137 
138     def bounds(self, mode, axis):
139         if axis > 1:
140             return (0, 0)
141         else:
142             return (0, self.size[axis])
143 
144     def draw(self, transforms):
145         if self._data is None:
146             return
147 
148         if transforms.get_full_transform().Linear:
149             method = 'subdivide'
150         else:
151             method = self.method
152 
153         # always have to rebuild for impostor, only first for subdivide
154         if self._texture is None:
155             self._build_data(transforms)
156         if method == 'subdivide':
157             tr = transforms.get_full_transform()
158             self._program.vert['map_local_to_nd'] = tr
159 
160         super(ImageVisual, self).draw(transforms)
161
```
--- 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/image.py b/vispy/visuals/image.py
--- a/vispy/visuals/image.py
+++ b/vispy/visuals/image.py
@@ -28,8 +28,8 @@
 
             * 'subdivide': ImageVisual is represented as a grid of triangles
               with texture coordinates linearly mapped.
-            * 'impostor': ImageVisual is represented as a quad covering the 
-              entire view, with texture coordinates determined by the 
+            * 'impostor': ImageVisual is represented as a quad covering the
+              entire view, with texture coordinates determined by the
               transform. This produces the best transformation results, but may
               be slow.
 
@@ -55,6 +55,9 @@
 
     def set_data(self, image=None, **kwds):
         if image is not None:
+            image = np.array(image, copy=False)
+            if image.dtype == np.float64:
+                image = image.astype(np.float32)
             self._data = image
             self._texture = None
         super(ImageVisual, self).set_data(**kwds)

{"golden_diff": "diff --git a/vispy/visuals/image.py b/vispy/visuals/image.py\n--- a/vispy/visuals/image.py\n+++ b/vispy/visuals/image.py\n@@ -28,8 +28,8 @@\n \n             * 'subdivide': ImageVisual is represented as a grid of triangles\n               with texture coordinates linearly mapped.\n-            * 'impostor': ImageVisual is represented as a quad covering the \n-              entire view, with texture coordinates determined by the \n+            * 'impostor': ImageVisual is represented as a quad covering the\n+              entire view, with texture coordinates determined by the\n               transform. This produces the best transformation results, but may\n               be slow.\n \n@@ -55,6 +55,9 @@\n \n     def set_data(self, image=None, **kwds):\n         if image is not None:\n+            image = np.array(image, copy=False)\n+            if image.dtype == np.float64:\n+                image = image.astype(np.float32)\n             self._data = image\n             self._texture = None\n         super(ImageVisual, self).set_data(**kwds)\n", "issue": "vispy.plot.image fails on float64 textures\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) 2014, Vispy Development Team.\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 .. import gloo\nfrom .transforms import STTransform, NullTransform\nfrom .modular_mesh import ModularMesh\nfrom .components import (TextureComponent, VertexTextureCoordinateComponent,\n                         TextureCoordinateComponent)\n\n\nclass ImageVisual(ModularMesh):\n    \"\"\"Visual subclass displaying an image.\n\n    Parameters\n    ----------\n    data : (height, width, 4) ubyte array\n        ImageVisual data.\n    method : str\n        Selects method of rendering image in case of non-linear transforms.\n        Each method produces similar results, but may trade efficiency\n        and accuracy. If the transform is linear, this parameter is ignored\n        and a single quad is drawn around the area of the image.\n\n            * 'subdivide': ImageVisual is represented as a grid of triangles\n              with texture coordinates linearly mapped.\n            * 'impostor': ImageVisual is represented as a quad covering the \n              entire view, with texture coordinates determined by the \n              transform. This produces the best transformation results, but may\n              be slow.\n\n    grid: tuple (rows, cols)\n        If method='subdivide', this tuple determines the number of rows and\n        columns in the image grid.\n    \"\"\"\n    def __init__(self, data, method='subdivide', grid=(10, 10), **kwargs):\n        super(ImageVisual, self).__init__(**kwargs)\n\n        self._data = None\n\n        # maps from quad coordinates to texture coordinates\n        self._tex_transform = STTransform()\n\n        self._texture = None\n        self._interpolation = 'nearest'\n        self.set_data(data)\n        self.set_gl_options(cull_face=('front_and_back',))\n\n        self.method = method\n        self.grid = grid\n\n    def set_data(self, image=None, **kwds):\n        if image is not None:\n            self._data = image\n            self._texture = None\n        super(ImageVisual, self).set_data(**kwds)\n\n    @property\n    def interpolation(self):\n        return self._interpolation\n\n    @interpolation.setter\n    def interpolation(self, interp):\n        self._interpolation = interp\n        self.update()\n\n    @property\n    def size(self):\n        return self._data.shape[:2][::-1]\n\n    def _build_data(self, transforms):\n        # Construct complete data array with position and optionally color\n        if transforms.get_full_transform().Linear:\n            method = 'subdivide'\n            grid = (1, 1)\n        else:\n            method = self.method\n            grid = self.grid\n\n        # TODO: subdivision and impostor modes should be handled by new\n        # components?\n        if method == 'subdivide':\n            # quads cover area of image as closely as possible\n            w = 1.0 / grid[1]\n            h = 1.0 / grid[0]\n\n            quad = np.array([[0, 0, 0], [w, 0, 0], [w, h, 0],\n                             [0, 0, 0], [w, h, 0], [0, h, 0]],\n                            dtype=np.float32)\n            quads = np.empty((grid[1], grid[0], 6, 3), dtype=np.float32)\n            quads[:] = quad\n\n            mgrid = np.mgrid[0.:grid[1], 0.:grid[0]].transpose(1, 2, 0)\n            mgrid = mgrid[:, :, np.newaxis, :]\n            mgrid[..., 0] *= w\n            mgrid[..., 1] *= h\n\n            quads[..., :2] += mgrid\n            tex_coords = quads.reshape(grid[1]*grid[0]*6, 3)\n            vertices = tex_coords.copy()\n            vertices[..., 0] *= self._data.shape[1]\n            vertices[..., 1] *= self._data.shape[0]\n            ModularMesh.set_data(self, pos=vertices)\n            coords = np.ascontiguousarray(tex_coords[:, :2])\n            tex_coord_comp = TextureCoordinateComponent(coords)\n        elif method == 'impostor':\n            # quad covers entire view; frag. shader will deal with image shape\n            quad = np.array([[-1, -1, 0], [1, -1, 0], [1, 1, 0],\n                             [-1, -1, 0], [1, 1, 0], [-1, 1, 0]],\n                            dtype=np.float32)\n            ModularMesh.set_data(self, pos=quad)\n\n            self._tex_transform.scale = (1./self._data.shape[0],\n                                         1./self._data.shape[1])\n            ctr = transforms.get_full_transform().inverse\n            total_transform = self._tex_transform * ctr\n            tex_coord_comp = VertexTextureCoordinateComponent(total_transform)\n            tr = NullTransform()\n            self._program.vert['map_local_to_nd'] = tr\n        else:\n            raise ValueError(\"Unknown image draw method '%s'\" % method)\n\n        data = self._data\n        self._texture = gloo.Texture2D(data)\n        self._texture.interpolation = self._interpolation\n\n        self.color_components = [TextureComponent(self._texture,\n                                                  tex_coord_comp)]\n\n    def _activate_transform(self, transforms=None):\n        # this is handled in _build_data instead.\n        pass\n\n    def bounds(self, mode, axis):\n        if axis > 1:\n            return (0, 0)\n        else:\n            return (0, self.size[axis])\n\n    def draw(self, transforms):\n        if self._data is None:\n            return\n\n        if transforms.get_full_transform().Linear:\n            method = 'subdivide'\n        else:\n            method = self.method\n\n        # always have to rebuild for impostor, only first for subdivide\n        if self._texture is None:\n            self._build_data(transforms)\n        if method == 'subdivide':\n            tr = transforms.get_full_transform()\n            self._program.vert['map_local_to_nd'] = tr\n\n        super(ImageVisual, self).draw(transforms)\n", "path": "vispy/visuals/image.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) 2014, Vispy Development Team.\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 .. import gloo\nfrom .transforms import STTransform, NullTransform\nfrom .modular_mesh import ModularMesh\nfrom .components import (TextureComponent, VertexTextureCoordinateComponent,\n                         TextureCoordinateComponent)\n\n\nclass ImageVisual(ModularMesh):\n    \"\"\"Visual subclass displaying an image.\n\n    Parameters\n    ----------\n    data : (height, width, 4) ubyte array\n        ImageVisual data.\n    method : str\n        Selects method of rendering image in case of non-linear transforms.\n        Each method produces similar results, but may trade efficiency\n        and accuracy. If the transform is linear, this parameter is ignored\n        and a single quad is drawn around the area of the image.\n\n            * 'subdivide': ImageVisual is represented as a grid of triangles\n              with texture coordinates linearly mapped.\n            * 'impostor': ImageVisual is represented as a quad covering the\n              entire view, with texture coordinates determined by the\n              transform. This produces the best transformation results, but may\n              be slow.\n\n    grid: tuple (rows, cols)\n        If method='subdivide', this tuple determines the number of rows and\n        columns in the image grid.\n    \"\"\"\n    def __init__(self, data, method='subdivide', grid=(10, 10), **kwargs):\n        super(ImageVisual, self).__init__(**kwargs)\n\n        self._data = None\n\n        # maps from quad coordinates to texture coordinates\n        self._tex_transform = STTransform()\n\n        self._texture = None\n        self._interpolation = 'nearest'\n        self.set_data(data)\n        self.set_gl_options(cull_face=('front_and_back',))\n\n        self.method = method\n        self.grid = grid\n\n    def set_data(self, image=None, **kwds):\n        if image is not None:\n            image = np.array(image, copy=False)\n            if image.dtype == np.float64:\n                image = image.astype(np.float32)\n            self._data = image\n            self._texture = None\n        super(ImageVisual, self).set_data(**kwds)\n\n    @property\n    def interpolation(self):\n        return self._interpolation\n\n    @interpolation.setter\n    def interpolation(self, interp):\n        self._interpolation = interp\n        self.update()\n\n    @property\n    def size(self):\n        return self._data.shape[:2][::-1]\n\n    def _build_data(self, transforms):\n        # Construct complete data array with position and optionally color\n        if transforms.get_full_transform().Linear:\n            method = 'subdivide'\n            grid = (1, 1)\n        else:\n            method = self.method\n            grid = self.grid\n\n        # TODO: subdivision and impostor modes should be handled by new\n        # components?\n        if method == 'subdivide':\n            # quads cover area of image as closely as possible\n            w = 1.0 / grid[1]\n            h = 1.0 / grid[0]\n\n            quad = np.array([[0, 0, 0], [w, 0, 0], [w, h, 0],\n                             [0, 0, 0], [w, h, 0], [0, h, 0]],\n                            dtype=np.float32)\n            quads = np.empty((grid[1], grid[0], 6, 3), dtype=np.float32)\n            quads[:] = quad\n\n            mgrid = np.mgrid[0.:grid[1], 0.:grid[0]].transpose(1, 2, 0)\n            mgrid = mgrid[:, :, np.newaxis, :]\n            mgrid[..., 0] *= w\n            mgrid[..., 1] *= h\n\n            quads[..., :2] += mgrid\n            tex_coords = quads.reshape(grid[1]*grid[0]*6, 3)\n            vertices = tex_coords.copy()\n            vertices[..., 0] *= self._data.shape[1]\n            vertices[..., 1] *= self._data.shape[0]\n            ModularMesh.set_data(self, pos=vertices)\n            coords = np.ascontiguousarray(tex_coords[:, :2])\n            tex_coord_comp = TextureCoordinateComponent(coords)\n        elif method == 'impostor':\n            # quad covers entire view; frag. shader will deal with image shape\n            quad = np.array([[-1, -1, 0], [1, -1, 0], [1, 1, 0],\n                             [-1, -1, 0], [1, 1, 0], [-1, 1, 0]],\n                            dtype=np.float32)\n            ModularMesh.set_data(self, pos=quad)\n\n            self._tex_transform.scale = (1./self._data.shape[0],\n                                         1./self._data.shape[1])\n            ctr = transforms.get_full_transform().inverse\n            total_transform = self._tex_transform * ctr\n            tex_coord_comp = VertexTextureCoordinateComponent(total_transform)\n            tr = NullTransform()\n            self._program.vert['map_local_to_nd'] = tr\n        else:\n            raise ValueError(\"Unknown image draw method '%s'\" % method)\n\n        data = self._data\n        self._texture = gloo.Texture2D(data)\n        self._texture.interpolation = self._interpolation\n\n        self.color_components = [TextureComponent(self._texture,\n                                                  tex_coord_comp)]\n\n    def _activate_transform(self, transforms=None):\n        # this is handled in _build_data instead.\n        pass\n\n    def bounds(self, mode, axis):\n        if axis > 1:\n            return (0, 0)\n        else:\n            return (0, self.size[axis])\n\n    def draw(self, transforms):\n        if self._data is None:\n            return\n\n        if transforms.get_full_transform().Linear:\n            method = 'subdivide'\n        else:\n            method = self.method\n\n        # always have to rebuild for impostor, only first for subdivide\n        if self._texture is None:\n            self._build_data(transforms)\n        if method == 'subdivide':\n            tr = transforms.get_full_transform()\n            self._program.vert['map_local_to_nd'] = tr\n\n        super(ImageVisual, self).draw(transforms)\n", "path": "vispy/visuals/image.py"}]}