We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Track vertex shader does not handle blending/opacity correctly
## 🐛 Bug

Two somewhat related bugs in `_vispy_tracks_shader.py` in the `Tracks` layer:
1. The opacity slider only changes the vispy node opacity, which has no effect on the vertex shader used for rendering the tracks or graph.
2. The translucent mode renders parts of the track, which should not be rendered, as dark lines:

![bug](https://user-images.githubusercontent.com/8217795/96697072-64ef9b00-1383-11eb-9648-54c92319ae84.gif)

## To Reproduce

Steps to reproduce the behavior:

1. run `examples\tracks_3d.py`
2. Change the blending mode to translucent in the `Tracks` layer
3. Change the opacity slider 

## Expected behavior

`opacity` should change the track opacity, and the `translucent` blending should not render parts of the track which should not be visible.

## Environment

napari: 0.3.9.dev32+g911e095.d20201007
Platform: Linux-4.15.0-1100-oem-x86_64-with-debian-buster-sid
Python: 3.7.7 (default, May 7 2020, 21:25:33) [GCC 7.3.0]
Qt: 5.14.2
PySide2: 5.14.2.2
NumPy: 1.19.1
SciPy: 1.4.1
Dask: 2.17.2
VisPy: 0.6.4

GL version: 4.6.0 NVIDIA 450.80.02
MAX_TEXTURE_SIZE: 32768

Plugins:
- napari-plugin-engine: 0.1.5
- svg: 0.1.3

## Additional context
This relates to the fact that the shader manipulates the alpha values of the vertices directly, late in the rendering pipeline.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `napari/_vispy/vispy_tracks_layer.py`
Content:
```
1 from vispy.scene.visuals import Compound, Line, Text
2 
3 from ._vispy_tracks_shader import TrackShader
4 from .vispy_base_layer import VispyBaseLayer
5 
6 
7 class VispyTracksLayer(VispyBaseLayer):
8     """VispyTracksLayer
9 
10     Track layer for visualizing tracks.
11 
12     Components:
13         - Track lines (vispy.LineVisual)
14         - Track IDs (vispy.TextVisual)
15         - Graph edges (vispy.LineVisual)
16 
17     """
18 
19     def __init__(self, layer):
20         node = Compound([Line(), Text(), Line()])
21         super().__init__(layer, node)
22 
23         self.layer.events.tail_width.connect(self._on_appearance_change)
24         self.layer.events.tail_length.connect(self._on_appearance_change)
25         self.layer.events.display_id.connect(self._on_appearance_change)
26         self.layer.events.display_tail.connect(self._on_appearance_change)
27         self.layer.events.display_graph.connect(self._on_appearance_change)
28 
29         self.layer.events.color_by.connect(self._on_appearance_change)
30         self.layer.events.colormap.connect(self._on_appearance_change)
31 
32         # these events are fired when changes occur to the tracks or the
33         # graph - as the vertex buffer of the shader needs to be updated
34         # alongside the actual vertex data
35         self.layer.events.rebuild_tracks.connect(self._on_tracks_change)
36         self.layer.events.rebuild_graph.connect(self._on_graph_change)
37 
38         # build and attach the shader to the track
39         self.track_shader = TrackShader()
40         self.graph_shader = TrackShader()
41         node._subvisuals[0].attach(self.track_shader)
42         node._subvisuals[2].attach(self.graph_shader)
43 
44         # text label properties
45         self.node._subvisuals[1].color = 'white'
46         self.node._subvisuals[1].font_size = 8
47 
48         self._reset_base()
49 
50         self._on_data_change()
51         self._on_appearance_change()
52 
53     def _on_data_change(self, event=None):
54         """ update the display """
55 
56         # update the shaders
57         self.track_shader.current_time = self.layer.current_time
58         self.graph_shader.current_time = self.layer.current_time
59 
60         # add text labels if they're visible
61         if self.node._subvisuals[1].visible:
62             labels_text, labels_pos = self.layer.track_labels
63             self.node._subvisuals[1].text = labels_text
64             self.node._subvisuals[1].pos = labels_pos
65 
66         self.node.update()
67         # Call to update order of translation values with new dims:
68         self._on_matrix_change()
69 
70     def _on_appearance_change(self, event=None):
71         """ change the appearance of the data """
72 
73         # update shader properties related to appearance
74         self.track_shader.use_fade = self.layer.use_fade
75         self.track_shader.tail_length = self.layer.tail_length
76         self.graph_shader.use_fade = self.layer.use_fade
77         self.graph_shader.tail_length = self.layer.tail_length
78 
79         # set visibility of subvisuals
80         self.node._subvisuals[0].visible = self.layer.display_tail
81         self.node._subvisuals[1].visible = self.layer.display_id
82         self.node._subvisuals[2].visible = self.layer.display_graph
83 
84         # set the width of the track tails
85         self.node._subvisuals[0].set_data(
86             width=self.layer.tail_width, color=self.layer.track_colors,
87         )
88         self.node._subvisuals[2].set_data(width=self.layer.tail_width,)
89 
90     def _on_tracks_change(self, event=None):
91         """ update the shader when the track data changes """
92 
93         self.track_shader.use_fade = self.layer.use_fade
94         self.track_shader.tail_length = self.layer.tail_length
95         self.track_shader.vertex_time = self.layer.track_times
96 
97         # change the data to the vispy line visual
98         self.node._subvisuals[0].set_data(
99             pos=self.layer._view_data,
100             connect=self.layer.track_connex,
101             width=self.layer.tail_width,
102             color=self.layer.track_colors,
103         )
104 
105         # Call to update order of translation values with new dims:
106         self._on_matrix_change()
107 
108     def _on_graph_change(self, event=None):
109         """ update the shader when the graph data changes """
110 
111         self.graph_shader.use_fade = self.layer.use_fade
112         self.graph_shader.tail_length = self.layer.tail_length
113         self.graph_shader.vertex_time = self.layer.graph_times
114 
115         # if the user clears a graph after it has been created, vispy offers
116         # no method to clear the data, therefore, we need to set private
117         # attributes to None to prevent errors
118         if self.layer._view_graph is None:
119             self.node._subvisuals[2]._pos = None
120             self.node._subvisuals[2]._connect = None
121             self.node.update()
122             return
123 
124         self.node._subvisuals[2].set_data(
125             pos=self.layer._view_graph,
126             connect=self.layer.graph_connex,
127             width=self.layer.tail_width,
128             color='white',
129         )
130 
131         # Call to update order of translation values with new dims:
132         self._on_matrix_change()
133
```

Path: `napari/_vispy/_vispy_tracks_shader.py`
Content:
```
1 from typing import List, Union
2 
3 import numpy as np
4 from vispy.gloo import VertexBuffer
5 from vispy.visuals.filters.base_filter import Filter
6 
7 
8 class TrackShader(Filter):
9     """ TrackShader
10 
11     Custom vertex and fragment shaders for visualizing tracks quickly with
12     vispy. The central assumption is that the tracks are rendered as a
13     continuous vispy Line segment, with connections and colors defined when
14     the visual is created.
15 
16     The shader simply changes the visibility and/or fading of the data according
17     to the current_time and the associate time metadata for each vertex. This
18     is scaled according to the tail length. Points ahead of the current time
19     are rendered with alpha set to zero.
20 
21     Parameters
22     ----------
23     current_time : int, float
24         the current time, which is typically the frame index, although this
25         can be an arbitrary float
26     tail_length : int, float
27         the upper limit on length of the 'tail'
28     use_fade : bool
29         this will enable/disable tail fading with time
30     vertex_time : 1D array, list
31         a vector describing the time associated with each vertex
32 
33 
34     TODO
35     ----
36     - the track is still displayed, albeit with fading, once the track has
37      finished but is still within the 'tail_length' window. Should it
38      disappear?
39     - check the shader positioning within the GL pipeline, currently
40      overrides layer opacity settings
41 
42     vertex_mask: 1D array, list
43         a vector describing whether to mask each vertex
44 
45     """
46 
47     VERT_SHADER = """
48         varying vec4 v_track_color;
49         void apply_track_shading() {
50 
51             float alpha;
52 
53             if ($a_vertex_time > $current_time) {
54                 // this is a hack to minimize the frag shader rendering ahead
55                 // of the current time point due to interpolation
56                 if ($a_vertex_time <= $current_time + 1){
57                     alpha = -100.;
58                 } else {
59                     alpha = 0.;
60                 }
61             } else {
62                 // fade the track into the temporal distance, scaled by the
63                 // maximum tail length from the gui
64                 float fade = ($current_time - $a_vertex_time) / $tail_length;
65                 alpha = clamp(1.0-fade, 0.0, 1.0);
66             }
67 
68             // when use_fade is disabled, the entire track is visible
69             if ($use_fade == 0) {
70                 alpha = 1.0;
71             }
72 
73             // set the vertex alpha according to the fade
74             v_track_color.a = alpha;
75         }
76     """
77 
78     FRAG_SHADER = """
79         varying vec4 v_track_color;
80         void apply_track_shading() {
81             // interpolate
82             gl_FragColor.a = clamp(v_track_color.a, 0.0, 1.0);
83         }
84     """
85 
86     def __init__(
87         self,
88         current_time=0,
89         tail_length=30,
90         use_fade: bool = True,
91         vertex_time: Union[List, np.ndarray] = None,
92     ):
93 
94         super().__init__(
95             vcode=self.VERT_SHADER, vpos=3, fcode=self.FRAG_SHADER, fpos=9
96         )
97 
98         self.current_time = current_time
99         self.tail_length = tail_length
100         self.use_fade = use_fade
101         self.vertex_time = vertex_time
102 
103     @property
104     def current_time(self) -> Union[int, float]:
105         return self._current_time
106 
107     @current_time.setter
108     def current_time(self, n: Union[int, float]):
109         self._current_time = n
110         if isinstance(n, slice):
111             n = np.max(self._vertex_time)
112         self.vshader['current_time'] = float(n)
113 
114     @property
115     def use_fade(self) -> bool:
116         return self._use_fade
117 
118     @use_fade.setter
119     def use_fade(self, value: bool):
120         self._use_fade = value
121         self.vshader['use_fade'] = float(self._use_fade)
122 
123     @property
124     def tail_length(self) -> Union[int, float]:
125         return self._tail_length
126 
127     @tail_length.setter
128     def tail_length(self, tail_length: Union[int, float]):
129         self._tail_length = tail_length
130         self.vshader['tail_length'] = float(self._tail_length)
131 
132     def _attach(self, visual):
133         super()._attach(visual)
134 
135     @property
136     def vertex_time(self):
137         return self._vertex_time
138 
139     @vertex_time.setter
140     def vertex_time(self, v_time):
141         self._vertex_time = np.array(v_time).reshape(-1, 1).astype(np.float32)
142         self.vshader['a_vertex_time'] = VertexBuffer(self.vertex_time)
143
```
--- 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/napari/_vispy/_vispy_tracks_shader.py b/napari/_vispy/_vispy_tracks_shader.py
--- a/napari/_vispy/_vispy_tracks_shader.py
+++ b/napari/_vispy/_vispy_tracks_shader.py
@@ -6,7 +6,7 @@
 
 
 class TrackShader(Filter):
-    """ TrackShader
+    """TrackShader.
 
     Custom vertex and fragment shaders for visualizing tracks quickly with
     vispy. The central assumption is that the tracks are rendered as a
@@ -30,17 +30,11 @@
     vertex_time : 1D array, list
         a vector describing the time associated with each vertex
 
-
     TODO
     ----
     - the track is still displayed, albeit with fading, once the track has
      finished but is still within the 'tail_length' window. Should it
      disappear?
-    - check the shader positioning within the GL pipeline, currently
-     overrides layer opacity settings
-
-    vertex_mask: 1D array, list
-        a vector describing whether to mask each vertex
 
     """
 
@@ -78,15 +72,21 @@
     FRAG_SHADER = """
         varying vec4 v_track_color;
         void apply_track_shading() {
+
+            // if the alpha is below the threshold, discard the fragment
+            if( v_track_color.a <= 0.0 ) {
+                discard;
+            }
+
             // interpolate
-            gl_FragColor.a = clamp(v_track_color.a, 0.0, 1.0);
+            gl_FragColor.a = clamp(v_track_color.a * gl_FragColor.a, 0.0, 1.0);
         }
     """
 
     def __init__(
         self,
-        current_time=0,
-        tail_length=30,
+        current_time: Union[int, float] = 0,
+        tail_length: Union[int, float] = 30,
         use_fade: bool = True,
         vertex_time: Union[List, np.ndarray] = None,
     ):
diff --git a/napari/_vispy/vispy_tracks_layer.py b/napari/_vispy/vispy_tracks_layer.py
--- a/napari/_vispy/vispy_tracks_layer.py
+++ b/napari/_vispy/vispy_tracks_layer.py
@@ -51,7 +51,7 @@
         self._on_appearance_change()
 
     def _on_data_change(self, event=None):
-        """ update the display """
+        """Update the display."""
 
         # update the shaders
         self.track_shader.current_time = self.layer.current_time
@@ -68,7 +68,7 @@
         self._on_matrix_change()
 
     def _on_appearance_change(self, event=None):
-        """ change the appearance of the data """
+        """Change the appearance of the data."""
 
         # update shader properties related to appearance
         self.track_shader.use_fade = self.layer.use_fade
@@ -88,7 +88,7 @@
         self.node._subvisuals[2].set_data(width=self.layer.tail_width,)
 
     def _on_tracks_change(self, event=None):
-        """ update the shader when the track data changes """
+        """Update the shader when the track data changes."""
 
         self.track_shader.use_fade = self.layer.use_fade
         self.track_shader.tail_length = self.layer.tail_length
@@ -106,7 +106,7 @@
         self._on_matrix_change()
 
     def _on_graph_change(self, event=None):
-        """ update the shader when the graph data changes """
+        """Update the shader when the graph data changes."""
 
         self.graph_shader.use_fade = self.layer.use_fade
         self.graph_shader.tail_length = self.layer.tail_length

{"golden_diff": "diff --git a/napari/_vispy/_vispy_tracks_shader.py b/napari/_vispy/_vispy_tracks_shader.py\n--- a/napari/_vispy/_vispy_tracks_shader.py\n+++ b/napari/_vispy/_vispy_tracks_shader.py\n@@ -6,7 +6,7 @@\n \n \n class TrackShader(Filter):\n-    \"\"\" TrackShader\n+    \"\"\"TrackShader.\n \n     Custom vertex and fragment shaders for visualizing tracks quickly with\n     vispy. The central assumption is that the tracks are rendered as a\n@@ -30,17 +30,11 @@\n     vertex_time : 1D array, list\n         a vector describing the time associated with each vertex\n \n-\n     TODO\n     ----\n     - the track is still displayed, albeit with fading, once the track has\n      finished but is still within the 'tail_length' window. Should it\n      disappear?\n-    - check the shader positioning within the GL pipeline, currently\n-     overrides layer opacity settings\n-\n-    vertex_mask: 1D array, list\n-        a vector describing whether to mask each vertex\n \n     \"\"\"\n \n@@ -78,15 +72,21 @@\n     FRAG_SHADER = \"\"\"\n         varying vec4 v_track_color;\n         void apply_track_shading() {\n+\n+            // if the alpha is below the threshold, discard the fragment\n+            if( v_track_color.a <= 0.0 ) {\n+                discard;\n+            }\n+\n             // interpolate\n-            gl_FragColor.a = clamp(v_track_color.a, 0.0, 1.0);\n+            gl_FragColor.a = clamp(v_track_color.a * gl_FragColor.a, 0.0, 1.0);\n         }\n     \"\"\"\n \n     def __init__(\n         self,\n-        current_time=0,\n-        tail_length=30,\n+        current_time: Union[int, float] = 0,\n+        tail_length: Union[int, float] = 30,\n         use_fade: bool = True,\n         vertex_time: Union[List, np.ndarray] = None,\n     ):\ndiff --git a/napari/_vispy/vispy_tracks_layer.py b/napari/_vispy/vispy_tracks_layer.py\n--- a/napari/_vispy/vispy_tracks_layer.py\n+++ b/napari/_vispy/vispy_tracks_layer.py\n@@ -51,7 +51,7 @@\n         self._on_appearance_change()\n \n     def _on_data_change(self, event=None):\n-        \"\"\" update the display \"\"\"\n+        \"\"\"Update the display.\"\"\"\n \n         # update the shaders\n         self.track_shader.current_time = self.layer.current_time\n@@ -68,7 +68,7 @@\n         self._on_matrix_change()\n \n     def _on_appearance_change(self, event=None):\n-        \"\"\" change the appearance of the data \"\"\"\n+        \"\"\"Change the appearance of the data.\"\"\"\n \n         # update shader properties related to appearance\n         self.track_shader.use_fade = self.layer.use_fade\n@@ -88,7 +88,7 @@\n         self.node._subvisuals[2].set_data(width=self.layer.tail_width,)\n \n     def _on_tracks_change(self, event=None):\n-        \"\"\" update the shader when the track data changes \"\"\"\n+        \"\"\"Update the shader when the track data changes.\"\"\"\n \n         self.track_shader.use_fade = self.layer.use_fade\n         self.track_shader.tail_length = self.layer.tail_length\n@@ -106,7 +106,7 @@\n         self._on_matrix_change()\n \n     def _on_graph_change(self, event=None):\n-        \"\"\" update the shader when the graph data changes \"\"\"\n+        \"\"\"Update the shader when the graph data changes.\"\"\"\n \n         self.graph_shader.use_fade = self.layer.use_fade\n         self.graph_shader.tail_length = self.layer.tail_length\n", "issue": "Track vertex shader does not handle blending/opacity correctly\n## \ud83d\udc1b Bug\r\n\r\nTwo somewhat related bugs in `_vispy_tracks_shader.py` in the `Tracks` layer:\r\n1. The opacity slider only changes the vispy node opacity, which has no effect on the vertex shader used for rendering the tracks or graph.\r\n2. The translucent mode renders parts of the track, which should not be rendered, as dark lines:\r\n\r\n![bug](https://user-images.githubusercontent.com/8217795/96697072-64ef9b00-1383-11eb-9648-54c92319ae84.gif)\r\n\r\n## To Reproduce\r\n\r\nSteps to reproduce the behavior:\r\n\r\n1. run `examples\\tracks_3d.py`\r\n2. Change the blending mode to translucent in the `Tracks` layer\r\n3. Change the opacity slider \r\n\r\n## Expected behavior\r\n\r\n`opacity` should change the track opacity, and the `translucent` blending should not render parts of the track which should not be visible.\r\n\r\n## Environment\r\n\r\nnapari: 0.3.9.dev32+g911e095.d20201007\r\nPlatform: Linux-4.15.0-1100-oem-x86_64-with-debian-buster-sid\r\nPython: 3.7.7 (default, May 7 2020, 21:25:33) [GCC 7.3.0]\r\nQt: 5.14.2\r\nPySide2: 5.14.2.2\r\nNumPy: 1.19.1\r\nSciPy: 1.4.1\r\nDask: 2.17.2\r\nVisPy: 0.6.4\r\n\r\nGL version: 4.6.0 NVIDIA 450.80.02\r\nMAX_TEXTURE_SIZE: 32768\r\n\r\nPlugins:\r\n- napari-plugin-engine: 0.1.5\r\n- svg: 0.1.3\r\n\r\n## Additional context\r\nThis relates to the fact that the shader manipulates the alpha values of the vertices directly, late in the rendering pipeline.\n", "before_files": [{"content": "from vispy.scene.visuals import Compound, Line, Text\n\nfrom ._vispy_tracks_shader import TrackShader\nfrom .vispy_base_layer import VispyBaseLayer\n\n\nclass VispyTracksLayer(VispyBaseLayer):\n    \"\"\"VispyTracksLayer\n\n    Track layer for visualizing tracks.\n\n    Components:\n        - Track lines (vispy.LineVisual)\n        - Track IDs (vispy.TextVisual)\n        - Graph edges (vispy.LineVisual)\n\n    \"\"\"\n\n    def __init__(self, layer):\n        node = Compound([Line(), Text(), Line()])\n        super().__init__(layer, node)\n\n        self.layer.events.tail_width.connect(self._on_appearance_change)\n        self.layer.events.tail_length.connect(self._on_appearance_change)\n        self.layer.events.display_id.connect(self._on_appearance_change)\n        self.layer.events.display_tail.connect(self._on_appearance_change)\n        self.layer.events.display_graph.connect(self._on_appearance_change)\n\n        self.layer.events.color_by.connect(self._on_appearance_change)\n        self.layer.events.colormap.connect(self._on_appearance_change)\n\n        # these events are fired when changes occur to the tracks or the\n        # graph - as the vertex buffer of the shader needs to be updated\n        # alongside the actual vertex data\n        self.layer.events.rebuild_tracks.connect(self._on_tracks_change)\n        self.layer.events.rebuild_graph.connect(self._on_graph_change)\n\n        # build and attach the shader to the track\n        self.track_shader = TrackShader()\n        self.graph_shader = TrackShader()\n        node._subvisuals[0].attach(self.track_shader)\n        node._subvisuals[2].attach(self.graph_shader)\n\n        # text label properties\n        self.node._subvisuals[1].color = 'white'\n        self.node._subvisuals[1].font_size = 8\n\n        self._reset_base()\n\n        self._on_data_change()\n        self._on_appearance_change()\n\n    def _on_data_change(self, event=None):\n        \"\"\" update the display \"\"\"\n\n        # update the shaders\n        self.track_shader.current_time = self.layer.current_time\n        self.graph_shader.current_time = self.layer.current_time\n\n        # add text labels if they're visible\n        if self.node._subvisuals[1].visible:\n            labels_text, labels_pos = self.layer.track_labels\n            self.node._subvisuals[1].text = labels_text\n            self.node._subvisuals[1].pos = labels_pos\n\n        self.node.update()\n        # Call to update order of translation values with new dims:\n        self._on_matrix_change()\n\n    def _on_appearance_change(self, event=None):\n        \"\"\" change the appearance of the data \"\"\"\n\n        # update shader properties related to appearance\n        self.track_shader.use_fade = self.layer.use_fade\n        self.track_shader.tail_length = self.layer.tail_length\n        self.graph_shader.use_fade = self.layer.use_fade\n        self.graph_shader.tail_length = self.layer.tail_length\n\n        # set visibility of subvisuals\n        self.node._subvisuals[0].visible = self.layer.display_tail\n        self.node._subvisuals[1].visible = self.layer.display_id\n        self.node._subvisuals[2].visible = self.layer.display_graph\n\n        # set the width of the track tails\n        self.node._subvisuals[0].set_data(\n            width=self.layer.tail_width, color=self.layer.track_colors,\n        )\n        self.node._subvisuals[2].set_data(width=self.layer.tail_width,)\n\n    def _on_tracks_change(self, event=None):\n        \"\"\" update the shader when the track data changes \"\"\"\n\n        self.track_shader.use_fade = self.layer.use_fade\n        self.track_shader.tail_length = self.layer.tail_length\n        self.track_shader.vertex_time = self.layer.track_times\n\n        # change the data to the vispy line visual\n        self.node._subvisuals[0].set_data(\n            pos=self.layer._view_data,\n            connect=self.layer.track_connex,\n            width=self.layer.tail_width,\n            color=self.layer.track_colors,\n        )\n\n        # Call to update order of translation values with new dims:\n        self._on_matrix_change()\n\n    def _on_graph_change(self, event=None):\n        \"\"\" update the shader when the graph data changes \"\"\"\n\n        self.graph_shader.use_fade = self.layer.use_fade\n        self.graph_shader.tail_length = self.layer.tail_length\n        self.graph_shader.vertex_time = self.layer.graph_times\n\n        # if the user clears a graph after it has been created, vispy offers\n        # no method to clear the data, therefore, we need to set private\n        # attributes to None to prevent errors\n        if self.layer._view_graph is None:\n            self.node._subvisuals[2]._pos = None\n            self.node._subvisuals[2]._connect = None\n            self.node.update()\n            return\n\n        self.node._subvisuals[2].set_data(\n            pos=self.layer._view_graph,\n            connect=self.layer.graph_connex,\n            width=self.layer.tail_width,\n            color='white',\n        )\n\n        # Call to update order of translation values with new dims:\n        self._on_matrix_change()\n", "path": "napari/_vispy/vispy_tracks_layer.py"}, {"content": "from typing import List, Union\n\nimport numpy as np\nfrom vispy.gloo import VertexBuffer\nfrom vispy.visuals.filters.base_filter import Filter\n\n\nclass TrackShader(Filter):\n    \"\"\" TrackShader\n\n    Custom vertex and fragment shaders for visualizing tracks quickly with\n    vispy. The central assumption is that the tracks are rendered as a\n    continuous vispy Line segment, with connections and colors defined when\n    the visual is created.\n\n    The shader simply changes the visibility and/or fading of the data according\n    to the current_time and the associate time metadata for each vertex. This\n    is scaled according to the tail length. Points ahead of the current time\n    are rendered with alpha set to zero.\n\n    Parameters\n    ----------\n    current_time : int, float\n        the current time, which is typically the frame index, although this\n        can be an arbitrary float\n    tail_length : int, float\n        the upper limit on length of the 'tail'\n    use_fade : bool\n        this will enable/disable tail fading with time\n    vertex_time : 1D array, list\n        a vector describing the time associated with each vertex\n\n\n    TODO\n    ----\n    - the track is still displayed, albeit with fading, once the track has\n     finished but is still within the 'tail_length' window. Should it\n     disappear?\n    - check the shader positioning within the GL pipeline, currently\n     overrides layer opacity settings\n\n    vertex_mask: 1D array, list\n        a vector describing whether to mask each vertex\n\n    \"\"\"\n\n    VERT_SHADER = \"\"\"\n        varying vec4 v_track_color;\n        void apply_track_shading() {\n\n            float alpha;\n\n            if ($a_vertex_time > $current_time) {\n                // this is a hack to minimize the frag shader rendering ahead\n                // of the current time point due to interpolation\n                if ($a_vertex_time <= $current_time + 1){\n                    alpha = -100.;\n                } else {\n                    alpha = 0.;\n                }\n            } else {\n                // fade the track into the temporal distance, scaled by the\n                // maximum tail length from the gui\n                float fade = ($current_time - $a_vertex_time) / $tail_length;\n                alpha = clamp(1.0-fade, 0.0, 1.0);\n            }\n\n            // when use_fade is disabled, the entire track is visible\n            if ($use_fade == 0) {\n                alpha = 1.0;\n            }\n\n            // set the vertex alpha according to the fade\n            v_track_color.a = alpha;\n        }\n    \"\"\"\n\n    FRAG_SHADER = \"\"\"\n        varying vec4 v_track_color;\n        void apply_track_shading() {\n            // interpolate\n            gl_FragColor.a = clamp(v_track_color.a, 0.0, 1.0);\n        }\n    \"\"\"\n\n    def __init__(\n        self,\n        current_time=0,\n        tail_length=30,\n        use_fade: bool = True,\n        vertex_time: Union[List, np.ndarray] = None,\n    ):\n\n        super().__init__(\n            vcode=self.VERT_SHADER, vpos=3, fcode=self.FRAG_SHADER, fpos=9\n        )\n\n        self.current_time = current_time\n        self.tail_length = tail_length\n        self.use_fade = use_fade\n        self.vertex_time = vertex_time\n\n    @property\n    def current_time(self) -> Union[int, float]:\n        return self._current_time\n\n    @current_time.setter\n    def current_time(self, n: Union[int, float]):\n        self._current_time = n\n        if isinstance(n, slice):\n            n = np.max(self._vertex_time)\n        self.vshader['current_time'] = float(n)\n\n    @property\n    def use_fade(self) -> bool:\n        return self._use_fade\n\n    @use_fade.setter\n    def use_fade(self, value: bool):\n        self._use_fade = value\n        self.vshader['use_fade'] = float(self._use_fade)\n\n    @property\n    def tail_length(self) -> Union[int, float]:\n        return self._tail_length\n\n    @tail_length.setter\n    def tail_length(self, tail_length: Union[int, float]):\n        self._tail_length = tail_length\n        self.vshader['tail_length'] = float(self._tail_length)\n\n    def _attach(self, visual):\n        super()._attach(visual)\n\n    @property\n    def vertex_time(self):\n        return self._vertex_time\n\n    @vertex_time.setter\n    def vertex_time(self, v_time):\n        self._vertex_time = np.array(v_time).reshape(-1, 1).astype(np.float32)\n        self.vshader['a_vertex_time'] = VertexBuffer(self.vertex_time)\n", "path": "napari/_vispy/_vispy_tracks_shader.py"}], "after_files": [{"content": "from vispy.scene.visuals import Compound, Line, Text\n\nfrom ._vispy_tracks_shader import TrackShader\nfrom .vispy_base_layer import VispyBaseLayer\n\n\nclass VispyTracksLayer(VispyBaseLayer):\n    \"\"\"VispyTracksLayer\n\n    Track layer for visualizing tracks.\n\n    Components:\n        - Track lines (vispy.LineVisual)\n        - Track IDs (vispy.TextVisual)\n        - Graph edges (vispy.LineVisual)\n\n    \"\"\"\n\n    def __init__(self, layer):\n        node = Compound([Line(), Text(), Line()])\n        super().__init__(layer, node)\n\n        self.layer.events.tail_width.connect(self._on_appearance_change)\n        self.layer.events.tail_length.connect(self._on_appearance_change)\n        self.layer.events.display_id.connect(self._on_appearance_change)\n        self.layer.events.display_tail.connect(self._on_appearance_change)\n        self.layer.events.display_graph.connect(self._on_appearance_change)\n\n        self.layer.events.color_by.connect(self._on_appearance_change)\n        self.layer.events.colormap.connect(self._on_appearance_change)\n\n        # these events are fired when changes occur to the tracks or the\n        # graph - as the vertex buffer of the shader needs to be updated\n        # alongside the actual vertex data\n        self.layer.events.rebuild_tracks.connect(self._on_tracks_change)\n        self.layer.events.rebuild_graph.connect(self._on_graph_change)\n\n        # build and attach the shader to the track\n        self.track_shader = TrackShader()\n        self.graph_shader = TrackShader()\n        node._subvisuals[0].attach(self.track_shader)\n        node._subvisuals[2].attach(self.graph_shader)\n\n        # text label properties\n        self.node._subvisuals[1].color = 'white'\n        self.node._subvisuals[1].font_size = 8\n\n        self._reset_base()\n\n        self._on_data_change()\n        self._on_appearance_change()\n\n    def _on_data_change(self, event=None):\n        \"\"\"Update the display.\"\"\"\n\n        # update the shaders\n        self.track_shader.current_time = self.layer.current_time\n        self.graph_shader.current_time = self.layer.current_time\n\n        # add text labels if they're visible\n        if self.node._subvisuals[1].visible:\n            labels_text, labels_pos = self.layer.track_labels\n            self.node._subvisuals[1].text = labels_text\n            self.node._subvisuals[1].pos = labels_pos\n\n        self.node.update()\n        # Call to update order of translation values with new dims:\n        self._on_matrix_change()\n\n    def _on_appearance_change(self, event=None):\n        \"\"\"Change the appearance of the data.\"\"\"\n\n        # update shader properties related to appearance\n        self.track_shader.use_fade = self.layer.use_fade\n        self.track_shader.tail_length = self.layer.tail_length\n        self.graph_shader.use_fade = self.layer.use_fade\n        self.graph_shader.tail_length = self.layer.tail_length\n\n        # set visibility of subvisuals\n        self.node._subvisuals[0].visible = self.layer.display_tail\n        self.node._subvisuals[1].visible = self.layer.display_id\n        self.node._subvisuals[2].visible = self.layer.display_graph\n\n        # set the width of the track tails\n        self.node._subvisuals[0].set_data(\n            width=self.layer.tail_width, color=self.layer.track_colors,\n        )\n        self.node._subvisuals[2].set_data(width=self.layer.tail_width,)\n\n    def _on_tracks_change(self, event=None):\n        \"\"\"Update the shader when the track data changes.\"\"\"\n\n        self.track_shader.use_fade = self.layer.use_fade\n        self.track_shader.tail_length = self.layer.tail_length\n        self.track_shader.vertex_time = self.layer.track_times\n\n        # change the data to the vispy line visual\n        self.node._subvisuals[0].set_data(\n            pos=self.layer._view_data,\n            connect=self.layer.track_connex,\n            width=self.layer.tail_width,\n            color=self.layer.track_colors,\n        )\n\n        # Call to update order of translation values with new dims:\n        self._on_matrix_change()\n\n    def _on_graph_change(self, event=None):\n        \"\"\"Update the shader when the graph data changes.\"\"\"\n\n        self.graph_shader.use_fade = self.layer.use_fade\n        self.graph_shader.tail_length = self.layer.tail_length\n        self.graph_shader.vertex_time = self.layer.graph_times\n\n        # if the user clears a graph after it has been created, vispy offers\n        # no method to clear the data, therefore, we need to set private\n        # attributes to None to prevent errors\n        if self.layer._view_graph is None:\n            self.node._subvisuals[2]._pos = None\n            self.node._subvisuals[2]._connect = None\n            self.node.update()\n            return\n\n        self.node._subvisuals[2].set_data(\n            pos=self.layer._view_graph,\n            connect=self.layer.graph_connex,\n            width=self.layer.tail_width,\n            color='white',\n        )\n\n        # Call to update order of translation values with new dims:\n        self._on_matrix_change()\n", "path": "napari/_vispy/vispy_tracks_layer.py"}, {"content": "from typing import List, Union\n\nimport numpy as np\nfrom vispy.gloo import VertexBuffer\nfrom vispy.visuals.filters.base_filter import Filter\n\n\nclass TrackShader(Filter):\n    \"\"\"TrackShader.\n\n    Custom vertex and fragment shaders for visualizing tracks quickly with\n    vispy. The central assumption is that the tracks are rendered as a\n    continuous vispy Line segment, with connections and colors defined when\n    the visual is created.\n\n    The shader simply changes the visibility and/or fading of the data according\n    to the current_time and the associate time metadata for each vertex. This\n    is scaled according to the tail length. Points ahead of the current time\n    are rendered with alpha set to zero.\n\n    Parameters\n    ----------\n    current_time : int, float\n        the current time, which is typically the frame index, although this\n        can be an arbitrary float\n    tail_length : int, float\n        the upper limit on length of the 'tail'\n    use_fade : bool\n        this will enable/disable tail fading with time\n    vertex_time : 1D array, list\n        a vector describing the time associated with each vertex\n\n    TODO\n    ----\n    - the track is still displayed, albeit with fading, once the track has\n     finished but is still within the 'tail_length' window. Should it\n     disappear?\n\n    \"\"\"\n\n    VERT_SHADER = \"\"\"\n        varying vec4 v_track_color;\n        void apply_track_shading() {\n\n            float alpha;\n\n            if ($a_vertex_time > $current_time) {\n                // this is a hack to minimize the frag shader rendering ahead\n                // of the current time point due to interpolation\n                if ($a_vertex_time <= $current_time + 1){\n                    alpha = -100.;\n                } else {\n                    alpha = 0.;\n                }\n            } else {\n                // fade the track into the temporal distance, scaled by the\n                // maximum tail length from the gui\n                float fade = ($current_time - $a_vertex_time) / $tail_length;\n                alpha = clamp(1.0-fade, 0.0, 1.0);\n            }\n\n            // when use_fade is disabled, the entire track is visible\n            if ($use_fade == 0) {\n                alpha = 1.0;\n            }\n\n            // set the vertex alpha according to the fade\n            v_track_color.a = alpha;\n        }\n    \"\"\"\n\n    FRAG_SHADER = \"\"\"\n        varying vec4 v_track_color;\n        void apply_track_shading() {\n\n            // if the alpha is below the threshold, discard the fragment\n            if( v_track_color.a <= 0.0 ) {\n                discard;\n            }\n\n            // interpolate\n            gl_FragColor.a = clamp(v_track_color.a * gl_FragColor.a, 0.0, 1.0);\n        }\n    \"\"\"\n\n    def __init__(\n        self,\n        current_time: Union[int, float] = 0,\n        tail_length: Union[int, float] = 30,\n        use_fade: bool = True,\n        vertex_time: Union[List, np.ndarray] = None,\n    ):\n\n        super().__init__(\n            vcode=self.VERT_SHADER, vpos=3, fcode=self.FRAG_SHADER, fpos=9\n        )\n\n        self.current_time = current_time\n        self.tail_length = tail_length\n        self.use_fade = use_fade\n        self.vertex_time = vertex_time\n\n    @property\n    def current_time(self) -> Union[int, float]:\n        return self._current_time\n\n    @current_time.setter\n    def current_time(self, n: Union[int, float]):\n        self._current_time = n\n        if isinstance(n, slice):\n            n = np.max(self._vertex_time)\n        self.vshader['current_time'] = float(n)\n\n    @property\n    def use_fade(self) -> bool:\n        return self._use_fade\n\n    @use_fade.setter\n    def use_fade(self, value: bool):\n        self._use_fade = value\n        self.vshader['use_fade'] = float(self._use_fade)\n\n    @property\n    def tail_length(self) -> Union[int, float]:\n        return self._tail_length\n\n    @tail_length.setter\n    def tail_length(self, tail_length: Union[int, float]):\n        self._tail_length = tail_length\n        self.vshader['tail_length'] = float(self._tail_length)\n\n    def _attach(self, visual):\n        super()._attach(visual)\n\n    @property\n    def vertex_time(self):\n        return self._vertex_time\n\n    @vertex_time.setter\n    def vertex_time(self, v_time):\n        self._vertex_time = np.array(v_time).reshape(-1, 1).astype(np.float32)\n        self.vshader['a_vertex_time'] = VertexBuffer(self.vertex_time)\n", "path": "napari/_vispy/_vispy_tracks_shader.py"}]}