We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ZoomTool "zoom history" keys are not working
From the examples/data_labels.py docstring:

> Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular region to
>  zoom.  If you use a sequence of zoom boxes, pressing alt-left-arrow and
> alt-right-arrow moves you forwards and backwards through the "zoom history".

but the alt-right-arrow and alt-left-arrow keys don't seem to have any effect.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `examples/demo/data_labels.py`
Content:
```
1 #!/usr/bin/env python
2 """
3 Draws a line plot with several points labelled.  Demonstrates how to annotate
4 plots.
5 
6 Left-drag pans the plot.
7 
8 Mousewheel up and down zooms the plot in and out.
9 
10 Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular
11 region to zoom.  If you use a sequence of zoom boxes, pressing alt-left-arrow
12 and alt-right-arrow moves you forwards and backwards through the
13 "zoom history".
14 
15 Right-drag is enabled on some of the labels.
16 """
17 
18 # Major library imports
19 from numpy import linspace
20 from scipy.special import jn
21 
22 # Enthought library imports
23 from enable.api import Component, ComponentEditor
24 from traits.api import Float, HasTraits, Instance, Int
25 from traitsui.api import Item, View
26 
27 # Chaco imports
28 from chaco.api import create_line_plot, add_default_axes, add_default_grids, \
29                       OverlayPlotContainer, DataLabel
30 from chaco.example_support import COLOR_PALETTE
31 from chaco.tools.api import PanTool, ZoomTool, DataLabelTool
32 
33 
34 class PlotExample(HasTraits):
35     plot = Instance(Component)
36     numpoints = Int(100)
37     low = Float(-5.0)
38     high = Float(15.0)
39 
40     traits_view = View(Item('plot', editor=ComponentEditor(),
41                             show_label=False),
42                        width=800, height=700, resizable=True,
43                        title="Data label example")
44 
45     def _plot_default(self):
46 
47         container = OverlayPlotContainer(padding=50, fill_padding=True,
48                                          bgcolor="lightgray",
49                                          use_backbuffer=True)
50 
51         # Create the initial X-series of data
52         numpoints = self.numpoints
53         low = self.low
54         high = self.high
55         x = linspace(low, high, numpoints + 1)
56         y = jn(0, x)
57         plot = create_line_plot((x, y), color=tuple(COLOR_PALETTE[0]),
58                                 width=2.0)
59         plot.index.sort_order = "ascending"
60         plot.bgcolor = "white"
61         plot.border_visible = True
62         add_default_grids(plot)
63         add_default_axes(plot)
64 
65         # Add some tools
66         plot.tools.append(PanTool(plot))
67         zoom = ZoomTool(plot, tool_mode="box", always_on=False)
68         plot.overlays.append(zoom)
69 
70         # Add a dynamic label.  This can be dragged and moved around using the
71         # right mouse button.  Note the use of padding to offset the label
72         # from its data point.
73         label = DataLabel(component=plot, data_point=(x[40], y[40]),
74                           label_position="top left", padding=40,
75                           bgcolor="lightgray",
76                           border_visible=False)
77         plot.overlays.append(label)
78         tool = DataLabelTool(label, drag_button="right", auto_arrow_root=True)
79         label.tools.append(tool)
80 
81         # Add some static labels.
82         label2 = DataLabel(component=plot, data_point=(x[20], y[20]),
83                            label_position="bottom right",
84                            border_visible=False,
85                            bgcolor="transparent",
86                            marker_color="blue",
87                            marker_line_color="transparent",
88                            marker="diamond",
89                            font='modern 14',
90                            arrow_visible=False)
91         plot.overlays.append(label2)
92 
93         label3 = DataLabel(component=plot, data_point=(x[80], y[80]),
94                            label_position="top", padding_bottom=20,
95                            marker_color="transparent",
96                            marker_size=8,
97                            marker="circle",
98                            arrow_visible=False)
99         plot.overlays.append(label3)
100 
101         # This label uses label_style='bubble'.
102         label4 = DataLabel(component=plot, data_point=(x[60], y[60]),
103                            border_padding=10,
104                            marker_color="red",
105                            marker_size=3,
106                            label_position=(20, 50),
107                            label_style='bubble',
108                            label_text="Something interesting",
109                            label_format="at x=%(x).2f, y=%(y).2f",
110                            font='modern 18',
111                            bgcolor=(1, 1, 0.75, 1),
112                           )
113         plot.overlays.append(label4)
114         tool4 = DataLabelTool(label4, drag_button="right",
115                               auto_arrow_root=True)
116         label4.tools.append(tool4)
117 
118         # Another 'bubble' label.  This one sets arrow_min_length=20, so
119         # the arrow is not drawn when the label is close to the data point.
120         label5 = DataLabel(component=plot, data_point=(x[65], y[65]),
121                            border_padding=10,
122                            marker_color="green",
123                            marker_size=4,
124                            show_label_coords=False,
125                            label_style='bubble',
126                            label_position=(25, 5),
127                            label_text="Label with\narrow_min_length=20",
128                            border_visible=False,
129                            arrow_min_length=20,
130                            font='modern 14',
131                            bgcolor=(0.75, 0.75, 0.75, 1),
132                           )
133         plot.overlays.append(label5)
134         tool5 = DataLabelTool(label5, drag_button="right",
135                               auto_arrow_root=True)
136         label5.tools.append(tool5)
137 
138         container.add(plot)
139 
140         return container
141 
142 demo = PlotExample()
143 
144 if __name__ == "__main__":
145     demo.configure_traits()
146
```

