We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
scene.visuals.Graph is not working with directed = True
I am trying to render an directed graph but I am getting the error.

Code (based on [example from gallery](https://vispy.org/gallery/scene/graph.html#sphx-glr-gallery-scene-graph-py), I just set directed=True):
```py
import sys

import networkx as nx

from vispy import app, scene
from vispy.visuals.graphs import layouts


canvas = scene.SceneCanvas(title='Simple NetworkX Graph', size=(600, 600),
                           bgcolor='white', show=True)
view = canvas.central_widget.add_view('panzoom')

graph = nx.adjacency_matrix(
    nx.fast_gnp_random_graph(500, 0.005, directed=True)
)
layout = layouts.get_layout('force_directed', iterations=100)

visual = scene.visuals.Graph(
    graph, layout=layout, line_color='black', arrow_type="stealth",
    arrow_size=30, node_symbol="disc", node_size=20,
    face_color=(1, 0, 0, 0.2), border_width=0.0, animate=True, directed=True,
    parent=view.scene)


@canvas.events.draw.connect
def on_draw(event):
    if not visual.animate_layout():
        canvas.update()

if __name__ == '__main__':
    if sys.flags.interactive != 1:
        app.run()
```

Error:
```
<< caught exception here: >>
  File "C:\Users\maxim\AppData\Local\Programs\Python\Python39\lib\site-packages\vispy\util\event.py", line 469, in _invoke_callback
    cb(event)
  File "D:\dev\university\UniversityProjects\3\alg_and_struct\2\demo.py", line 27, in on_draw
    if not visual.animate_layout():
  File "C:\Users\maxim\AppData\Local\Programs\Python\Python39\lib\site-packages\vispy\visuals\graphs\graph.py", line 143, in animate_layout
    node_vertices, line_vertices, arrows = next(self._layout_iter)
  File "C:\Users\maxim\AppData\Local\Programs\Python\Python39\lib\site-packages\vispy\visuals\graphs\layouts\force_directed.py", line 95, in __call__
    for result in solver(adjacency_mat, directed):
  File "C:\Users\maxim\AppData\Local\Programs\Python\Python39\lib\site-packages\vispy\visuals\graphs\layouts\force_directed.py", line 162, in _sparse_fruchterman_reingold
    line_vertices, arrows = _straight_line_vertices(adjacency_coo, pos,
  File "C:\Users\maxim\AppData\Local\Programs\Python\Python39\lib\site-packages\vispy\visuals\graphs\util.py", line 92, in _straight_line_vertices
    arrow_vertices = arrow_vertices.reshape((len(arrow_vertices)/2, 4))
TypeError: 'float' object cannot be interpreted as an integer
ERROR: Invoking <function on_draw at 0x000001EB3573EDC0> for DrawEvent
```

May be typecasting or `//` at [this line](https://github.com/vispy/vispy/blob/feeaf8afa99ddbbac86a03e3e611a52c1c89584d/vispy/visuals/graphs/util.py#L92) is needed.


--- 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/graphs/util.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 Graph utilities
6 ===============
7 
8 A module containing several graph utility functions.
9 """
10 
11 import numpy as np
12 
13 try:
14     from scipy.sparse import issparse
15     from scipy import sparse
16 except ImportError:
17     def issparse(*args, **kwargs):
18         return False
19 
20 
21 def _get_edges(adjacency_mat):
22     func = _sparse_get_edges if issparse(adjacency_mat) else _ndarray_get_edges
23     return func(adjacency_mat)
24 
25 
26 def _sparse_get_edges(adjacency_mat):
27     return np.concatenate((adjacency_mat.row[:, np.newaxis],
28                            adjacency_mat.col[:, np.newaxis]), axis=-1)
29 
30 
31 def _ndarray_get_edges(adjacency_mat):
32     # Get indices of all non zero values
33     i, j = np.where(adjacency_mat)
34 
35     return np.concatenate((i[:, np.newaxis], j[:, np.newaxis]), axis=-1)
36 
37 
38 def _get_directed_edges(adjacency_mat):
39     func = _sparse_get_edges if issparse(adjacency_mat) else _ndarray_get_edges
40 
41     if issparse(adjacency_mat):
42         triu = sparse.triu
43         tril = sparse.tril
44     else:
45         triu = np.triu
46         tril = np.tril
47 
48     upper = triu(adjacency_mat)
49     lower = tril(adjacency_mat)
50 
51     return np.concatenate((func(upper), func(lower)))
52 
53 
54 def _straight_line_vertices(adjacency_mat, node_coords, directed=False):
55     """
56     Generate the vertices for straight lines between nodes.
57 
58     If it is a directed graph, it also generates the vertices which can be
59     passed to an :class:`ArrowVisual`.
60 
61     Parameters
62     ----------
63     adjacency_mat : array
64         The adjacency matrix of the graph
65     node_coords : array
66         The current coordinates of all nodes in the graph
67     directed : bool
68         Wether the graph is directed. If this is true it will also generate
69         the vertices for arrows which can be passed to :class:`ArrowVisual`.
70 
71     Returns
72     -------
73     vertices : tuple
74         Returns a tuple containing containing (`line_vertices`,
75         `arrow_vertices`)
76     """
77     if not issparse(adjacency_mat):
78         adjacency_mat = np.asarray(adjacency_mat, float)
79 
80     if (adjacency_mat.ndim != 2 or adjacency_mat.shape[0] !=
81             adjacency_mat.shape[1]):
82         raise ValueError("Adjacency matrix should be square.")
83 
84     arrow_vertices = np.array([])
85 
86     edges = _get_edges(adjacency_mat)
87     line_vertices = node_coords[edges.ravel()]
88 
89     if directed:
90         arrows = np.array(list(_get_directed_edges(adjacency_mat)))
91         arrow_vertices = node_coords[arrows.ravel()]
92         arrow_vertices = arrow_vertices.reshape((len(arrow_vertices)/2, 4))
93 
94     return line_vertices, arrow_vertices
95 
96 
97 def _rescale_layout(pos, scale=1):
98     """
99     Normalize the given coordinate list to the range [0, `scale`].
100 
101     Parameters
102     ----------
103     pos : array
104         Coordinate list
105     scale : number
106         The upperbound value for the coordinates range
107 
108     Returns
109     -------
110     pos : array
111         The rescaled (normalized) coordinates in the range [0, `scale`].
112 
113     Notes
114     -----
115     Changes `pos` in place.
116     """
117     pos -= pos.min(axis=0)
118     pos *= scale / pos.max()
119 
120     return pos
121
```
--- 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/graphs/util.py b/vispy/visuals/graphs/util.py
--- a/vispy/visuals/graphs/util.py
+++ b/vispy/visuals/graphs/util.py
@@ -89,7 +89,7 @@
     if directed:
         arrows = np.array(list(_get_directed_edges(adjacency_mat)))
         arrow_vertices = node_coords[arrows.ravel()]
-        arrow_vertices = arrow_vertices.reshape((len(arrow_vertices)/2, 4))
+        arrow_vertices = arrow_vertices.reshape((len(arrow_vertices)//2, 4))
 
     return line_vertices, arrow_vertices

{"golden_diff": "diff --git a/vispy/visuals/graphs/util.py b/vispy/visuals/graphs/util.py\n--- a/vispy/visuals/graphs/util.py\n+++ b/vispy/visuals/graphs/util.py\n@@ -89,7 +89,7 @@\n     if directed:\n         arrows = np.array(list(_get_directed_edges(adjacency_mat)))\n         arrow_vertices = node_coords[arrows.ravel()]\n-        arrow_vertices = arrow_vertices.reshape((len(arrow_vertices)/2, 4))\n+        arrow_vertices = arrow_vertices.reshape((len(arrow_vertices)//2, 4))\n \n     return line_vertices, arrow_vertices\n", "issue": "scene.visuals.Graph is not working with directed = True\nI am trying to render an directed graph but I am getting the error.\r\n\r\nCode (based on [example from gallery](https://vispy.org/gallery/scene/graph.html#sphx-glr-gallery-scene-graph-py), I just set directed=True):\r\n```py\r\nimport sys\r\n\r\nimport networkx as nx\r\n\r\nfrom vispy import app, scene\r\nfrom vispy.visuals.graphs import layouts\r\n\r\n\r\ncanvas = scene.SceneCanvas(title='Simple NetworkX Graph', size=(600, 600),\r\n                           bgcolor='white', show=True)\r\nview = canvas.central_widget.add_view('panzoom')\r\n\r\ngraph = nx.adjacency_matrix(\r\n    nx.fast_gnp_random_graph(500, 0.005, directed=True)\r\n)\r\nlayout = layouts.get_layout('force_directed', iterations=100)\r\n\r\nvisual = scene.visuals.Graph(\r\n    graph, layout=layout, line_color='black', arrow_type=\"stealth\",\r\n    arrow_size=30, node_symbol=\"disc\", node_size=20,\r\n    face_color=(1, 0, 0, 0.2), border_width=0.0, animate=True, directed=True,\r\n    parent=view.scene)\r\n\r\n\r\n@canvas.events.draw.connect\r\ndef on_draw(event):\r\n    if not visual.animate_layout():\r\n        canvas.update()\r\n\r\nif __name__ == '__main__':\r\n    if sys.flags.interactive != 1:\r\n        app.run()\r\n```\r\n\r\nError:\r\n```\r\n<< caught exception here: >>\r\n  File \"C:\\Users\\maxim\\AppData\\Local\\Programs\\Python\\Python39\\lib\\site-packages\\vispy\\util\\event.py\", line 469, in _invoke_callback\r\n    cb(event)\r\n  File \"D:\\dev\\university\\UniversityProjects\\3\\alg_and_struct\\2\\demo.py\", line 27, in on_draw\r\n    if not visual.animate_layout():\r\n  File \"C:\\Users\\maxim\\AppData\\Local\\Programs\\Python\\Python39\\lib\\site-packages\\vispy\\visuals\\graphs\\graph.py\", line 143, in animate_layout\r\n    node_vertices, line_vertices, arrows = next(self._layout_iter)\r\n  File \"C:\\Users\\maxim\\AppData\\Local\\Programs\\Python\\Python39\\lib\\site-packages\\vispy\\visuals\\graphs\\layouts\\force_directed.py\", line 95, in __call__\r\n    for result in solver(adjacency_mat, directed):\r\n  File \"C:\\Users\\maxim\\AppData\\Local\\Programs\\Python\\Python39\\lib\\site-packages\\vispy\\visuals\\graphs\\layouts\\force_directed.py\", line 162, in _sparse_fruchterman_reingold\r\n    line_vertices, arrows = _straight_line_vertices(adjacency_coo, pos,\r\n  File \"C:\\Users\\maxim\\AppData\\Local\\Programs\\Python\\Python39\\lib\\site-packages\\vispy\\visuals\\graphs\\util.py\", line 92, in _straight_line_vertices\r\n    arrow_vertices = arrow_vertices.reshape((len(arrow_vertices)/2, 4))\r\nTypeError: 'float' object cannot be interpreted as an integer\r\nERROR: Invoking <function on_draw at 0x000001EB3573EDC0> for DrawEvent\r\n```\r\n\r\nMay be typecasting or `//` at [this line](https://github.com/vispy/vispy/blob/feeaf8afa99ddbbac86a03e3e611a52c1c89584d/vispy/visuals/graphs/util.py#L92) is needed.\r\n\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\"\"\"\nGraph utilities\n===============\n\nA module containing several graph utility functions.\n\"\"\"\n\nimport numpy as np\n\ntry:\n    from scipy.sparse import issparse\n    from scipy import sparse\nexcept ImportError:\n    def issparse(*args, **kwargs):\n        return False\n\n\ndef _get_edges(adjacency_mat):\n    func = _sparse_get_edges if issparse(adjacency_mat) else _ndarray_get_edges\n    return func(adjacency_mat)\n\n\ndef _sparse_get_edges(adjacency_mat):\n    return np.concatenate((adjacency_mat.row[:, np.newaxis],\n                           adjacency_mat.col[:, np.newaxis]), axis=-1)\n\n\ndef _ndarray_get_edges(adjacency_mat):\n    # Get indices of all non zero values\n    i, j = np.where(adjacency_mat)\n\n    return np.concatenate((i[:, np.newaxis], j[:, np.newaxis]), axis=-1)\n\n\ndef _get_directed_edges(adjacency_mat):\n    func = _sparse_get_edges if issparse(adjacency_mat) else _ndarray_get_edges\n\n    if issparse(adjacency_mat):\n        triu = sparse.triu\n        tril = sparse.tril\n    else:\n        triu = np.triu\n        tril = np.tril\n\n    upper = triu(adjacency_mat)\n    lower = tril(adjacency_mat)\n\n    return np.concatenate((func(upper), func(lower)))\n\n\ndef _straight_line_vertices(adjacency_mat, node_coords, directed=False):\n    \"\"\"\n    Generate the vertices for straight lines between nodes.\n\n    If it is a directed graph, it also generates the vertices which can be\n    passed to an :class:`ArrowVisual`.\n\n    Parameters\n    ----------\n    adjacency_mat : array\n        The adjacency matrix of the graph\n    node_coords : array\n        The current coordinates of all nodes in the graph\n    directed : bool\n        Wether the graph is directed. If this is true it will also generate\n        the vertices for arrows which can be passed to :class:`ArrowVisual`.\n\n    Returns\n    -------\n    vertices : tuple\n        Returns a tuple containing containing (`line_vertices`,\n        `arrow_vertices`)\n    \"\"\"\n    if not issparse(adjacency_mat):\n        adjacency_mat = np.asarray(adjacency_mat, float)\n\n    if (adjacency_mat.ndim != 2 or adjacency_mat.shape[0] !=\n            adjacency_mat.shape[1]):\n        raise ValueError(\"Adjacency matrix should be square.\")\n\n    arrow_vertices = np.array([])\n\n    edges = _get_edges(adjacency_mat)\n    line_vertices = node_coords[edges.ravel()]\n\n    if directed:\n        arrows = np.array(list(_get_directed_edges(adjacency_mat)))\n        arrow_vertices = node_coords[arrows.ravel()]\n        arrow_vertices = arrow_vertices.reshape((len(arrow_vertices)/2, 4))\n\n    return line_vertices, arrow_vertices\n\n\ndef _rescale_layout(pos, scale=1):\n    \"\"\"\n    Normalize the given coordinate list to the range [0, `scale`].\n\n    Parameters\n    ----------\n    pos : array\n        Coordinate list\n    scale : number\n        The upperbound value for the coordinates range\n\n    Returns\n    -------\n    pos : array\n        The rescaled (normalized) coordinates in the range [0, `scale`].\n\n    Notes\n    -----\n    Changes `pos` in place.\n    \"\"\"\n    pos -= pos.min(axis=0)\n    pos *= scale / pos.max()\n\n    return pos\n", "path": "vispy/visuals/graphs/util.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\"\"\"\nGraph utilities\n===============\n\nA module containing several graph utility functions.\n\"\"\"\n\nimport numpy as np\n\ntry:\n    from scipy.sparse import issparse\n    from scipy import sparse\nexcept ImportError:\n    def issparse(*args, **kwargs):\n        return False\n\n\ndef _get_edges(adjacency_mat):\n    func = _sparse_get_edges if issparse(adjacency_mat) else _ndarray_get_edges\n    return func(adjacency_mat)\n\n\ndef _sparse_get_edges(adjacency_mat):\n    return np.concatenate((adjacency_mat.row[:, np.newaxis],\n                           adjacency_mat.col[:, np.newaxis]), axis=-1)\n\n\ndef _ndarray_get_edges(adjacency_mat):\n    # Get indices of all non zero values\n    i, j = np.where(adjacency_mat)\n\n    return np.concatenate((i[:, np.newaxis], j[:, np.newaxis]), axis=-1)\n\n\ndef _get_directed_edges(adjacency_mat):\n    func = _sparse_get_edges if issparse(adjacency_mat) else _ndarray_get_edges\n\n    if issparse(adjacency_mat):\n        triu = sparse.triu\n        tril = sparse.tril\n    else:\n        triu = np.triu\n        tril = np.tril\n\n    upper = triu(adjacency_mat)\n    lower = tril(adjacency_mat)\n\n    return np.concatenate((func(upper), func(lower)))\n\n\ndef _straight_line_vertices(adjacency_mat, node_coords, directed=False):\n    \"\"\"\n    Generate the vertices for straight lines between nodes.\n\n    If it is a directed graph, it also generates the vertices which can be\n    passed to an :class:`ArrowVisual`.\n\n    Parameters\n    ----------\n    adjacency_mat : array\n        The adjacency matrix of the graph\n    node_coords : array\n        The current coordinates of all nodes in the graph\n    directed : bool\n        Wether the graph is directed. If this is true it will also generate\n        the vertices for arrows which can be passed to :class:`ArrowVisual`.\n\n    Returns\n    -------\n    vertices : tuple\n        Returns a tuple containing containing (`line_vertices`,\n        `arrow_vertices`)\n    \"\"\"\n    if not issparse(adjacency_mat):\n        adjacency_mat = np.asarray(adjacency_mat, float)\n\n    if (adjacency_mat.ndim != 2 or adjacency_mat.shape[0] !=\n            adjacency_mat.shape[1]):\n        raise ValueError(\"Adjacency matrix should be square.\")\n\n    arrow_vertices = np.array([])\n\n    edges = _get_edges(adjacency_mat)\n    line_vertices = node_coords[edges.ravel()]\n\n    if directed:\n        arrows = np.array(list(_get_directed_edges(adjacency_mat)))\n        arrow_vertices = node_coords[arrows.ravel()]\n        arrow_vertices = arrow_vertices.reshape((len(arrow_vertices)//2, 4))\n\n    return line_vertices, arrow_vertices\n\n\ndef _rescale_layout(pos, scale=1):\n    \"\"\"\n    Normalize the given coordinate list to the range [0, `scale`].\n\n    Parameters\n    ----------\n    pos : array\n        Coordinate list\n    scale : number\n        The upperbound value for the coordinates range\n\n    Returns\n    -------\n    pos : array\n        The rescaled (normalized) coordinates in the range [0, `scale`].\n\n    Notes\n    -----\n    Changes `pos` in place.\n    \"\"\"\n    pos -= pos.min(axis=0)\n    pos *= scale / pos.max()\n\n    return pos\n", "path": "vispy/visuals/graphs/util.py"}]}