We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
TypeError when running stock prices examples
This error was discovered when running the `examples/demo/financial/stock_prices.py` example.

In order to reproduce, simply load the example and start zooming out. This was observed on python 3.6 with wx toolkit.

```
>python stock_prices.py
c:\users\rporuri\work\github\ets\enable\kiva\agg\plat_support.py:188: wxPyDeprecationWarning: Call to deprecated item. Use GetHandle instead.
  self.draw(window_dc.GetHDC(), x, y, width, height)
Exception occurred in traits notification handler for event object: TraitChangeEvent(object=<chaco.data_range_1d.DataRange1D object at 0x000001C06339C518>, name='updated', old=<undefined>, new=(1614674109.0105073, 1657874109.0105073))
Traceback (most recent call last):
  File "C:\Users\rporuri\.edm\envs\enable-test-3.6-wx\lib\site-packages\traits\observation\_trait_event_notifier.py", line 122, in __call__
    self.dispatcher(handler, event)
  File "C:\Users\rporuri\.edm\envs\enable-test-3.6-wx\lib\site-packages\traits\observation\observe.py", line 26, in dispatch_same
    handler(event)
  File "stock_prices.py", line 147, in _plot_range_handler
    low, high = event
TypeError: 'TraitChangeEvent' object is not iterable
Exception occurred in traits notification handler for event object: TraitChangeEvent(object=<chaco.data_range_1d.DataRange1D object at 0x000001C06339C518>, name='updated', old=<undefined>, new=(1593074109.0105073, 1679474109.0105073))
Traceback (most recent call last):
  File "C:\Users\rporuri\.edm\envs\enable-test-3.6-wx\lib\site-packages\traits\observation\_trait_event_notifier.py", line 122, in __call__
    self.dispatcher(handler, event)
  File "C:\Users\rporuri\.edm\envs\enable-test-3.6-wx\lib\site-packages\traits\observation\observe.py", line 26, in dispatch_same
    handler(event)
  File "stock_prices.py", line 147, in _plot_range_handler
    low, high = event
TypeError: 'TraitChangeEvent' object is not iterable
```