Path: `examples/demo/edit_line.py`
Content:
```
1 #!/usr/bin/env python
2 """
3 Allows editing of a line plot.
4 
5 Left-dragging a point will move its position.
6 
7 Right-drag pans the plot.
8 
9 Mousewheel up and down zooms the plot in and out.
10 
11 Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular region to
12 zoom.  If you use a sequence of zoom boxes, pressing alt-left-arrow and
13 alt-right-arrow moves you forwards and backwards through the "zoom history".
14 """
15 
16 # Major library imports
17 from numpy import linspace
18 from scipy.special import jn
19 
20 from chaco.example_support import COLOR_PALETTE
21 
22 # Enthought library imports
23 from enable.tools.api import DragTool
24 from enable.api import Component, ComponentEditor
25 from traits.api import HasTraits, Instance, Int, Tuple
26 from traitsui.api import UItem, View
27 
28 # Chaco imports
29 from chaco.api import add_default_axes, add_default_grids, \
30         OverlayPlotContainer, PlotLabel, ScatterPlot, create_line_plot
31 from chaco.tools.api import PanTool, ZoomTool
32 
33 
34 
35 class PointDraggingTool(DragTool):
36 
37     component = Instance(Component)
38 
39     # The pixel distance from a point that the cursor is still considered
40     # to be 'on' the point
41     threshold = Int(5)
42 
43     # The index of the point being dragged
44     _drag_index = Int(-1)
45 
46     # The original dataspace values of the index and value datasources
47     # corresponding to _drag_index
48     _orig_value = Tuple
49 
50     def is_draggable(self, x, y):
51         # Check to see if (x,y) are over one of the points in self.component
52         if self._lookup_point(x, y) is not None:
53             return True
54         else:
55             return False
56 
57     def normal_mouse_move(self, event):
58         plot = self.component
59 
60         ndx = plot.map_index((event.x, event.y), self.threshold)
61         if ndx is None:
62             if plot.index.metadata.has_key('selections'):
63                 del plot.index.metadata['selections']
64         else:
65             plot.index.metadata['selections'] = [ndx]
66 
67         plot.invalidate_draw()
68         plot.request_redraw()
69 
70 
71     def drag_start(self, event):
72         plot = self.component
73         ndx = plot.map_index((event.x, event.y), self.threshold)
74         if ndx is None:
75             return
76         self._drag_index = ndx
77         self._orig_value = (plot.index.get_data()[ndx], plot.value.get_data()[ndx])
78 
79     def dragging(self, event):
80         plot = self.component
81 
82         data_x, data_y = plot.map_data((event.x, event.y))
83 
84         plot.index._data[self._drag_index] = data_x
85         plot.value._data[self._drag_index] = data_y
86         plot.index.data_changed = True
87         plot.value.data_changed = True
88         plot.request_redraw()
89 
90     def drag_cancel(self, event):
91         plot = self.component
92         plot.index._data[self._drag_index] = self._orig_value[0]
93         plot.value._data[self._drag_index] = self._orig_value[1]
94         plot.index.data_changed = True
95         plot.value.data_changed = True
96         plot.request_redraw()
97 
98     def drag_end(self, event):
99         plot = self.component
100         if plot.index.metadata.has_key('selections'):
101             del plot.index.metadata['selections']
102         plot.invalidate_draw()
103         plot.request_redraw()
104 
105     def _lookup_point(self, x, y):
106         """ Finds the point closest to a screen point if it is within self.threshold
107 
108         Parameters
109         ==========
110         x : float
111             screen x-coordinate
112         y : float
113             screen y-coordinate
114 
115         Returns
116         =======
117         (screen_x, screen_y, distance) of datapoint nearest to the input *(x,y)*.
118         If no data points are within *self.threshold* of *(x,y)*, returns None.
119         """
120 
121         if hasattr(self.component, 'get_closest_point'):
122             # This is on BaseXYPlots
123             return self.component.get_closest_point((x,y), threshold=self.threshold)
124 
125         return None
126 
127 
128 #===============================================================================
129 # # Create the Chaco plot.
130 #===============================================================================
131 def _create_plot_component():
132 
133     container = OverlayPlotContainer(padding = 50, fill_padding = True,
134                                      bgcolor = "lightgray", use_backbuffer=True)
135 
136     # Create the initial X-series of data
137     numpoints = 30
138     low = -5
139     high = 15.0
140     x = linspace(low, high, numpoints)
141     y = jn(0, x)
142 
143     lineplot = create_line_plot((x,y), color=tuple(COLOR_PALETTE[0]), width=2.0)
144     lineplot.selected_color = "none"
145     scatter = ScatterPlot(index = lineplot.index,
146                        value = lineplot.value,
147                        index_mapper = lineplot.index_mapper,
148                        value_mapper = lineplot.value_mapper,
149                        color = tuple(COLOR_PALETTE[0]),
150                        marker_size = 5)
151     scatter.index.sort_order = "ascending"
152 
153     scatter.bgcolor = "white"
154     scatter.border_visible = True
155 
156     add_default_grids(scatter)
157     add_default_axes(scatter)
158 
159     scatter.tools.append(PanTool(scatter, drag_button="right"))
160 
161     # The ZoomTool tool is stateful and allows drawing a zoom
162     # box to select a zoom region.
163     zoom = ZoomTool(scatter, tool_mode="box", always_on=False, drag_button=None)
164     scatter.overlays.append(zoom)
165 
166     scatter.tools.append(PointDraggingTool(scatter))
167 
168     container.add(lineplot)
169     container.add(scatter)
170 
171     # Add the title at the top
172     container.overlays.append(PlotLabel("Line Editor",
173                               component=container,
174                               font = "swiss 16",
175                               overlay_position="top"))
176 
177     return container
178 
179 
180 #===============================================================================
181 # Attributes to use for the plot view.
182 size=(800,700)
183 title="Simple line plot"
184 
185 #===============================================================================
186 # # Demo class that is used by the demo.py application.
187 #===============================================================================
188 class Demo(HasTraits):
189     plot = Instance(Component)
190 
191     traits_view = View(UItem('plot', editor=ComponentEditor()),
192                        width=size[0], height=size[1], resizable=True,
193                        title=title
194                        )
195 
196     def _plot_default(self):
197          return _create_plot_component()
198 
199 demo = Demo()
200 
201 if __name__ == "__main__":
202     demo.configure_traits()
203 
204 #--EOF---
205
```
--- 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/examples/demo/data_labels.py b/examples/demo/data_labels.py
--- a/examples/demo/data_labels.py
+++ b/examples/demo/data_labels.py
@@ -8,9 +8,9 @@
 Mousewheel up and down zooms the plot in and out.
 
 Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular
-region to zoom.  If you use a sequence of zoom boxes, pressing alt-left-arrow
-and alt-right-arrow moves you forwards and backwards through the
-"zoom history".
+region to zoom.  If you use a sequence of zoom boxes, pressing control-y
+and control-z (Meta-y and Meta-z on Mac) moves you forwards and backwards
+through the "zoom history".
 
 Right-drag is enabled on some of the labels.
 """
diff --git a/examples/demo/edit_line.py b/examples/demo/edit_line.py
--- a/examples/demo/edit_line.py
+++ b/examples/demo/edit_line.py
@@ -8,9 +8,10 @@
 
 Mousewheel up and down zooms the plot in and out.
 
-Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular region to
-zoom.  If you use a sequence of zoom boxes, pressing alt-left-arrow and
-alt-right-arrow moves you forwards and backwards through the "zoom history".
+Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular
+region to zoom.  If you use a sequence of zoom boxes, pressing control-y and
+control-z  (use Meta-y and Meta-z on Mac) moves you forwards and backwards
+through the "zoom history".
 """
 
 # Major library imports
@@ -160,7 +161,7 @@
 
     # The ZoomTool tool is stateful and allows drawing a zoom
     # box to select a zoom region.
-    zoom = ZoomTool(scatter, tool_mode="box", always_on=False, drag_button=None)
+    zoom = ZoomTool(scatter, tool_mode="box", always_on=False)
     scatter.overlays.append(zoom)
 
     scatter.tools.append(PointDraggingTool(scatter))