--- 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/financial/stock_prices.py`
Content:
```
1 """
2 Implementation of a standard financial plot visualization using Chaco
3 renderers and scales.
4 
5 In the main price plot area, mouse wheel zooms and mouse drag pans (if
6 the plot is not at the edge of the time series data).  In the bottom
7 overview plot area, right-click-drag selects a range of times to display
8 on the top two plots.  Once a region is selected, it can be moved
9 around by left-dragging or resized by left-dragging one of its
10 edges.
11 """
12 
13 # Major library imports
14 from numpy import abs, cumprod, linspace, random
15 import time
16 
17 from enable.example_support import DemoFrame, demo_main
18 
19 # Enthought library imports
20 from enable.api import Window
21 
22 # Chaco imports
23 from chaco.api import (
24     ArrayDataSource,
25     BarPlot,
26     DataRange1D,
27     LinePlot,
28     LinearMapper,
29     VPlotContainer,
30     PlotAxis,
31     FilledLinePlot,
32     add_default_grids,
33 )
34 from chaco.tools.api import (
35     PanTool,
36     ZoomTool,
37     RangeSelection,
38     RangeSelectionOverlay,
39 )
40 
41 from chaco.scales.api import CalendarScaleSystem
42 from chaco.scales_tick_generator import ScalesTickGenerator
43 
44 
45 def create_dates(numpoints, units="days"):
46     """Returns **numpoints** number of dates that evenly bracket the current
47     date and time.  **units** should be one of "weeks", "days", "hours"
48     "minutes", or "seconds".
49     """
50     units_map = {
51         "weeks": 7 * 24 * 3600,
52         "days": 24 * 3600,
53         "hours": 3600,
54         "minutes": 60,
55         "seconds": 1,
56     }
57     now = time.time()
58     dt = units_map[units]
59     dates = linspace(now, now + numpoints * dt, numpoints)
60     return dates
61 
62 
63 class PlotFrame(DemoFrame):
64     def _create_price_plots(self, times, prices, mini_height=75):
65         """Creates the two plots of prices and returns them.  One of the
66         plots can be zoomed and panned, and the other plot (smaller) always
67         shows the full data.
68 
69         *dates* and *prices* are two data sources.
70         """
71 
72         # Create the price plot
73         price_plot = FilledLinePlot(
74             index=times,
75             value=prices,
76             index_mapper=LinearMapper(range=DataRange1D(times)),
77             value_mapper=LinearMapper(range=DataRange1D(prices)),
78             edge_color="blue",
79             face_color="paleturquoise",
80             bgcolor="white",
81             border_visible=True,
82         )
83 
84         # Add pan and zoom
85         price_plot.tools.append(
86             PanTool(
87                 price_plot,
88                 constrain=True,
89                 constrain_direction="x",
90                 restrict_to_data=True,
91             )
92         )
93         price_plot.overlays.append(
94             ZoomTool(
95                 price_plot,
96                 drag_button="right",
97                 always_on=True,
98                 tool_mode="range",
99                 axis="index",
100                 max_zoom_out_factor=1.0,
101                 x_min_zoom_factor=float(1e-3),
102             )
103         )
104 
105         # Create the miniplot
106         miniplot = LinePlot(
107             index=times,
108             value=prices,
109             index_mapper=LinearMapper(range=DataRange1D(times)),
110             value_mapper=LinearMapper(range=DataRange1D(prices)),
111             color="black",
112             border_visible=True,
113             bgcolor="white",
114             height=mini_height,
115             resizable="h",
116         )
117 
118         # Add a range overlay to the miniplot that is hooked up to the range
119         # of the main price_plot
120         range_tool = RangeSelection(miniplot)
121         miniplot.tools.append(range_tool)
122         range_overlay = RangeSelectionOverlay(
123             miniplot, metadata_name="selections"
124         )
125         miniplot.overlays.append(range_overlay)
126         range_tool.observe(self._range_selection_handler, "selection")
127 
128         # Attach a handler that sets the tool when the plot's index range changes
129         self.range_tool = range_tool
130         price_plot.index_range.observe(self._plot_range_handler, "updated")
131 
132         return price_plot, miniplot
133 
134     def _range_selection_handler(self, event):
135         range_selection_event = event.new
136         # The event obj should be a tuple (low, high) in data space
137         if range_selection_event is not None:
138             low, high = range_selection_event
139             self.price_plot.index_range.low = low
140             self.price_plot.index_range.high = high
141         else:
142             self.price_plot.index_range.set_bounds("auto", "auto")
143 
144     def _plot_range_handler(self, event):
145         plot_range_event = event.new
146         if plot_range_event is not None:
147             low, high = event
148             if "auto" not in (low, high):
149                 self.range_tool.selection = (low, high)
150 
151     def _create_vol_plot(self, times, volumes, height=100):
152         "Creates and returns the volume plot"
153         index_range = self.price_plot.index_range
154         vol_plot = BarPlot(
155             index=times,
156             value=volumes,
157             index_mapper=LinearMapper(range=index_range),
158             value_mapper=LinearMapper(range=DataRange1D(volumes)),
159             line_color="transparent",
160             fill_color="black",
161             bar_width=1.0,
162             bar_width_type="screen",
163             antialias=False,
164             height=100,
165             resizable="h",
166             bgcolor="white",
167             border_visible=True,
168         )
169         vol_plot.tools.append(
170             PanTool(vol_plot, constrain=True, constrain_direction="x")
171         )
172         return vol_plot
173 
174     def _create_component(self):
175 
176         # Create the data and datasource objects
177         # In order for the date axis to work, the index data points need to
178         # be in units of seconds since the epoch.  This is because we are using
179         # the CalendarScaleSystem, whose formatters interpret the numerical values
180         # as seconds since the epoch.
181         numpoints = 500
182         index = create_dates(numpoints)
183         returns = random.lognormal(0.01, 0.1, size=numpoints)
184         price = 100.0 * cumprod(returns)
185         volume = abs(random.normal(1000.0, 1500.0, size=numpoints) + 2000.0)
186 
187         time_ds = ArrayDataSource(index)
188         vol_ds = ArrayDataSource(volume, sort_order="none")
189         price_ds = ArrayDataSource(price, sort_order="none")
190 
191         # Create the price plots
192         price_plot, mini_plot = self._create_price_plots(time_ds, price_ds)
193         price_plot.index_mapper.domain_limits = (index[0], index[-1])
194         self.price_plot = price_plot
195         self.mini_plot = mini_plot
196 
197         # Create the volume plot
198         vol_plot = self._create_vol_plot(time_ds, vol_ds)
199         vol_plot.index_mapper.domain_limits = (index[0], index[-1])
200 
201         # Set the plot's bottom axis to use the Scales ticking system
202         ticker = ScalesTickGenerator(scale=CalendarScaleSystem())
203         for plot in price_plot, mini_plot, vol_plot:
204             bottom_axis = PlotAxis(
205                 plot, orientation="bottom", tick_generator=ticker
206             )
207             plot.overlays.append(bottom_axis)
208             plot.overlays.append(PlotAxis(plot, orientation="left"))
209             hgrid, vgrid = add_default_grids(plot)
210             vgrid.tick_generator = bottom_axis.tick_generator
211 
212         container = VPlotContainer(
213             bgcolor="lightgray", spacing=40, padding=50, fill_padding=False
214         )
215         container.add(mini_plot, vol_plot, price_plot)
216 
217         return container
218 
219 
220 if __name__ == "__main__":
221     # Save demo so that it doesn't get garbage collected when run within
222     # existing event loop (i.e. from ipython).
223     demo = demo_main(
224         PlotFrame, size=(800, 600), title="Stock price and volume"
225     )
226
```
--- 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/financial/stock_prices.py b/examples/demo/financial/stock_prices.py
--- a/examples/demo/financial/stock_prices.py
+++ b/examples/demo/financial/stock_prices.py
@@ -144,7 +144,7 @@
     def _plot_range_handler(self, event):
         plot_range_event = event.new
         if plot_range_event is not None:
-            low, high = event
+            low, high = plot_range_event
             if "auto" not in (low, high):
                 self.range_tool.selection = (low, high)

{"golden_diff": "diff --git a/examples/demo/financial/stock_prices.py b/examples/demo/financial/stock_prices.py\n--- a/examples/demo/financial/stock_prices.py\n+++ b/examples/demo/financial/stock_prices.py\n@@ -144,7 +144,7 @@\n     def _plot_range_handler(self, event):\n         plot_range_event = event.new\n         if plot_range_event is not None:\n-            low, high = event\n+            low, high = plot_range_event\n             if \"auto\" not in (low, high):\n                 self.range_tool.selection = (low, high)\n", "issue": "TypeError when running stock prices examples\nThis error was discovered when running the `examples/demo/financial/stock_prices.py` example.\r\n\r\nIn order to reproduce, simply load the example and start zooming out. This was observed on python 3.6 with wx toolkit.\r\n\r\n```\r\n>python stock_prices.py\r\nc:\\users\\rporuri\\work\\github\\ets\\enable\\kiva\\agg\\plat_support.py:188: wxPyDeprecationWarning: Call to deprecated item. Use GetHandle instead.\r\n  self.draw(window_dc.GetHDC(), x, y, width, height)\r\nException occurred in traits notification handler for event object: TraitChangeEvent(object=<chaco.data_range_1d.DataRange1D object at 0x000001C06339C518>, name='updated', old=<undefined>, new=(1614674109.0105073, 1657874109.0105073))\r\nTraceback (most recent call last):\r\n  File \"C:\\Users\\rporuri\\.edm\\envs\\enable-test-3.6-wx\\lib\\site-packages\\traits\\observation\\_trait_event_notifier.py\", line 122, in __call__\r\n    self.dispatcher(handler, event)\r\n  File \"C:\\Users\\rporuri\\.edm\\envs\\enable-test-3.6-wx\\lib\\site-packages\\traits\\observation\\observe.py\", line 26, in dispatch_same\r\n    handler(event)\r\n  File \"stock_prices.py\", line 147, in _plot_range_handler\r\n    low, high = event\r\nTypeError: 'TraitChangeEvent' object is not iterable\r\nException occurred in traits notification handler for event object: TraitChangeEvent(object=<chaco.data_range_1d.DataRange1D object at 0x000001C06339C518>, name='updated', old=<undefined>, new=(1593074109.0105073, 1679474109.0105073))\r\nTraceback (most recent call last):\r\n  File \"C:\\Users\\rporuri\\.edm\\envs\\enable-test-3.6-wx\\lib\\site-packages\\traits\\observation\\_trait_event_notifier.py\", line 122, in __call__\r\n    self.dispatcher(handler, event)\r\n  File \"C:\\Users\\rporuri\\.edm\\envs\\enable-test-3.6-wx\\lib\\site-packages\\traits\\observation\\observe.py\", line 26, in dispatch_same\r\n    handler(event)\r\n  File \"stock_prices.py\", line 147, in _plot_range_handler\r\n    low, high = event\r\nTypeError: 'TraitChangeEvent' object is not iterable\r\n```\n", "before_files": [{"content": "\"\"\"\nImplementation of a standard financial plot visualization using Chaco\nrenderers and scales.\n\nIn the main price plot area, mouse wheel zooms and mouse drag pans (if\nthe plot is not at the edge of the time series data).  In the bottom\noverview plot area, right-click-drag selects a range of times to display\non the top two plots.  Once a region is selected, it can be moved\naround by left-dragging or resized by left-dragging one of its\nedges.\n\"\"\"\n\n# Major library imports\nfrom numpy import abs, cumprod, linspace, random\nimport time\n\nfrom enable.example_support import DemoFrame, demo_main\n\n# Enthought library imports\nfrom enable.api import Window\n\n# Chaco imports\nfrom chaco.api import (\n    ArrayDataSource,\n    BarPlot,\n    DataRange1D,\n    LinePlot,\n    LinearMapper,\n    VPlotContainer,\n    PlotAxis,\n    FilledLinePlot,\n    add_default_grids,\n)\nfrom chaco.tools.api import (\n    PanTool,\n    ZoomTool,\n    RangeSelection,\n    RangeSelectionOverlay,\n)\n\nfrom chaco.scales.api import CalendarScaleSystem\nfrom chaco.scales_tick_generator import ScalesTickGenerator\n\n\ndef create_dates(numpoints, units=\"days\"):\n    \"\"\"Returns **numpoints** number of dates that evenly bracket the current\n    date and time.  **units** should be one of \"weeks\", \"days\", \"hours\"\n    \"minutes\", or \"seconds\".\n    \"\"\"\n    units_map = {\n        \"weeks\": 7 * 24 * 3600,\n        \"days\": 24 * 3600,\n        \"hours\": 3600,\n        \"minutes\": 60,\n        \"seconds\": 1,\n    }\n    now = time.time()\n    dt = units_map[units]\n    dates = linspace(now, now + numpoints * dt, numpoints)\n    return dates\n\n\nclass PlotFrame(DemoFrame):\n    def _create_price_plots(self, times, prices, mini_height=75):\n        \"\"\"Creates the two plots of prices and returns them.  One of the\n        plots can be zoomed and panned, and the other plot (smaller) always\n        shows the full data.\n\n        *dates* and *prices* are two data sources.\n        \"\"\"\n\n        # Create the price plot\n        price_plot = FilledLinePlot(\n            index=times,\n            value=prices,\n            index_mapper=LinearMapper(range=DataRange1D(times)),\n            value_mapper=LinearMapper(range=DataRange1D(prices)),\n            edge_color=\"blue\",\n            face_color=\"paleturquoise\",\n            bgcolor=\"white\",\n            border_visible=True,\n        )\n\n        # Add pan and zoom\n        price_plot.tools.append(\n            PanTool(\n                price_plot,\n                constrain=True,\n                constrain_direction=\"x\",\n                restrict_to_data=True,\n            )\n        )\n        price_plot.overlays.append(\n            ZoomTool(\n                price_plot,\n                drag_button=\"right\",\n                always_on=True,\n                tool_mode=\"range\",\n                axis=\"index\",\n                max_zoom_out_factor=1.0,\n                x_min_zoom_factor=float(1e-3),\n            )\n        )\n\n        # Create the miniplot\n        miniplot = LinePlot(\n            index=times,\n            value=prices,\n            index_mapper=LinearMapper(range=DataRange1D(times)),\n            value_mapper=LinearMapper(range=DataRange1D(prices)),\n            color=\"black\",\n            border_visible=True,\n            bgcolor=\"white\",\n            height=mini_height,\n            resizable=\"h\",\n        )\n\n        # Add a range overlay to the miniplot that is hooked up to the range\n        # of the main price_plot\n        range_tool = RangeSelection(miniplot)\n        miniplot.tools.append(range_tool)\n        range_overlay = RangeSelectionOverlay(\n            miniplot, metadata_name=\"selections\"\n        )\n        miniplot.overlays.append(range_overlay)\n        range_tool.observe(self._range_selection_handler, \"selection\")\n\n        # Attach a handler that sets the tool when the plot's index range changes\n        self.range_tool = range_tool\n        price_plot.index_range.observe(self._plot_range_handler, \"updated\")\n\n        return price_plot, miniplot\n\n    def _range_selection_handler(self, event):\n        range_selection_event = event.new\n        # The event obj should be a tuple (low, high) in data space\n        if range_selection_event is not None:\n            low, high = range_selection_event\n            self.price_plot.index_range.low = low\n            self.price_plot.index_range.high = high\n        else:\n            self.price_plot.index_range.set_bounds(\"auto\", \"auto\")\n\n    def _plot_range_handler(self, event):\n        plot_range_event = event.new\n        if plot_range_event is not None:\n            low, high = event\n            if \"auto\" not in (low, high):\n                self.range_tool.selection = (low, high)\n\n    def _create_vol_plot(self, times, volumes, height=100):\n        \"Creates and returns the volume plot\"\n        index_range = self.price_plot.index_range\n        vol_plot = BarPlot(\n            index=times,\n            value=volumes,\n            index_mapper=LinearMapper(range=index_range),\n            value_mapper=LinearMapper(range=DataRange1D(volumes)),\n            line_color=\"transparent\",\n            fill_color=\"black\",\n            bar_width=1.0,\n            bar_width_type=\"screen\",\n            antialias=False,\n            height=100,\n            resizable=\"h\",\n            bgcolor=\"white\",\n            border_visible=True,\n        )\n        vol_plot.tools.append(\n            PanTool(vol_plot, constrain=True, constrain_direction=\"x\")\n        )\n        return vol_plot\n\n    def _create_component(self):\n\n        # Create the data and datasource objects\n        # In order for the date axis to work, the index data points need to\n        # be in units of seconds since the epoch.  This is because we are using\n        # the CalendarScaleSystem, whose formatters interpret the numerical values\n        # as seconds since the epoch.\n        numpoints = 500\n        index = create_dates(numpoints)\n        returns = random.lognormal(0.01, 0.1, size=numpoints)\n        price = 100.0 * cumprod(returns)\n        volume = abs(random.normal(1000.0, 1500.0, size=numpoints) + 2000.0)\n\n        time_ds = ArrayDataSource(index)\n        vol_ds = ArrayDataSource(volume, sort_order=\"none\")\n        price_ds = ArrayDataSource(price, sort_order=\"none\")\n\n        # Create the price plots\n        price_plot, mini_plot = self._create_price_plots(time_ds, price_ds)\n        price_plot.index_mapper.domain_limits = (index[0], index[-1])\n        self.price_plot = price_plot\n        self.mini_plot = mini_plot\n\n        # Create the volume plot\n        vol_plot = self._create_vol_plot(time_ds, vol_ds)\n        vol_plot.index_mapper.domain_limits = (index[0], index[-1])\n\n        # Set the plot's bottom axis to use the Scales ticking system\n        ticker = ScalesTickGenerator(scale=CalendarScaleSystem())\n        for plot in price_plot, mini_plot, vol_plot:\n            bottom_axis = PlotAxis(\n                plot, orientation=\"bottom\", tick_generator=ticker\n            )\n            plot.overlays.append(bottom_axis)\n            plot.overlays.append(PlotAxis(plot, orientation=\"left\"))\n            hgrid, vgrid = add_default_grids(plot)\n            vgrid.tick_generator = bottom_axis.tick_generator\n\n        container = VPlotContainer(\n            bgcolor=\"lightgray\", spacing=40, padding=50, fill_padding=False\n        )\n        container.add(mini_plot, vol_plot, price_plot)\n\n        return container\n\n\nif __name__ == \"__main__\":\n    # Save demo so that it doesn't get garbage collected when run within\n    # existing event loop (i.e. from ipython).\n    demo = demo_main(\n        PlotFrame, size=(800, 600), title=\"Stock price and volume\"\n    )\n", "path": "examples/demo/financial/stock_prices.py"}], "after_files": [{"content": "\"\"\"\nImplementation of a standard financial plot visualization using Chaco\nrenderers and scales.\n\nIn the main price plot area, mouse wheel zooms and mouse drag pans (if\nthe plot is not at the edge of the time series data).  In the bottom\noverview plot area, right-click-drag selects a range of times to display\non the top two plots.  Once a region is selected, it can be moved\naround by left-dragging or resized by left-dragging one of its\nedges.\n\"\"\"\n\n# Major library imports\nfrom numpy import abs, cumprod, linspace, random\nimport time\n\nfrom enable.example_support import DemoFrame, demo_main\n\n# Enthought library imports\nfrom enable.api import Window\n\n# Chaco imports\nfrom chaco.api import (\n    ArrayDataSource,\n    BarPlot,\n    DataRange1D,\n    LinePlot,\n    LinearMapper,\n    VPlotContainer,\n    PlotAxis,\n    FilledLinePlot,\n    add_default_grids,\n)\nfrom chaco.tools.api import (\n    PanTool,\n    ZoomTool,\n    RangeSelection,\n    RangeSelectionOverlay,\n)\n\nfrom chaco.scales.api import CalendarScaleSystem\nfrom chaco.scales_tick_generator import ScalesTickGenerator\n\n\ndef create_dates(numpoints, units=\"days\"):\n    \"\"\"Returns **numpoints** number of dates that evenly bracket the current\n    date and time.  **units** should be one of \"weeks\", \"days\", \"hours\"\n    \"minutes\", or \"seconds\".\n    \"\"\"\n    units_map = {\n        \"weeks\": 7 * 24 * 3600,\n        \"days\": 24 * 3600,\n        \"hours\": 3600,\n        \"minutes\": 60,\n        \"seconds\": 1,\n    }\n    now = time.time()\n    dt = units_map[units]\n    dates = linspace(now, now + numpoints * dt, numpoints)\n    return dates\n\n\nclass PlotFrame(DemoFrame):\n    def _create_price_plots(self, times, prices, mini_height=75):\n        \"\"\"Creates the two plots of prices and returns them.  One of the\n        plots can be zoomed and panned, and the other plot (smaller) always\n        shows the full data.\n\n        *dates* and *prices* are two data sources.\n        \"\"\"\n\n        # Create the price plot\n        price_plot = FilledLinePlot(\n            index=times,\n            value=prices,\n            index_mapper=LinearMapper(range=DataRange1D(times)),\n            value_mapper=LinearMapper(range=DataRange1D(prices)),\n            edge_color=\"blue\",\n            face_color=\"paleturquoise\",\n            bgcolor=\"white\",\n            border_visible=True,\n        )\n\n        # Add pan and zoom\n        price_plot.tools.append(\n            PanTool(\n                price_plot,\n                constrain=True,\n                constrain_direction=\"x\",\n                restrict_to_data=True,\n            )\n        )\n        price_plot.overlays.append(\n            ZoomTool(\n                price_plot,\n                drag_button=\"right\",\n                always_on=True,\n                tool_mode=\"range\",\n                axis=\"index\",\n                max_zoom_out_factor=1.0,\n                x_min_zoom_factor=float(1e-3),\n            )\n        )\n\n        # Create the miniplot\n        miniplot = LinePlot(\n            index=times,\n            value=prices,\n            index_mapper=LinearMapper(range=DataRange1D(times)),\n            value_mapper=LinearMapper(range=DataRange1D(prices)),\n            color=\"black\",\n            border_visible=True,\n            bgcolor=\"white\",\n            height=mini_height,\n            resizable=\"h\",\n        )\n\n        # Add a range overlay to the miniplot that is hooked up to the range\n        # of the main price_plot\n        range_tool = RangeSelection(miniplot)\n        miniplot.tools.append(range_tool)\n        range_overlay = RangeSelectionOverlay(\n            miniplot, metadata_name=\"selections\"\n        )\n        miniplot.overlays.append(range_overlay)\n        range_tool.observe(self._range_selection_handler, \"selection\")\n\n        # Attach a handler that sets the tool when the plot's index range changes\n        self.range_tool = range_tool\n        price_plot.index_range.observe(self._plot_range_handler, \"updated\")\n\n        return price_plot, miniplot\n\n    def _range_selection_handler(self, event):\n        range_selection_event = event.new\n        # The event obj should be a tuple (low, high) in data space\n        if range_selection_event is not None:\n            low, high = range_selection_event\n            self.price_plot.index_range.low = low\n            self.price_plot.index_range.high = high\n        else:\n            self.price_plot.index_range.set_bounds(\"auto\", \"auto\")\n\n    def _plot_range_handler(self, event):\n        plot_range_event = event.new\n        if plot_range_event is not None:\n            low, high = plot_range_event\n            if \"auto\" not in (low, high):\n                self.range_tool.selection = (low, high)\n\n    def _create_vol_plot(self, times, volumes, height=100):\n        \"Creates and returns the volume plot\"\n        index_range = self.price_plot.index_range\n        vol_plot = BarPlot(\n            index=times,\n            value=volumes,\n            index_mapper=LinearMapper(range=index_range),\n            value_mapper=LinearMapper(range=DataRange1D(volumes)),\n            line_color=\"transparent\",\n            fill_color=\"black\",\n            bar_width=1.0,\n            bar_width_type=\"screen\",\n            antialias=False,\n            height=100,\n            resizable=\"h\",\n            bgcolor=\"white\",\n            border_visible=True,\n        )\n        vol_plot.tools.append(\n            PanTool(vol_plot, constrain=True, constrain_direction=\"x\")\n        )\n        return vol_plot\n\n    def _create_component(self):\n\n        # Create the data and datasource objects\n        # In order for the date axis to work, the index data points need to\n        # be in units of seconds since the epoch.  This is because we are using\n        # the CalendarScaleSystem, whose formatters interpret the numerical values\n        # as seconds since the epoch.\n        numpoints = 500\n        index = create_dates(numpoints)\n        returns = random.lognormal(0.01, 0.1, size=numpoints)\n        price = 100.0 * cumprod(returns)\n        volume = abs(random.normal(1000.0, 1500.0, size=numpoints) + 2000.0)\n\n        time_ds = ArrayDataSource(index)\n        vol_ds = ArrayDataSource(volume, sort_order=\"none\")\n        price_ds = ArrayDataSource(price, sort_order=\"none\")\n\n        # Create the price plots\n        price_plot, mini_plot = self._create_price_plots(time_ds, price_ds)\n        price_plot.index_mapper.domain_limits = (index[0], index[-1])\n        self.price_plot = price_plot\n        self.mini_plot = mini_plot\n\n        # Create the volume plot\n        vol_plot = self._create_vol_plot(time_ds, vol_ds)\n        vol_plot.index_mapper.domain_limits = (index[0], index[-1])\n\n        # Set the plot's bottom axis to use the Scales ticking system\n        ticker = ScalesTickGenerator(scale=CalendarScaleSystem())\n        for plot in price_plot, mini_plot, vol_plot:\n            bottom_axis = PlotAxis(\n                plot, orientation=\"bottom\", tick_generator=ticker\n            )\n            plot.overlays.append(bottom_axis)\n            plot.overlays.append(PlotAxis(plot, orientation=\"left\"))\n            hgrid, vgrid = add_default_grids(plot)\n            vgrid.tick_generator = bottom_axis.tick_generator\n\n        container = VPlotContainer(\n            bgcolor=\"lightgray\", spacing=40, padding=50, fill_padding=False\n        )\n        container.add(mini_plot, vol_plot, price_plot)\n\n        return container\n\n\nif __name__ == \"__main__\":\n    # Save demo so that it doesn't get garbage collected when run within\n    # existing event loop (i.e. from ipython).\n    demo = demo_main(\n        PlotFrame, size=(800, 600), title=\"Stock price and volume\"\n    )\n", "path": "examples/demo/financial/stock_prices.py"}]}