{"golden_diff": "diff --git a/examples/demo/data_labels.py b/examples/demo/data_labels.py\n--- a/examples/demo/data_labels.py\n+++ b/examples/demo/data_labels.py\n@@ -8,9 +8,9 @@\n Mousewheel up and down zooms the plot in and out.\n \n Pressing \"z\" brings up the Zoom Box, and you can click-drag a rectangular\n-region to zoom.  If you use a sequence of zoom boxes, pressing alt-left-arrow\n-and alt-right-arrow moves you forwards and backwards through the\n-\"zoom history\".\n+region to zoom.  If you use a sequence of zoom boxes, pressing control-y\n+and control-z (Meta-y and Meta-z on Mac) moves you forwards and backwards\n+through the \"zoom history\".\n \n Right-drag is enabled on some of the labels.\n \"\"\"\ndiff --git a/examples/demo/edit_line.py b/examples/demo/edit_line.py\n--- a/examples/demo/edit_line.py\n+++ b/examples/demo/edit_line.py\n@@ -8,9 +8,10 @@\n \n Mousewheel up and down zooms the plot in and out.\n \n-Pressing \"z\" brings up the Zoom Box, and you can click-drag a rectangular region to\n-zoom.  If you use a sequence of zoom boxes, pressing alt-left-arrow and\n-alt-right-arrow moves you forwards and backwards through the \"zoom history\".\n+Pressing \"z\" brings up the Zoom Box, and you can click-drag a rectangular\n+region to zoom.  If you use a sequence of zoom boxes, pressing control-y and\n+control-z  (use Meta-y and Meta-z on Mac) moves you forwards and backwards\n+through the \"zoom history\".\n \"\"\"\n \n # Major library imports\n@@ -160,7 +161,7 @@\n \n     # The ZoomTool tool is stateful and allows drawing a zoom\n     # box to select a zoom region.\n-    zoom = ZoomTool(scatter, tool_mode=\"box\", always_on=False, drag_button=None)\n+    zoom = ZoomTool(scatter, tool_mode=\"box\", always_on=False)\n     scatter.overlays.append(zoom)\n \n     scatter.tools.append(PointDraggingTool(scatter))\n", "issue": "ZoomTool \"zoom history\" keys are not working\nFrom the examples/data_labels.py docstring:\n\n> Pressing \"z\" brings up the Zoom Box, and you can click-drag a rectangular region to\n>  zoom.  If you use a sequence of zoom boxes, pressing alt-left-arrow and\n> alt-right-arrow moves you forwards and backwards through the \"zoom history\".\n\nbut the alt-right-arrow and alt-left-arrow keys don't seem to have any effect.\n\n", "before_files": [{"content": "#!/usr/bin/env python\n\"\"\"\nDraws a line plot with several points labelled.  Demonstrates how to annotate\nplots.\n\nLeft-drag pans the plot.\n\nMousewheel up and down zooms the plot in and out.\n\nPressing \"z\" brings up the Zoom Box, and you can click-drag a rectangular\nregion to zoom.  If you use a sequence of zoom boxes, pressing alt-left-arrow\nand alt-right-arrow moves you forwards and backwards through the\n\"zoom history\".\n\nRight-drag is enabled on some of the labels.\n\"\"\"\n\n# Major library imports\nfrom numpy import linspace\nfrom scipy.special import jn\n\n# Enthought library imports\nfrom enable.api import Component, ComponentEditor\nfrom traits.api import Float, HasTraits, Instance, Int\nfrom traitsui.api import Item, View\n\n# Chaco imports\nfrom chaco.api import create_line_plot, add_default_axes, add_default_grids, \\\n                      OverlayPlotContainer, DataLabel\nfrom chaco.example_support import COLOR_PALETTE\nfrom chaco.tools.api import PanTool, ZoomTool, DataLabelTool\n\n\nclass PlotExample(HasTraits):\n    plot = Instance(Component)\n    numpoints = Int(100)\n    low = Float(-5.0)\n    high = Float(15.0)\n\n    traits_view = View(Item('plot', editor=ComponentEditor(),\n                            show_label=False),\n                       width=800, height=700, resizable=True,\n                       title=\"Data label example\")\n\n    def _plot_default(self):\n\n        container = OverlayPlotContainer(padding=50, fill_padding=True,\n                                         bgcolor=\"lightgray\",\n                                         use_backbuffer=True)\n\n        # Create the initial X-series of data\n        numpoints = self.numpoints\n        low = self.low\n        high = self.high\n        x = linspace(low, high, numpoints + 1)\n        y = jn(0, x)\n        plot = create_line_plot((x, y), color=tuple(COLOR_PALETTE[0]),\n                                width=2.0)\n        plot.index.sort_order = \"ascending\"\n        plot.bgcolor = \"white\"\n        plot.border_visible = True\n        add_default_grids(plot)\n        add_default_axes(plot)\n\n        # Add some tools\n        plot.tools.append(PanTool(plot))\n        zoom = ZoomTool(plot, tool_mode=\"box\", always_on=False)\n        plot.overlays.append(zoom)\n\n        # Add a dynamic label.  This can be dragged and moved around using the\n        # right mouse button.  Note the use of padding to offset the label\n        # from its data point.\n        label = DataLabel(component=plot, data_point=(x[40], y[40]),\n                          label_position=\"top left\", padding=40,\n                          bgcolor=\"lightgray\",\n                          border_visible=False)\n        plot.overlays.append(label)\n        tool = DataLabelTool(label, drag_button=\"right\", auto_arrow_root=True)\n        label.tools.append(tool)\n\n        # Add some static labels.\n        label2 = DataLabel(component=plot, data_point=(x[20], y[20]),\n                           label_position=\"bottom right\",\n                           border_visible=False,\n                           bgcolor=\"transparent\",\n                           marker_color=\"blue\",\n                           marker_line_color=\"transparent\",\n                           marker=\"diamond\",\n                           font='modern 14',\n                           arrow_visible=False)\n        plot.overlays.append(label2)\n\n        label3 = DataLabel(component=plot, data_point=(x[80], y[80]),\n                           label_position=\"top\", padding_bottom=20,\n                           marker_color=\"transparent\",\n                           marker_size=8,\n                           marker=\"circle\",\n                           arrow_visible=False)\n        plot.overlays.append(label3)\n\n        # This label uses label_style='bubble'.\n        label4 = DataLabel(component=plot, data_point=(x[60], y[60]),\n                           border_padding=10,\n                           marker_color=\"red\",\n                           marker_size=3,\n                           label_position=(20, 50),\n                           label_style='bubble',\n                           label_text=\"Something interesting\",\n                           label_format=\"at x=%(x).2f, y=%(y).2f\",\n                           font='modern 18',\n                           bgcolor=(1, 1, 0.75, 1),\n                          )\n        plot.overlays.append(label4)\n        tool4 = DataLabelTool(label4, drag_button=\"right\",\n                              auto_arrow_root=True)\n        label4.tools.append(tool4)\n\n        # Another 'bubble' label.  This one sets arrow_min_length=20, so\n        # the arrow is not drawn when the label is close to the data point.\n        label5 = DataLabel(component=plot, data_point=(x[65], y[65]),\n                           border_padding=10,\n                           marker_color=\"green\",\n                           marker_size=4,\n                           show_label_coords=False,\n                           label_style='bubble',\n                           label_position=(25, 5),\n                           label_text=\"Label with\\narrow_min_length=20\",\n                           border_visible=False,\n                           arrow_min_length=20,\n                           font='modern 14',\n                           bgcolor=(0.75, 0.75, 0.75, 1),\n                          )\n        plot.overlays.append(label5)\n        tool5 = DataLabelTool(label5, drag_button=\"right\",\n                              auto_arrow_root=True)\n        label5.tools.append(tool5)\n\n        container.add(plot)\n\n        return container\n\ndemo = PlotExample()\n\nif __name__ == \"__main__\":\n    demo.configure_traits()\n", "path": "examples/demo/data_labels.py"}, {"content": "#!/usr/bin/env python\n\"\"\"\nAllows editing of a line plot.\n\nLeft-dragging a point will move its position.\n\nRight-drag pans the plot.\n\nMousewheel up and down zooms the plot in and out.\n\nPressing \"z\" brings up the Zoom Box, and you can click-drag a rectangular region to\nzoom.  If you use a sequence of zoom boxes, pressing alt-left-arrow and\nalt-right-arrow moves you forwards and backwards through the \"zoom history\".\n\"\"\"\n\n# Major library imports\nfrom numpy import linspace\nfrom scipy.special import jn\n\nfrom chaco.example_support import COLOR_PALETTE\n\n# Enthought library imports\nfrom enable.tools.api import DragTool\nfrom enable.api import Component, ComponentEditor\nfrom traits.api import HasTraits, Instance, Int, Tuple\nfrom traitsui.api import UItem, View\n\n# Chaco imports\nfrom chaco.api import add_default_axes, add_default_grids, \\\n        OverlayPlotContainer, PlotLabel, ScatterPlot, create_line_plot\nfrom chaco.tools.api import PanTool, ZoomTool\n\n\n\nclass PointDraggingTool(DragTool):\n\n    component = Instance(Component)\n\n    # The pixel distance from a point that the cursor is still considered\n    # to be 'on' the point\n    threshold = Int(5)\n\n    # The index of the point being dragged\n    _drag_index = Int(-1)\n\n    # The original dataspace values of the index and value datasources\n    # corresponding to _drag_index\n    _orig_value = Tuple\n\n    def is_draggable(self, x, y):\n        # Check to see if (x,y) are over one of the points in self.component\n        if self._lookup_point(x, y) is not None:\n            return True\n        else:\n            return False\n\n    def normal_mouse_move(self, event):\n        plot = self.component\n\n        ndx = plot.map_index((event.x, event.y), self.threshold)\n        if ndx is None:\n            if plot.index.metadata.has_key('selections'):\n                del plot.index.metadata['selections']\n        else:\n            plot.index.metadata['selections'] = [ndx]\n\n        plot.invalidate_draw()\n        plot.request_redraw()\n\n\n    def drag_start(self, event):\n        plot = self.component\n        ndx = plot.map_index((event.x, event.y), self.threshold)\n        if ndx is None:\n            return\n        self._drag_index = ndx\n        self._orig_value = (plot.index.get_data()[ndx], plot.value.get_data()[ndx])\n\n    def dragging(self, event):\n        plot = self.component\n\n        data_x, data_y = plot.map_data((event.x, event.y))\n\n        plot.index._data[self._drag_index] = data_x\n        plot.value._data[self._drag_index] = data_y\n        plot.index.data_changed = True\n        plot.value.data_changed = True\n        plot.request_redraw()\n\n    def drag_cancel(self, event):\n        plot = self.component\n        plot.index._data[self._drag_index] = self._orig_value[0]\n        plot.value._data[self._drag_index] = self._orig_value[1]\n        plot.index.data_changed = True\n        plot.value.data_changed = True\n        plot.request_redraw()\n\n    def drag_end(self, event):\n        plot = self.component\n        if plot.index.metadata.has_key('selections'):\n            del plot.index.metadata['selections']\n        plot.invalidate_draw()\n        plot.request_redraw()\n\n    def _lookup_point(self, x, y):\n        \"\"\" Finds the point closest to a screen point if it is within self.threshold\n\n        Parameters\n        ==========\n        x : float\n            screen x-coordinate\n        y : float\n            screen y-coordinate\n\n        Returns\n        =======\n        (screen_x, screen_y, distance) of datapoint nearest to the input *(x,y)*.\n        If no data points are within *self.threshold* of *(x,y)*, returns None.\n        \"\"\"\n\n        if hasattr(self.component, 'get_closest_point'):\n            # This is on BaseXYPlots\n            return self.component.get_closest_point((x,y), threshold=self.threshold)\n\n        return None\n\n\n#===============================================================================\n# # Create the Chaco plot.\n#===============================================================================\ndef _create_plot_component():\n\n    container = OverlayPlotContainer(padding = 50, fill_padding = True,\n                                     bgcolor = \"lightgray\", use_backbuffer=True)\n\n    # Create the initial X-series of data\n    numpoints = 30\n    low = -5\n    high = 15.0\n    x = linspace(low, high, numpoints)\n    y = jn(0, x)\n\n    lineplot = create_line_plot((x,y), color=tuple(COLOR_PALETTE[0]), width=2.0)\n    lineplot.selected_color = \"none\"\n    scatter = ScatterPlot(index = lineplot.index,\n                       value = lineplot.value,\n                       index_mapper = lineplot.index_mapper,\n                       value_mapper = lineplot.value_mapper,\n                       color = tuple(COLOR_PALETTE[0]),\n                       marker_size = 5)\n    scatter.index.sort_order = \"ascending\"\n\n    scatter.bgcolor = \"white\"\n    scatter.border_visible = True\n\n    add_default_grids(scatter)\n    add_default_axes(scatter)\n\n    scatter.tools.append(PanTool(scatter, drag_button=\"right\"))\n\n    # The ZoomTool tool is stateful and allows drawing a zoom\n    # box to select a zoom region.\n    zoom = ZoomTool(scatter, tool_mode=\"box\", always_on=False, drag_button=None)\n    scatter.overlays.append(zoom)\n\n    scatter.tools.append(PointDraggingTool(scatter))\n\n    container.add(lineplot)\n    container.add(scatter)\n\n    # Add the title at the top\n    container.overlays.append(PlotLabel(\"Line Editor\",\n                              component=container,\n                              font = \"swiss 16\",\n                              overlay_position=\"top\"))\n\n    return container\n\n\n#===============================================================================\n# Attributes to use for the plot view.\nsize=(800,700)\ntitle=\"Simple line plot\"\n\n#===============================================================================\n# # Demo class that is used by the demo.py application.\n#===============================================================================\nclass Demo(HasTraits):\n    plot = Instance(Component)\n\n    traits_view = View(UItem('plot', editor=ComponentEditor()),\n                       width=size[0], height=size[1], resizable=True,\n                       title=title\n                       )\n\n    def _plot_default(self):\n         return _create_plot_component()\n\ndemo = Demo()\n\nif __name__ == \"__main__\":\n    demo.configure_traits()\n\n#--EOF---\n", "path": "examples/demo/edit_line.py"}], "after_files": [{"content": "#!/usr/bin/env python\n\"\"\"\nDraws a line plot with several points labelled.  Demonstrates how to annotate\nplots.\n\nLeft-drag pans the plot.\n\nMousewheel up and down zooms the plot in and out.\n\nPressing \"z\" brings up the Zoom Box, and you can click-drag a rectangular\nregion to zoom.  If you use a sequence of zoom boxes, pressing control-y\nand control-z (Meta-y and Meta-z on Mac) moves you forwards and backwards\nthrough the \"zoom history\".\n\nRight-drag is enabled on some of the labels.\n\"\"\"\n\n# Major library imports\nfrom numpy import linspace\nfrom scipy.special import jn\n\n# Enthought library imports\nfrom enable.api import Component, ComponentEditor\nfrom traits.api import Float, HasTraits, Instance, Int\nfrom traitsui.api import Item, View\n\n# Chaco imports\nfrom chaco.api import create_line_plot, add_default_axes, add_default_grids, \\\n                      OverlayPlotContainer, DataLabel\nfrom chaco.example_support import COLOR_PALETTE\nfrom chaco.tools.api import PanTool, ZoomTool, DataLabelTool\n\n\nclass PlotExample(HasTraits):\n    plot = Instance(Component)\n    numpoints = Int(100)\n    low = Float(-5.0)\n    high = Float(15.0)\n\n    traits_view = View(Item('plot', editor=ComponentEditor(),\n                            show_label=False),\n                       width=800, height=700, resizable=True,\n                       title=\"Data label example\")\n\n    def _plot_default(self):\n\n        container = OverlayPlotContainer(padding=50, fill_padding=True,\n                                         bgcolor=\"lightgray\",\n                                         use_backbuffer=True)\n\n        # Create the initial X-series of data\n        numpoints = self.numpoints\n        low = self.low\n        high = self.high\n        x = linspace(low, high, numpoints + 1)\n        y = jn(0, x)\n        plot = create_line_plot((x, y), color=tuple(COLOR_PALETTE[0]),\n                                width=2.0)\n        plot.index.sort_order = \"ascending\"\n        plot.bgcolor = \"white\"\n        plot.border_visible = True\n        add_default_grids(plot)\n        add_default_axes(plot)\n\n        # Add some tools\n        plot.tools.append(PanTool(plot))\n        zoom = ZoomTool(plot, tool_mode=\"box\", always_on=False)\n        plot.overlays.append(zoom)\n\n        # Add a dynamic label.  This can be dragged and moved around using the\n        # right mouse button.  Note the use of padding to offset the label\n        # from its data point.\n        label = DataLabel(component=plot, data_point=(x[40], y[40]),\n                          label_position=\"top left\", padding=40,\n                          bgcolor=\"lightgray\",\n                          border_visible=False)\n        plot.overlays.append(label)\n        tool = DataLabelTool(label, drag_button=\"right\", auto_arrow_root=True)\n        label.tools.append(tool)\n\n        # Add some static labels.\n        label2 = DataLabel(component=plot, data_point=(x[20], y[20]),\n                           label_position=\"bottom right\",\n                           border_visible=False,\n                           bgcolor=\"transparent\",\n                           marker_color=\"blue\",\n                           marker_line_color=\"transparent\",\n                           marker=\"diamond\",\n                           font='modern 14',\n                           arrow_visible=False)\n        plot.overlays.append(label2)\n\n        label3 = DataLabel(component=plot, data_point=(x[80], y[80]),\n                           label_position=\"top\", padding_bottom=20,\n                           marker_color=\"transparent\",\n                           marker_size=8,\n                           marker=\"circle\",\n                           arrow_visible=False)\n        plot.overlays.append(label3)\n\n        # This label uses label_style='bubble'.\n        label4 = DataLabel(component=plot, data_point=(x[60], y[60]),\n                           border_padding=10,\n                           marker_color=\"red\",\n                           marker_size=3,\n                           label_position=(20, 50),\n                           label_style='bubble',\n                           label_text=\"Something interesting\",\n                           label_format=\"at x=%(x).2f, y=%(y).2f\",\n                           font='modern 18',\n                           bgcolor=(1, 1, 0.75, 1),\n                          )\n        plot.overlays.append(label4)\n        tool4 = DataLabelTool(label4, drag_button=\"right\",\n                              auto_arrow_root=True)\n        label4.tools.append(tool4)\n\n        # Another 'bubble' label.  This one sets arrow_min_length=20, so\n        # the arrow is not drawn when the label is close to the data point.\n        label5 = DataLabel(component=plot, data_point=(x[65], y[65]),\n                           border_padding=10,\n                           marker_color=\"green\",\n                           marker_size=4,\n                           show_label_coords=False,\n                           label_style='bubble',\n                           label_position=(25, 5),\n                           label_text=\"Label with\\narrow_min_length=20\",\n                           border_visible=False,\n                           arrow_min_length=20,\n                           font='modern 14',\n                           bgcolor=(0.75, 0.75, 0.75, 1),\n                          )\n        plot.overlays.append(label5)\n        tool5 = DataLabelTool(label5, drag_button=\"right\",\n                              auto_arrow_root=True)\n        label5.tools.append(tool5)\n\n        container.add(plot)\n\n        return container\n\ndemo = PlotExample()\n\nif __name__ == \"__main__\":\n    demo.configure_traits()\n", "path": "examples/demo/data_labels.py"}, {"content": "#!/usr/bin/env python\n\"\"\"\nAllows editing of a line plot.\n\nLeft-dragging a point will move its position.\n\nRight-drag pans the plot.\n\nMousewheel up and down zooms the plot in and out.\n\nPressing \"z\" brings up the Zoom Box, and you can click-drag a rectangular\nregion to zoom.  If you use a sequence of zoom boxes, pressing control-y and\ncontrol-z  (use Meta-y and Meta-z on Mac) moves you forwards and backwards\nthrough the \"zoom history\".\n\"\"\"\n\n# Major library imports\nfrom numpy import linspace\nfrom scipy.special import jn\n\nfrom chaco.example_support import COLOR_PALETTE\n\n# Enthought library imports\nfrom enable.tools.api import DragTool\nfrom enable.api import Component, ComponentEditor\nfrom traits.api import HasTraits, Instance, Int, Tuple\nfrom traitsui.api import UItem, View\n\n# Chaco imports\nfrom chaco.api import add_default_axes, add_default_grids, \\\n        OverlayPlotContainer, PlotLabel, ScatterPlot, create_line_plot\nfrom chaco.tools.api import PanTool, ZoomTool\n\n\n\nclass PointDraggingTool(DragTool):\n\n    component = Instance(Component)\n\n    # The pixel distance from a point that the cursor is still considered\n    # to be 'on' the point\n    threshold = Int(5)\n\n    # The index of the point being dragged\n    _drag_index = Int(-1)\n\n    # The original dataspace values of the index and value datasources\n    # corresponding to _drag_index\n    _orig_value = Tuple\n\n    def is_draggable(self, x, y):\n        # Check to see if (x,y) are over one of the points in self.component\n        if self._lookup_point(x, y) is not None:\n            return True\n        else:\n            return False\n\n    def normal_mouse_move(self, event):\n        plot = self.component\n\n        ndx = plot.map_index((event.x, event.y), self.threshold)\n        if ndx is None:\n            if plot.index.metadata.has_key('selections'):\n                del plot.index.metadata['selections']\n        else:\n            plot.index.metadata['selections'] = [ndx]\n\n        plot.invalidate_draw()\n        plot.request_redraw()\n\n\n    def drag_start(self, event):\n        plot = self.component\n        ndx = plot.map_index((event.x, event.y), self.threshold)\n        if ndx is None:\n            return\n        self._drag_index = ndx\n        self._orig_value = (plot.index.get_data()[ndx], plot.value.get_data()[ndx])\n\n    def dragging(self, event):\n        plot = self.component\n\n        data_x, data_y = plot.map_data((event.x, event.y))\n\n        plot.index._data[self._drag_index] = data_x\n        plot.value._data[self._drag_index] = data_y\n        plot.index.data_changed = True\n        plot.value.data_changed = True\n        plot.request_redraw()\n\n    def drag_cancel(self, event):\n        plot = self.component\n        plot.index._data[self._drag_index] = self._orig_value[0]\n        plot.value._data[self._drag_index] = self._orig_value[1]\n        plot.index.data_changed = True\n        plot.value.data_changed = True\n        plot.request_redraw()\n\n    def drag_end(self, event):\n        plot = self.component\n        if plot.index.metadata.has_key('selections'):\n            del plot.index.metadata['selections']\n        plot.invalidate_draw()\n        plot.request_redraw()\n\n    def _lookup_point(self, x, y):\n        \"\"\" Finds the point closest to a screen point if it is within self.threshold\n\n        Parameters\n        ==========\n        x : float\n            screen x-coordinate\n        y : float\n            screen y-coordinate\n\n        Returns\n        =======\n        (screen_x, screen_y, distance) of datapoint nearest to the input *(x,y)*.\n        If no data points are within *self.threshold* of *(x,y)*, returns None.\n        \"\"\"\n\n        if hasattr(self.component, 'get_closest_point'):\n            # This is on BaseXYPlots\n            return self.component.get_closest_point((x,y), threshold=self.threshold)\n\n        return None\n\n\n#===============================================================================\n# # Create the Chaco plot.\n#===============================================================================\ndef _create_plot_component():\n\n    container = OverlayPlotContainer(padding = 50, fill_padding = True,\n                                     bgcolor = \"lightgray\", use_backbuffer=True)\n\n    # Create the initial X-series of data\n    numpoints = 30\n    low = -5\n    high = 15.0\n    x = linspace(low, high, numpoints)\n    y = jn(0, x)\n\n    lineplot = create_line_plot((x,y), color=tuple(COLOR_PALETTE[0]), width=2.0)\n    lineplot.selected_color = \"none\"\n    scatter = ScatterPlot(index = lineplot.index,\n                       value = lineplot.value,\n                       index_mapper = lineplot.index_mapper,\n                       value_mapper = lineplot.value_mapper,\n                       color = tuple(COLOR_PALETTE[0]),\n                       marker_size = 5)\n    scatter.index.sort_order = \"ascending\"\n\n    scatter.bgcolor = \"white\"\n    scatter.border_visible = True\n\n    add_default_grids(scatter)\n    add_default_axes(scatter)\n\n    scatter.tools.append(PanTool(scatter, drag_button=\"right\"))\n\n    # The ZoomTool tool is stateful and allows drawing a zoom\n    # box to select a zoom region.\n    zoom = ZoomTool(scatter, tool_mode=\"box\", always_on=False)\n    scatter.overlays.append(zoom)\n\n    scatter.tools.append(PointDraggingTool(scatter))\n\n    container.add(lineplot)\n    container.add(scatter)\n\n    # Add the title at the top\n    container.overlays.append(PlotLabel(\"Line Editor\",\n                              component=container,\n                              font = \"swiss 16\",\n                              overlay_position=\"top\"))\n\n    return container\n\n\n#===============================================================================\n# Attributes to use for the plot view.\nsize=(800,700)\ntitle=\"Simple line plot\"\n\n#===============================================================================\n# # Demo class that is used by the demo.py application.\n#===============================================================================\nclass Demo(HasTraits):\n    plot = Instance(Component)\n\n    traits_view = View(UItem('plot', editor=ComponentEditor()),\n                       width=size[0], height=size[1], resizable=True,\n                       title=title\n                       )\n\n    def _plot_default(self):\n         return _create_plot_component()\n\ndemo = Demo()\n\nif __name__ == \"__main__\":\n    demo.configure_traits()\n\n#--EOF---\n", "path": "examples/demo/edit_line.py"}]}