Browse code

update pre-commit filter versions

Bas Nijholt authored on 07/08/2020 13:31:33
Showing 1 changed files
... ...
@@ -64,8 +64,8 @@ def ensure_plotly():
64 64
         import plotly
65 65
 
66 66
         if not _plotly_enabled:
67
-            import plotly.graph_objs
68 67
             import plotly.figure_factory
68
+            import plotly.graph_objs
69 69
             import plotly.offline
70 70
 
71 71
             # This injects javascript and should happen only once
Browse code

join strings

Bas Nijholt authored on 12/05/2020 15:34:25
Showing 1 changed files
... ...
@@ -31,7 +31,7 @@ def notebook_extension(*, _inline_js=True):
31 31
             _holoviews_enabled = True
32 32
     except ModuleNotFoundError:
33 33
         warnings.warn(
34
-            "holoviews is not installed; plotting " "is disabled.", RuntimeWarning
34
+            "holoviews is not installed; plotting is disabled.", RuntimeWarning
35 35
         )
36 36
 
37 37
     # Load ipywidgets
... ...
@@ -42,7 +42,7 @@ def notebook_extension(*, _inline_js=True):
42 42
             _ipywidgets_enabled = True
43 43
     except ModuleNotFoundError:
44 44
         warnings.warn(
45
-            "ipywidgets is not installed; live_info " "is disabled.", RuntimeWarning
45
+            "ipywidgets is not installed; live_info is disabled.", RuntimeWarning
46 46
         )
47 47
 
48 48
     # Enable asyncio integration
Browse code

simplify _table_row in notebook_integration.py

Bas Nijholt authored on 19/12/2019 09:39:59
Showing 1 changed files
... ...
@@ -233,11 +233,10 @@ def live_info(runner, *, update_interval=0.5):
233 233
 
234 234
 def _table_row(i, key, value):
235 235
     """Style the rows of a table. Based on the default Jupyterlab table style."""
236
-    style_odd = "text-align: right; padding: 0.5em 0.5em; line-height: 1.0;"
237
-    style_even = style_odd + "background: var(--md-grey-100);"
238
-    template = '<tr><th style="{style}">{key}</th><th style="{style}">{value}</th></tr>'
239
-    style = style_odd if i % 2 == 1 else style_even
240
-    return template.format(style=style, key=key, value=value)
236
+    style = "text-align: right; padding: 0.5em 0.5em; line-height: 1.0;"
237
+    if i % 2 == 1:
238
+        style += " background: var(--md-grey-100);"
239
+    return f'<tr><th style="{style}">{key}</th><th style="{style}">{value}</th></tr>'
241 240
 
242 241
 
243 242
 def _info_html(runner):
Browse code

color the overhead between red and green (#252)

color the overhead between red and green

Bas Nijholt authored on 18/12/2019 18:26:30 • Joseph Weston committed on 18/12/2019 18:26:30
Showing 1 changed files
... ...
@@ -250,10 +250,14 @@ def _info_html(runner):
250 250
         "finished": "green",
251 251
     }[status]
252 252
 
253
+    overhead = runner.overhead()
254
+    red_level = max(0, min(int(255 * overhead / 100), 255))
255
+    overhead_color = "#{:02x}{:02x}{:02x}".format(red_level, 255 - red_level, 0)
256
+
253 257
     info = [
254 258
         ("status", f'<font color="{color}">{status}</font>'),
255 259
         ("elapsed time", datetime.timedelta(seconds=runner.elapsed_time())),
256
-        ("overhead", f"{runner.overhead():.2f}%"),
260
+        ("overhead", f'<font color="{overhead_color}">{overhead:.2f}%</font>'),
257 261
     ]
258 262
 
259 263
     with suppress(Exception):
Browse code

improve the style of the live_info widget, closes #250 (#251)

Based on the default style of the Jupyterlab table.

Bas Nijholt authored on 18/12/2019 17:36:23 • GitHub committed on 18/12/2019 17:36:23
Showing 1 changed files
... ...
@@ -228,14 +228,16 @@ def live_info(runner, *, update_interval=0.5):
228 228
 
229 229
     runner.ioloop.create_task(update())
230 230
 
231
-    display(
232
-        ipywidgets.HBox(
233
-            (status, cancel),
234
-            layout=ipywidgets.Layout(
235
-                border="solid 1px", width="200px", align_items="center"
236
-            ),
237
-        )
238
-    )
231
+    display(ipywidgets.VBox((status, cancel)))
232
+
233
+
234
+def _table_row(i, key, value):
235
+    """Style the rows of a table. Based on the default Jupyterlab table style."""
236
+    style_odd = "text-align: right; padding: 0.5em 0.5em; line-height: 1.0;"
237
+    style_even = style_odd + "background: var(--md-grey-100);"
238
+    template = '<tr><th style="{style}">{key}</th><th style="{style}">{value}</th></tr>'
239
+    style = style_odd if i % 2 == 1 else style_even
240
+    return template.format(style=style, key=key, value=value)
239 241
 
240 242
 
241 243
 def _info_html(runner):
... ...
@@ -260,11 +262,10 @@ def _info_html(runner):
260 262
     with suppress(Exception):
261 263
         info.append(("latest loss", f'{runner.learner._cache["loss"]:.3f}'))
262 264
 
263
-    template = '<dt class="ignore-css">{}</dt><dd>{}</dd>'
264
-    table = "\n".join(template.format(k, v) for k, v in info)
265
+    table = "\n".join(_table_row(i, k, v) for i, (k, v) in enumerate(info))
265 266
 
266 267
     return f"""
267
-        <dl>
268
+        <table>
268 269
         {table}
269
-        </dl>
270
+        </table>
270 271
     """
Browse code

run pre-commit run --all

Bas Nijholt authored on 11/12/2019 14:00:39
Showing 1 changed files
... ...
@@ -1,5 +1,3 @@
1
-# -*- coding: utf-8 -*-
2
-
3 1
 import asyncio
4 2
 import datetime
5 3
 import importlib
Browse code

set the DynamicMap.cache_size = 1

Bas Nijholt authored on 24/05/2019 20:33:30
Showing 1 changed files
... ...
@@ -136,6 +136,7 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None, normalize=T
136 136
 
137 137
     streams = [hv.streams.Stream.define("Next")()]
138 138
     dm = hv.DynamicMap(plot_generator(), streams=streams)
139
+    dm.cache_size = 1
139 140
 
140 141
     if normalize:
141 142
         # XXX: change when https://github.com/pyviz/holoviews/issues/3637
Browse code

make the 'normalize' argument available in 'runner.live_plot'

Bas Nijholt authored on 15/05/2019 21:02:12
Showing 1 changed files
... ...
@@ -96,7 +96,7 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None, normalize=T
96 96
 
97 97
     Parameters
98 98
     ----------
99
-    runner : `Runner`
99
+    runner : `~adaptive.Runner`
100 100
     plotter : function
101 101
         A function that takes the learner as a argument and returns a
102 102
         holoviews object. By default ``learner.plot()`` will be called.
Browse code

fix all flake8 issues and run pre-commit filters

Bas Nijholt authored on 08/05/2019 02:26:15
Showing 1 changed files
... ...
@@ -16,8 +16,10 @@ _plotly_enabled = False
16 16
 def notebook_extension(*, _inline_js=True):
17 17
     """Enable ipywidgets, holoviews, and asyncio notebook integration."""
18 18
     if not in_ipynb():
19
-        raise RuntimeError('"adaptive.notebook_extension()" may only be run '
20
-                           'from a Jupyter notebook.')
19
+        raise RuntimeError(
20
+            '"adaptive.notebook_extension()" may only be run '
21
+            "from a Jupyter notebook."
22
+        )
21 23
 
22 24
     global _async_enabled, _holoviews_enabled, _ipywidgets_enabled
23 25
 
... ...
@@ -26,54 +28,60 @@ def notebook_extension(*, _inline_js=True):
26 28
         _holoviews_enabled = False  # After closing a notebook the js is gone
27 29
         if not _holoviews_enabled:
28 30
             import holoviews
29
-            holoviews.notebook_extension('bokeh', logo=False, inline=_inline_js)
31
+
32
+            holoviews.notebook_extension("bokeh", logo=False, inline=_inline_js)
30 33
             _holoviews_enabled = True
31 34
     except ModuleNotFoundError:
32
-        warnings.warn("holoviews is not installed; plotting "
33
-                      "is disabled.", RuntimeWarning)
35
+        warnings.warn(
36
+            "holoviews is not installed; plotting " "is disabled.", RuntimeWarning
37
+        )
34 38
 
35 39
     # Load ipywidgets
36 40
     try:
37 41
         if not _ipywidgets_enabled:
38
-            import ipywidgets
42
+            import ipywidgets  # noqa: F401
43
+
39 44
             _ipywidgets_enabled = True
40 45
     except ModuleNotFoundError:
41
-        warnings.warn("ipywidgets is not installed; live_info "
42
-                      "is disabled.", RuntimeWarning)
46
+        warnings.warn(
47
+            "ipywidgets is not installed; live_info " "is disabled.", RuntimeWarning
48
+        )
43 49
 
44 50
     # Enable asyncio integration
45 51
     if not _async_enabled:
46
-        get_ipython().magic('gui asyncio')
52
+        get_ipython().magic("gui asyncio")  # noqa: F821
47 53
         _async_enabled = True
48 54
 
49 55
 
50 56
 def ensure_holoviews():
51 57
     try:
52
-        return importlib.import_module('holoviews')
58
+        return importlib.import_module("holoviews")
53 59
     except ModuleNotFoundError:
54
-        raise RuntimeError('holoviews is not installed; plotting is disabled.')
60
+        raise RuntimeError("holoviews is not installed; plotting is disabled.")
55 61
 
56 62
 
57 63
 def ensure_plotly():
58 64
     global _plotly_enabled
59 65
     try:
60 66
         import plotly
67
+
61 68
         if not _plotly_enabled:
62 69
             import plotly.graph_objs
63 70
             import plotly.figure_factory
64 71
             import plotly.offline
72
+
65 73
             # This injects javascript and should happen only once
66 74
             plotly.offline.init_notebook_mode()
67 75
             _plotly_enabled = True
68 76
         return plotly
69 77
     except ModuleNotFoundError:
70
-        raise RuntimeError('plotly is not installed; plotting is disabled.')
78
+        raise RuntimeError("plotly is not installed; plotting is disabled.")
71 79
 
72 80
 
73 81
 def in_ipynb():
74 82
     try:
75 83
         # If we are running in IPython, then `get_ipython()` is always a global
76
-        return get_ipython().__class__.__name__ == 'ZMQInteractiveShell'
84
+        return get_ipython().__class__.__name__ == "ZMQInteractiveShell"
77 85
     except NameError:
78 86
         return False
79 87
 
... ...
@@ -83,8 +91,7 @@ def in_ipynb():
83 91
 active_plotting_tasks = dict()
84 92
 
85 93
 
86
-def live_plot(runner, *, plotter=None, update_interval=2,
87
-              name=None, normalize=True):
94
+def live_plot(runner, *, plotter=None, update_interval=2, name=None, normalize=True):
88 95
     """Live plotting of the learner's data.
89 96
 
90 97
     Parameters
... ...
@@ -135,14 +142,17 @@ def live_plot(runner, *, plotter=None, update_interval=2,
135 142
         # is fixed.
136 143
         dm = dm.map(lambda obj: obj.opts(framewise=True), hv.Element)
137 144
 
138
-    cancel_button = ipywidgets.Button(description='cancel live-plot',
139
-                                      layout=ipywidgets.Layout(width='150px'))
145
+    cancel_button = ipywidgets.Button(
146
+        description="cancel live-plot", layout=ipywidgets.Layout(width="150px")
147
+    )
140 148
 
141 149
     # Could have used dm.periodic in the following, but this would either spin
142 150
     # off a thread (and learner is not threadsafe) or block the kernel.
143 151
 
144 152
     async def updater():
145
-        event = lambda: hv.streams.Stream.trigger(dm.streams) # XXX: used to be dm.event()
153
+        event = lambda: hv.streams.Stream.trigger(  # noqa: E731
154
+            dm.streams
155
+        )  # XXX: used to be dm.event()
146 156
         # see https://github.com/pyviz/holoviews/issues/3564
147 157
         try:
148 158
             while not runner.task.done():
... ...
@@ -152,7 +162,7 @@ def live_plot(runner, *, plotter=None, update_interval=2,
152 162
         finally:
153 163
             if active_plotting_tasks[name] is asyncio.Task.current_task():
154 164
                 active_plotting_tasks.pop(name, None)
155
-            cancel_button.layout.display = 'none'  # remove cancel button
165
+            cancel_button.layout.display = "none"  # remove cancel button
156 166
 
157 167
     def cancel(_):
158 168
         with suppress(KeyError):
... ...
@@ -177,7 +187,7 @@ def should_update(status):
177 187
         # i.e. we're offline for 12h, with an update_interval of 0.5s,
178 188
         # and without the reduced probability, we have buffer_size=86400.
179 189
         # With the correction this is np.log(86400) / np.log(1.1) = 119.2
180
-        return 1.1**buffer_size * random.random() < 1
190
+        return 1.1 ** buffer_size * random.random() < 1
181 191
     except Exception:
182 192
         # We catch any Exception because we are using a private API.
183 193
         return True
... ...
@@ -190,16 +200,19 @@ def live_info(runner, *, update_interval=0.5):
190 200
     visualized in a Jupyter notebook.
191 201
     """
192 202
     if not _holoviews_enabled:
193
-        raise RuntimeError("Live plotting is not enabled; did you run "
194
-                           "'adaptive.notebook_extension()'?")
203
+        raise RuntimeError(
204
+            "Live plotting is not enabled; did you run "
205
+            "'adaptive.notebook_extension()'?"
206
+        )
195 207
 
196 208
     import ipywidgets
197 209
     from IPython.display import display
198 210
 
199 211
     status = ipywidgets.HTML(value=_info_html(runner))
200 212
 
201
-    cancel = ipywidgets.Button(description='cancel runner',
202
-                               layout=ipywidgets.Layout(width='100px'))
213
+    cancel = ipywidgets.Button(
214
+        description="cancel runner", layout=ipywidgets.Layout(width="100px")
215
+    )
203 216
     cancel.on_click(lambda _: runner.cancel())
204 217
 
205 218
     async def update():
... ...
@@ -212,43 +225,47 @@ def live_info(runner, *, update_interval=0.5):
212 225
                 await asyncio.sleep(0.05)
213 226
 
214 227
         status.value = _info_html(runner)
215
-        cancel.layout.display = 'none'
228
+        cancel.layout.display = "none"
216 229
 
217 230
     runner.ioloop.create_task(update())
218 231
 
219
-    display(ipywidgets.HBox(
220
-        (status, cancel),
221
-        layout=ipywidgets.Layout(border='solid 1px',
222
-                                 width='200px',
223
-                                 align_items='center'),
224
-    ))
232
+    display(
233
+        ipywidgets.HBox(
234
+            (status, cancel),
235
+            layout=ipywidgets.Layout(
236
+                border="solid 1px", width="200px", align_items="center"
237
+            ),
238
+        )
239
+    )
225 240
 
226 241
 
227 242
 def _info_html(runner):
228 243
     status = runner.status()
229 244
 
230
-    color = {'cancelled': 'orange',
231
-             'failed': 'red',
232
-             'running': 'blue',
233
-             'finished': 'green'}[status]
245
+    color = {
246
+        "cancelled": "orange",
247
+        "failed": "red",
248
+        "running": "blue",
249
+        "finished": "green",
250
+    }[status]
234 251
 
235 252
     info = [
236
-        ('status', f'<font color="{color}">{status}</font>'),
237
-        ('elapsed time', datetime.timedelta(seconds=runner.elapsed_time())),
238
-        ('overhead', f'{runner.overhead():.2f}%'),
253
+        ("status", f'<font color="{color}">{status}</font>'),
254
+        ("elapsed time", datetime.timedelta(seconds=runner.elapsed_time())),
255
+        ("overhead", f"{runner.overhead():.2f}%"),
239 256
     ]
240 257
 
241 258
     with suppress(Exception):
242
-        info.append(('# of points', runner.learner.npoints))
259
+        info.append(("# of points", runner.learner.npoints))
243 260
 
244 261
     with suppress(Exception):
245
-        info.append(('latest loss', f'{runner.learner._cache["loss"]:.3f}'))
262
+        info.append(("latest loss", f'{runner.learner._cache["loss"]:.3f}'))
246 263
 
247 264
     template = '<dt class="ignore-css">{}</dt><dd>{}</dd>'
248
-    table = '\n'.join(template.format(k, v) for k, v in info)
265
+    table = "\n".join(template.format(k, v) for k, v in info)
249 266
 
250
-    return f'''
267
+    return f"""
251 268
         <dl>
252 269
         {table}
253 270
         </dl>
254
-    '''
271
+    """
Browse code

fix variable typo

Bas Nijholt authored on 08/05/2019 01:31:00
Showing 1 changed files
... ...
@@ -127,7 +127,7 @@ def live_plot(runner, *, plotter=None, update_interval=2,
127 127
             else:
128 128
                 yield plotter(runner.learner)
129 129
 
130
-    steams = [hv.streams.Stream.define("Next")()]
130
+    streams = [hv.streams.Stream.define("Next")()]
131 131
     dm = hv.DynamicMap(plot_generator(), streams=streams)
132 132
 
133 133
     if normalize:
Browse code

fix import order and style

Bas Nijholt authored on 07/05/2019 23:42:40
Showing 1 changed files
... ...
@@ -1,12 +1,11 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 
3 3
 import asyncio
4
-from contextlib import suppress
5 4
 import datetime
6 5
 import importlib
7 6
 import random
8 7
 import warnings
9
-
8
+from contextlib import suppress
10 9
 
11 10
 _async_enabled = False
12 11
 _holoviews_enabled = False
Browse code

add to-do and link holoviews issue

see https://github.com/pyviz/holoviews/issues/3637

Bas Nijholt authored on 25/04/2019 23:07:57
Showing 1 changed files
... ...
@@ -132,6 +132,8 @@ def live_plot(runner, *, plotter=None, update_interval=2,
132 132
     dm = hv.DynamicMap(plot_generator(), streams=streams)
133 133
 
134 134
     if normalize:
135
+        # XXX: change when https://github.com/pyviz/holoviews/issues/3637
136
+        # is fixed.
135 137
         dm = dm.map(lambda obj: obj.opts(framewise=True), hv.Element)
136 138
 
137 139
     cancel_button = ipywidgets.Button(description='cancel live-plot',
Browse code

renormalize the plots value axis on every update

Bas Nijholt authored on 19/04/2019 01:31:13
Showing 1 changed files
... ...
@@ -84,7 +84,8 @@ def in_ipynb():
84 84
 active_plotting_tasks = dict()
85 85
 
86 86
 
87
-def live_plot(runner, *, plotter=None, update_interval=2, name=None):
87
+def live_plot(runner, *, plotter=None, update_interval=2,
88
+              name=None, normalize=True):
88 89
     """Live plotting of the learner's data.
89 90
 
90 91
     Parameters
... ...
@@ -99,6 +100,8 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
99 100
         Name for the `live_plot` task in `adaptive.active_plotting_tasks`.
100 101
         By default the name is None and if another task with the same name
101 102
         already exists that other `live_plot` is canceled.
103
+    normalize : bool
104
+        Normalize (scale to fit) the frame upon each update.
102 105
 
103 106
     Returns
104 107
     -------
... ...
@@ -106,8 +109,10 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
106 109
         The plot that automatically updates every `update_interval`.
107 110
     """
108 111
     if not _holoviews_enabled:
109
-        raise RuntimeError("Live plotting is not enabled; did you run "
110
-                           "'adaptive.notebook_extension()'?")
112
+        raise RuntimeError(
113
+            "Live plotting is not enabled; did you run "
114
+            "'adaptive.notebook_extension()'?"
115
+        )
111 116
 
112 117
     import holoviews as hv
113 118
     import ipywidgets
... ...
@@ -123,8 +128,12 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
123 128
             else:
124 129
                 yield plotter(runner.learner)
125 130
 
126
-    dm = hv.DynamicMap(plot_generator(),
127
-                       streams=[hv.streams.Stream.define('Next')()])
131
+    steams = [hv.streams.Stream.define("Next")()]
132
+    dm = hv.DynamicMap(plot_generator(), streams=streams)
133
+
134
+    if normalize:
135
+        dm = dm.map(lambda obj: obj.opts(framewise=True), hv.Element)
136
+
128 137
     cancel_button = ipywidgets.Button(description='cancel live-plot',
129 138
                                       layout=ipywidgets.Layout(width='150px'))
130 139
 
Browse code

do not inline the HoloViews JS

Bas Nijholt authored on 26/03/2019 12:44:31
Showing 1 changed files
... ...
@@ -14,7 +14,7 @@ _ipywidgets_enabled = False
14 14
 _plotly_enabled = False
15 15
 
16 16
 
17
-def notebook_extension():
17
+def notebook_extension(*, _inline_js=True):
18 18
     """Enable ipywidgets, holoviews, and asyncio notebook integration."""
19 19
     if not in_ipynb():
20 20
         raise RuntimeError('"adaptive.notebook_extension()" may only be run '
... ...
@@ -27,7 +27,7 @@ def notebook_extension():
27 27
         _holoviews_enabled = False  # After closing a notebook the js is gone
28 28
         if not _holoviews_enabled:
29 29
             import holoviews
30
-            holoviews.notebook_extension('bokeh', logo=False)
30
+            holoviews.notebook_extension('bokeh', logo=False, inline=_inline_js)
31 31
             _holoviews_enabled = True
32 32
     except ModuleNotFoundError:
33 33
         warnings.warn("holoviews is not installed; plotting "
Browse code

fix live_plot

See https://github.com/pyviz/holoviews/issues/3564
and https://github.com/python-adaptive/adaptive/issues/166

Bas Nijholt authored on 19/03/2019 19:22:20
Showing 1 changed files
... ...
@@ -132,11 +132,13 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
132 132
     # off a thread (and learner is not threadsafe) or block the kernel.
133 133
 
134 134
     async def updater():
135
+        event = lambda: hv.streams.Stream.trigger(dm.streams) # XXX: used to be dm.event()
136
+        # see https://github.com/pyviz/holoviews/issues/3564
135 137
         try:
136 138
             while not runner.task.done():
137
-                dm.event()
139
+                event()
138 140
                 await asyncio.sleep(update_interval)
139
-            dm.event()  # fire off one last update before we die
141
+            event()  # fire off one last update before we die
140 142
         finally:
141 143
             if active_plotting_tasks[name] is asyncio.Task.current_task():
142 144
                 active_plotting_tasks.pop(name, None)
Browse code

fix whitespace issues

Joseph Weston authored on 20/12/2018 22:35:02
Showing 1 changed files
... ...
@@ -32,7 +32,7 @@ def notebook_extension():
32 32
     except ModuleNotFoundError:
33 33
         warnings.warn("holoviews is not installed; plotting "
34 34
                       "is disabled.", RuntimeWarning)
35
-    
35
+
36 36
     # Load ipywidgets
37 37
     try:
38 38
         if not _ipywidgets_enabled:
Browse code

adhere to PEP008 by using absolute imports

See https://www.python.org/dev/peps/pep-0008/#imports

Bas Nijholt authored on 26/11/2018 13:39:12
Showing 1 changed files
... ...
@@ -1,8 +1,9 @@
1 1
 # -*- coding: utf-8 -*-
2
-import importlib
2
+
3 3
 import asyncio
4 4
 from contextlib import suppress
5 5
 import datetime
6
+import importlib
6 7
 import random
7 8
 import warnings
8 9
 
Browse code

reload the holoviews javascript each time notebook_integration is called

Because after closing the notebook and then opening it, the javascript
is gone. Without this change, one could not load it again.

Bas Nijholt authored on 30/10/2018 13:34:34
Showing 1 changed files
... ...
@@ -23,6 +23,7 @@ def notebook_extension():
23 23
 
24 24
     # Load holoviews
25 25
     try:
26
+        _holoviews_enabled = False  # After closing a notebook the js is gone
26 27
         if not _holoviews_enabled:
27 28
             import holoviews
28 29
             holoviews.notebook_extension('bokeh', logo=False)
Browse code

exponentially decay message frequency in live_info

Jorn Hoofwijk authored on 20/09/2018 13:42:04 • Bas Nijholt committed on 22/10/2018 14:47:59
Showing 1 changed files
... ...
@@ -3,6 +3,7 @@ import importlib
3 3
 import asyncio
4 4
 from contextlib import suppress
5 5
 import datetime
6
+import random
6 7
 import warnings
7 8
 
8 9
 
... ...
@@ -150,6 +151,24 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
150 151
     return dm
151 152
 
152 153
 
154
+def should_update(status):
155
+    try:
156
+        # Get the length of the write buffer size
157
+        buffer_size = len(status.comm.kernel.iopub_thread._events)
158
+
159
+        # Make sure to only keep all the messages when the notebook
160
+        # is viewed, this means 'buffer_size == 1'. However, when not
161
+        # viewing the notebook the buffer fills up. When this happens
162
+        # we decide to only add messages to it when a certain probability.
163
+        # i.e. we're offline for 12h, with an update_interval of 0.5s,
164
+        # and without the reduced probability, we have buffer_size=86400.
165
+        # With the correction this is np.log(86400) / np.log(1.1) = 119.2
166
+        return 1.1**buffer_size * random.random() < 1
167
+    except Exception:
168
+        # We catch any Exception because we are using a private API.
169
+        return True
170
+
171
+
153 172
 def live_info(runner, *, update_interval=0.5):
154 173
     """Display live information about the runner.
155 174
 
... ...
@@ -172,7 +191,12 @@ def live_info(runner, *, update_interval=0.5):
172 191
     async def update():
173 192
         while not runner.task.done():
174 193
             await asyncio.sleep(update_interval)
175
-            status.value = _info_html(runner)
194
+
195
+            if should_update(status):
196
+                status.value = _info_html(runner)
197
+            else:
198
+                await asyncio.sleep(0.05)
199
+
176 200
         status.value = _info_html(runner)
177 201
         cancel.layout.display = 'none'
178 202
 
Browse code

improve 'notebook_extension' and add 'plotly' as a dependency

Bas Nijholt authored on 20/10/2018 13:04:45
Showing 1 changed files
... ...
@@ -7,28 +7,42 @@ import warnings
7 7
 
8 8
 
9 9
 _async_enabled = False
10
-_plotting_enabled = False
10
+_holoviews_enabled = False
11
+_ipywidgets_enabled = False
12
+_plotly_enabled = False
11 13
 
12 14
 
13 15
 def notebook_extension():
16
+    """Enable ipywidgets, holoviews, and asyncio notebook integration."""
14 17
     if not in_ipynb():
15 18
         raise RuntimeError('"adaptive.notebook_extension()" may only be run '
16 19
                            'from a Jupyter notebook.')
17 20
 
18
-    global _plotting_enabled
19
-    _plotting_enabled = False
21
+    global _async_enabled, _holoviews_enabled, _ipywidgets_enabled
22
+
23
+    # Load holoviews
24
+    try:
25
+        if not _holoviews_enabled:
26
+            import holoviews
27
+            holoviews.notebook_extension('bokeh', logo=False)
28
+            _holoviews_enabled = True
29
+    except ModuleNotFoundError:
30
+        warnings.warn("holoviews is not installed; plotting "
31
+                      "is disabled.", RuntimeWarning)
32
+    
33
+    # Load ipywidgets
20 34
     try:
21
-        import ipywidgets
22
-        import holoviews
23
-        holoviews.notebook_extension('bokeh', logo=False)
24
-        _plotting_enabled = True
35
+        if not _ipywidgets_enabled:
36
+            import ipywidgets
37
+            _ipywidgets_enabled = True
25 38
     except ModuleNotFoundError:
26
-        warnings.warn("holoviews and (or) ipywidgets are not installed; plotting "
39
+        warnings.warn("ipywidgets is not installed; live_info "
27 40
                       "is disabled.", RuntimeWarning)
28 41
 
29
-    global _async_enabled
30
-    get_ipython().magic('gui asyncio')
31
-    _async_enabled = True
42
+    # Enable asyncio integration
43
+    if not _async_enabled:
44
+        get_ipython().magic('gui asyncio')
45
+        _async_enabled = True
32 46
 
33 47
 
34 48
 def ensure_holoviews():
... ...
@@ -38,6 +52,22 @@ def ensure_holoviews():
38 52
         raise RuntimeError('holoviews is not installed; plotting is disabled.')
39 53
 
40 54
 
55
+def ensure_plotly():
56
+    global _plotly_enabled
57
+    try:
58
+        import plotly
59
+        if not _plotly_enabled:
60
+            import plotly.graph_objs
61
+            import plotly.figure_factory
62
+            import plotly.offline
63
+            # This injects javascript and should happen only once
64
+            plotly.offline.init_notebook_mode()
65
+            _plotly_enabled = True
66
+        return plotly
67
+    except ModuleNotFoundError:
68
+        raise RuntimeError('plotly is not installed; plotting is disabled.')
69
+
70
+
41 71
 def in_ipynb():
42 72
     try:
43 73
         # If we are running in IPython, then `get_ipython()` is always a global
... ...
@@ -72,7 +102,7 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
72 102
     dm : `holoviews.core.DynamicMap`
73 103
         The plot that automatically updates every `update_interval`.
74 104
     """
75
-    if not _plotting_enabled:
105
+    if not _holoviews_enabled:
76 106
         raise RuntimeError("Live plotting is not enabled; did you run "
77 107
                            "'adaptive.notebook_extension()'?")
78 108
 
... ...
@@ -126,7 +156,7 @@ def live_info(runner, *, update_interval=0.5):
126 156
     Returns an interactive ipywidget that can be
127 157
     visualized in a Jupyter notebook.
128 158
     """
129
-    if not _plotting_enabled:
159
+    if not _holoviews_enabled:
130 160
         raise RuntimeError("Live plotting is not enabled; did you run "
131 161
                            "'adaptive.notebook_extension()'?")
132 162
 
Browse code

fix live_info css

Bas Nijholt authored on 19/10/2018 13:24:42
Showing 1 changed files
... ...
@@ -176,7 +176,7 @@ def _info_html(runner):
176 176
     with suppress(Exception):
177 177
         info.append(('latest loss', f'{runner.learner._cache["loss"]:.3f}'))
178 178
 
179
-    template = '<dt>{}</dt><dd>{}</dd>'
179
+    template = '<dt class="ignore-css">{}</dt><dd>{}</dd>'
180 180
     table = '\n'.join(template.format(k, v) for k, v in info)
181 181
 
182 182
     return f'''
Browse code

add tutorials

Bas Nijholt authored on 17/10/2018 13:30:10
Showing 1 changed files
... ...
@@ -20,7 +20,7 @@ def notebook_extension():
20 20
     try:
21 21
         import ipywidgets
22 22
         import holoviews
23
-        holoviews.notebook_extension('bokeh')
23
+        holoviews.notebook_extension('bokeh', logo=False)
24 24
         _plotting_enabled = True
25 25
     except ModuleNotFoundError:
26 26
         warnings.warn("holoviews and (or) ipywidgets are not installed; plotting "
Browse code

add doc files

Bas Nijholt authored on 16/10/2018 18:10:12
Showing 1 changed files
... ...
@@ -56,21 +56,21 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
56 56
 
57 57
     Parameters
58 58
     ----------
59
-    runner : Runner
59
+    runner : `Runner`
60 60
     plotter : function
61 61
         A function that takes the learner as a argument and returns a
62
-        holoviews object. By default learner.plot() will be called.
62
+        holoviews object. By default ``learner.plot()`` will be called.
63 63
     update_interval : int
64 64
         Number of second between the updates of the plot.
65 65
     name : hasable
66 66
         Name for the `live_plot` task in `adaptive.active_plotting_tasks`.
67
-        By default the name is `None` and if another task with the same name
68
-        already exists that other live_plot is canceled.
67
+        By default the name is None and if another task with the same name
68
+        already exists that other `live_plot` is canceled.
69 69
 
70 70
     Returns
71 71
     -------
72
-    dm : holoviews.DynamicMap
73
-        The plot that automatically updates every update_interval.
72
+    dm : `holoviews.core.DynamicMap`
73
+        The plot that automatically updates every `update_interval`.
74 74
     """
75 75
     if not _plotting_enabled:
76 76
         raise RuntimeError("Live plotting is not enabled; did you run "
Browse code

fix bug 'ModuleNotFounderror' -> 'ModuleNotFoundError'

Bas Nijholt authored on 15/10/2018 16:32:49
Showing 1 changed files
... ...
@@ -34,7 +34,7 @@ def notebook_extension():
34 34
 def ensure_holoviews():
35 35
     try:
36 36
         return importlib.import_module('holoviews')
37
-    except ModuleNotFounderror:
37
+    except ModuleNotFoundError:
38 38
         raise RuntimeError('holoviews is not installed; plotting is disabled.')
39 39
 
40 40
 
Browse code

fix empty lines and remove unused import

Bas Nijholt authored on 15/10/2018 14:46:32
Showing 1 changed files
... ...
@@ -3,7 +3,6 @@ import importlib
3 3
 import asyncio
4 4
 from contextlib import suppress
5 5
 import datetime
6
-from pkg_resources import parse_version
7 6
 import warnings
8 7
 
9 8
 
Browse code

display the loss with 'live_info'

Bas Nijholt authored on 08/10/2018 13:16:54
Showing 1 changed files
... ...
@@ -174,6 +174,9 @@ def _info_html(runner):
174 174
     with suppress(Exception):
175 175
         info.append(('# of points', runner.learner.npoints))
176 176
 
177
+    with suppress(Exception):
178
+        info.append(('latest loss', f'{runner.learner._cache["loss"]:.3f}'))
179
+
177 180
     template = '<dt>{}</dt><dd>{}</dd>'
178 181
     table = '\n'.join(template.format(k, v) for k, v in info)
179 182
 
Browse code

use contextlib.suppress

Bas Nijholt authored on 10/07/2018 23:25:10
Showing 1 changed files
... ...
@@ -1,6 +1,7 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 import importlib
3 3
 import asyncio
4
+from contextlib import suppress
4 5
 import datetime
5 6
 from pkg_resources import parse_version
6 7
 import warnings
... ...
@@ -110,10 +111,8 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
110 111
             cancel_button.layout.display = 'none'  # remove cancel button
111 112
 
112 113
     def cancel(_):
113
-        try:
114
+        with suppress(KeyError):
114 115
             active_plotting_tasks[name].cancel()
115
-        except KeyError:
116
-            pass
117 116
 
118 117
     active_plotting_tasks[name] = runner.ioloop.create_task(updater())
119 118
     cancel_button.on_click(cancel)
... ...
@@ -172,10 +171,8 @@ def _info_html(runner):
172 171
         ('overhead', f'{runner.overhead():.2f}%'),
173 172
     ]
174 173
 
175
-    try:
174
+    with suppress(Exception):
176 175
         info.append(('# of points', runner.learner.npoints))
177
-    except Exception:
178
-        pass
179 176
 
180 177
     template = '<dt>{}</dt><dd>{}</dd>'
181 178
     table = '\n'.join(template.format(k, v) for k, v in info)
Browse code

remove 'performance' and define 'overhead' (1 - efficiecy)

Bas Nijholt authored on 16/06/2018 23:02:26
Showing 1 changed files
... ...
@@ -161,19 +161,15 @@ def live_info(runner, *, update_interval=0.5):
161 161
 def _info_html(runner):
162 162
     status = runner.status()
163 163
 
164
-    stat_color = {'cancelled': 'orange',
165
-                  'failed': 'red',
166
-                  'running': 'blue',
167
-                  'finished': 'green'}[status]
168
-
169
-    performance = runner.performance()
170
-    perf_color = 'green' if performance > 1 else 'red'
164
+    color = {'cancelled': 'orange',
165
+             'failed': 'red',
166
+             'running': 'blue',
167
+             'finished': 'green'}[status]
171 168
 
172 169
     info = [
173
-        ('status', f'<font color="{stat_color}">{status}</font>'),
170
+        ('status', f'<font color="{color}">{status}</font>'),
174 171
         ('elapsed time', datetime.timedelta(seconds=runner.elapsed_time())),
175
-        ('performance', f'<font color="{perf_color}">{performance:.1f}</font>'),
176
-        ('efficiency', f'{runner.efficiency():.2f}%'),
172
+        ('overhead', f'{runner.overhead():.2f}%'),
177 173
     ]
178 174
 
179 175
     try:
Browse code

calculate the actual efficiency of the resources

Bas Nijholt authored on 16/06/2018 22:32:07
Showing 1 changed files
... ...
@@ -173,6 +173,7 @@ def _info_html(runner):
173 173
         ('status', f'<font color="{stat_color}">{status}</font>'),
174 174
         ('elapsed time', datetime.timedelta(seconds=runner.elapsed_time())),
175 175
         ('performance', f'<font color="{perf_color}">{performance:.1f}</font>'),
176
+        ('efficiency', f'{runner.efficiency():.2f}%'),
176 177
     ]
177 178
 
178 179
     try:
Browse code

define a measure of 'performance'

Bas Nijholt authored on 16/06/2018 09:59:54
Showing 1 changed files
... ...
@@ -161,15 +161,18 @@ def live_info(runner, *, update_interval=0.5):
161 161
 def _info_html(runner):
162 162
     status = runner.status()
163 163
 
164
-    color = {'cancelled': 'orange',
165
-             'failed': 'red',
166
-             'running': 'blue',
167
-             'finished': 'green'}[status]
164
+    stat_color = {'cancelled': 'orange',
165
+                  'failed': 'red',
166
+                  'running': 'blue',
167
+                  'finished': 'green'}[status]
168
+
169
+    performance = runner.performance()
170
+    perf_color = 'green' if performance > 1 else 'red'
168 171
 
169 172
     info = [
170
-        ('status', f'<font color="{color}">{status}</font>'),
173
+        ('status', f'<font color="{stat_color}">{status}</font>'),
171 174
         ('elapsed time', datetime.timedelta(seconds=runner.elapsed_time())),
172
-        (f'efficiency', f'{runner.efficiency():.1f}%'),
175
+        ('performance', f'<font color="{perf_color}">{performance:.1f}</font>'),
173 176
     ]
174 177
 
175 178
     try:
Browse code

correctly keep track of the average time

Bas Nijholt authored on 16/06/2018 09:07:44
Showing 1 changed files
... ...
@@ -166,13 +166,10 @@ def _info_html(runner):
166 166
              'running': 'blue',
167 167
              'finished': 'green'}[status]
168 168
 
169
-    t_total = runner.elapsed_time()
170
-    efficiency = (t_total - runner.time_ask_tell) / t_total * 100
171
-
172 169
     info = [
173 170
         ('status', f'<font color="{color}">{status}</font>'),
174
-        ('elapsed time', datetime.timedelta(seconds=t_total)),
175
-        (f'efficiency', f'{efficiency:.1f}%'),
171
+        ('elapsed time', datetime.timedelta(seconds=runner.elapsed_time())),
172
+        (f'efficiency', f'{runner.efficiency():.1f}%'),
176 173
     ]
177 174
 
178 175
     try:
Browse code

measure the efficiency of the runner

Bas Nijholt authored on 15/06/2018 05:58:51
Showing 1 changed files
... ...
@@ -166,9 +166,13 @@ def _info_html(runner):
166 166
              'running': 'blue',
167 167
              'finished': 'green'}[status]
168 168
 
169
+    t_total = runner.elapsed_time()
170
+    efficiency = (t_total - runner.time_ask_tell) / t_total * 100
171
+
169 172
     info = [
170 173
         ('status', f'<font color="{color}">{status}</font>'),
171
-        ('elapsed time', datetime.timedelta(seconds=runner.elapsed_time())),
174
+        ('elapsed time', datetime.timedelta(seconds=t_total)),
175
+        (f'efficiency', f'{efficiency:.1f}%'),
172 176
     ]
173 177
 
174 178
     try:
Browse code

remove 'description' argument in ipywidgets.HBox because it's deprecated

> This is deprecated in traitlets 4.2. This error will be raised in a future release of traitlets.

Bas Nijholt authored on 24/05/2018 07:47:31
Showing 1 changed files
... ...
@@ -152,7 +152,6 @@ def live_info(runner, *, update_interval=0.5):
152 152
 
153 153
     display(ipywidgets.HBox(
154 154
         (status, cancel),
155
-        description='Runner stats',
156 155
         layout=ipywidgets.Layout(border='solid 1px',
157 156
                                  width='200px',
158 157
                                  align_items='center'),
Browse code

fix the warning message when holoviews and (or) ipywidgets are not installed

Bas Nijholt authored on 03/03/2018 20:00:31
Showing 1 changed files
... ...
@@ -23,7 +23,7 @@ def notebook_extension():
23 23
         holoviews.notebook_extension('bokeh')
24 24
         _plotting_enabled = True
25 25
     except ModuleNotFoundError:
26
-        warnings.warn("holoviews and ipywidgets are not installed; plotting "
26
+        warnings.warn("holoviews and (or) ipywidgets are not installed; plotting "
27 27
                       "is disabled.", RuntimeWarning)
28 28
 
29 29
     global _async_enabled
Browse code

remove cancel button when runner or live plot stops

This provides a better UX than leaving a useless button dangling.

Joseph Weston authored on 19/02/2018 14:45:12
Showing 1 changed files
... ...
@@ -80,6 +80,9 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
80 80
     import ipywidgets
81 81
     from IPython.display import display
82 82
 
83
+    if name in active_plotting_tasks:
84
+        active_plotting_tasks[name].cancel()
85
+
83 86
     def plot_generator():
84 87
         while True:
85 88
             if not plotter:
... ...
@@ -89,7 +92,8 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
89 92
 
90 93
     dm = hv.DynamicMap(plot_generator(),
91 94
                        streams=[hv.streams.Stream.define('Next')()])
92
-
95
+    cancel_button = ipywidgets.Button(description='cancel live-plot',
96
+                                      layout=ipywidgets.Layout(width='150px'))
93 97
 
94 98
     # Could have used dm.periodic in the following, but this would either spin
95 99
     # off a thread (and learner is not threadsafe) or block the kernel.
... ...
@@ -103,12 +107,7 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
103 107
         finally:
104 108
             if active_plotting_tasks[name] is asyncio.Task.current_task():
105 109
                 active_plotting_tasks.pop(name, None)
106
-
107
-    global active_plotting_tasks
108
-    if name in active_plotting_tasks:
109
-        active_plotting_tasks[name].cancel()
110
-
111
-    active_plotting_tasks[name] = asyncio.get_event_loop().create_task(updater())
110
+            cancel_button.layout.display = 'none'  # remove cancel button
112 111
 
113 112
     def cancel(_):
114 113
         try:
... ...
@@ -116,11 +115,10 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
116 115
         except KeyError:
117 116
             pass
118 117
 
119
-    cancel_button = ipywidgets.Button(description='cancel live-plot',
120
-                                      layout=ipywidgets.Layout(width='150px'))
118
+    active_plotting_tasks[name] = runner.ioloop.create_task(updater())
121 119
     cancel_button.on_click(cancel)
122
-    display(cancel_button)
123 120
 
121
+    display(cancel_button)
124 122
     return dm
125 123
 
126 124
 
... ...
@@ -140,7 +138,7 @@ def live_info(runner, *, update_interval=0.5):
140 138
     status = ipywidgets.HTML(value=_info_html(runner))
141 139
 
142 140
     cancel = ipywidgets.Button(description='cancel runner',
143
-                            layout=ipywidgets.Layout(width='100px'))
141
+                               layout=ipywidgets.Layout(width='100px'))
144 142
     cancel.on_click(lambda _: runner.cancel())
145 143
 
146 144
     async def update():
... ...
@@ -148,17 +146,17 @@ def live_info(runner, *, update_interval=0.5):
148 146
             await asyncio.sleep(update_interval)
149 147
             status.value = _info_html(runner)
150 148
         status.value = _info_html(runner)
149
+        cancel.layout.display = 'none'
151 150
 
152 151
     runner.ioloop.create_task(update())
153 152
 
154
-    hbox = ipywidgets.HBox(
153
+    display(ipywidgets.HBox(
155 154
         (status, cancel),
156 155
         description='Runner stats',
157 156
         layout=ipywidgets.Layout(border='solid 1px',
158 157
                                  width='200px',
159 158
                                  align_items='center'),
160
-    )
161
-    return display(hbox)
159
+    ))
162 160
 
163 161
 
164 162
 def _info_html(runner):
Browse code

factor out holoviews import

Now we raise a custom error telling the user to install holoviews

Joseph Weston authored on 19/02/2018 14:44:19
Showing 1 changed files
... ...
@@ -1,4 +1,5 @@
1 1
 # -*- coding: utf-8 -*-
2
+import importlib
2 3
 import asyncio
3 4
 import datetime
4 5
 from pkg_resources import parse_version
... ...
@@ -30,6 +31,13 @@ def notebook_extension():
30 31
     _async_enabled = True
31 32
 
32 33
 
34
+def ensure_holoviews():
35
+    try:
36
+        return importlib.import_module('holoviews')
37
+    except ModuleNotFounderror:
38
+        raise RuntimeError('holoviews is not installed; plotting is disabled.')
39
+
40
+
33 41
 def in_ipynb():
34 42
     try:
35 43
         # If we are running in IPython, then `get_ipython()` is always a global
Browse code

fix whitespace

Bas Nijholt authored on 17/02/2018 17:29:01
Showing 1 changed files
... ...
@@ -147,8 +147,8 @@ def live_info(runner, *, update_interval=0.5):
147 147
         (status, cancel),
148 148
         description='Runner stats',
149 149
         layout=ipywidgets.Layout(border='solid 1px',
150
-                              width='200px',
151
-                              align_items='center'),
150
+                                 width='200px',
151
+                                 align_items='center'),
152 152
     )
153 153
     return display(hbox)
154 154
 
Browse code

move all notebook-related code to notebook_integration

Also move all non-essential requirements to 'extras_require'.

Joseph Weston authored on 16/02/2018 20:49:15
Showing 1 changed files
... ...
@@ -4,55 +4,41 @@ import datetime
4 4
 from pkg_resources import parse_version
5 5
 import warnings
6 6
 
7
-from IPython import get_ipython
8
-import ipykernel
9
-from ipykernel.eventloops import register_integration
10 7
 
8
+_async_enabled = False
9
+_plotting_enabled = False
11 10
 
12
-# IPython event loop integration
13 11
 
14
-if parse_version(ipykernel.__version__) < parse_version('4.7.0'):
15
-    # XXX: remove this function when we depend on ipykernel>=4.7.0
16
-    @register_integration('asyncio')
17
-    def _loop_asyncio(kernel):
18
-        """Start a kernel with asyncio event loop support.
19
-        Taken from https://github.com/ipython/ipykernel/blob/fa814da201bdebd5b16110597604f7dabafec58d/ipykernel/eventloops.py#L294"""
20
-        loop = asyncio.get_event_loop()
12
+def notebook_extension():
13
+    if not in_ipynb():
14
+        raise RuntimeError('"adaptive.notebook_extension()" may only be run '
15
+                           'from a Jupyter notebook.')
21 16
 
22
-        def kernel_handler():
23
-            loop.call_soon(kernel.do_one_iteration)
24
-            loop.call_later(kernel._poll_interval, kernel_handler)
17
+    global _plotting_enabled
18
+    _plotting_enabled = False
19
+    try:
20
+        import ipywidgets
21
+        import holoviews
22
+        holoviews.notebook_extension('bokeh')
23
+        _plotting_enabled = True
24
+    except ModuleNotFoundError:
25
+        warnings.warn("holoviews and ipywidgets are not installed; plotting "
26
+                      "is disabled.", RuntimeWarning)
25 27
 
26
-        loop.call_soon(kernel_handler)
27
-        # loop is already running (e.g. tornado 5), nothing left to do
28
-        if loop.is_running():
29
-            return
30
-        while True:
31
-            error = None
32
-            try:
33
-                loop.run_forever()
34
-            except KeyboardInterrupt:
35
-                continue
36
-            except Exception as e:
37
-                error = e
38
-            loop.run_until_complete(loop.shutdown_asyncgens())
39
-            loop.close()
40
-            if error is not None:
41
-                raise error
42
-            break
28
+    global _async_enabled
29
+    get_ipython().magic('gui asyncio')
30
+    _async_enabled = True
43 31
 
44 32
 
45
-def notebook_extension():
46
-    get_ipython().magic('gui asyncio')
33
+def in_ipynb():
47 34
     try:
48
-        import holoviews as hv
49
-        return hv.notebook_extension('bokeh')
50
-    except ModuleNotFoundError:
51
-        warnings.warn("The holoviews package is not installed so plotting"
52
-                      "will not work.", RuntimeWarning)
35
+        # If we are running in IPython, then `get_ipython()` is always a global
36
+        return get_ipython().__class__.__name__ == 'ZMQInteractiveShell'
37
+    except NameError:
38
+        return False
53 39
 
54 40
 
55
-# Plotting
41
+# Fancy displays in the Jupyter notebook
56 42
 
57 43
 active_plotting_tasks = dict()
58 44
 
... ...
@@ -78,11 +64,11 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
78 64
     dm : holoviews.DynamicMap
79 65
         The plot that automatically updates every update_interval.
80 66
     """
81
-    try:
82
-        import holoviews as hv
83
-    except ModuleNotFoundError:
84
-        raise RuntimeError('Plotting requires the holoviews Python package'
85
-                           ' which is not installed.')
67
+    if not _plotting_enabled:
68
+        raise RuntimeError("Live plotting is not enabled; did you run "
69
+                           "'adaptive.notebook_extension()'?")
70
+
71
+    import holoviews as hv
86 72
     import ipywidgets
87 73
     from IPython.display import display
88 74
 
... ...
@@ -136,6 +122,10 @@ def live_info(runner, *, update_interval=0.5):
136 122
     Returns an interactive ipywidget that can be
137 123
     visualized in a Jupyter notebook.
138 124
     """
125
+    if not _plotting_enabled:
126
+        raise RuntimeError("Live plotting is not enabled; did you run "
127
+                           "'adaptive.notebook_extension()'?")
128
+
139 129
     import ipywidgets
140 130
     from IPython.display import display
141 131
 
Browse code

change the 'n' attribute of learners to 'npoints'

Previously this attribute was meant to be an implementation
detail, but it is useful information and should be made public.
Given that it is public information, it should have an informative
name.

Joseph Weston authored on 16/02/2018 17:50:48
Showing 1 changed files
... ...
@@ -177,7 +177,7 @@ def _info_html(runner):
177 177
     ]
178 178
 
179 179
     try:
180
-        info.append(('# of points', runner.learner.n))
180
+        info.append(('# of points', runner.learner.npoints))
181 181
     except Exception:
182 182
         pass
183 183
 
Browse code

print the status in runner.live_info in color

Bas Nijholt authored on 16/02/2018 17:42:35
Showing 1 changed files
... ...
@@ -164,8 +164,15 @@ def live_info(runner, *, update_interval=0.5):
164 164
 
165 165
 
166 166
 def _info_html(runner):
167
+    status = runner.status()
168
+
169
+    color = {'cancelled': 'orange',
170
+             'failed': 'red',
171
+             'running': 'blue',
172
+             'finished': 'green'}[status]
173
+
167 174
     info = [
168
-        ('status', runner.status()),
175
+        ('status', f'<font color="{color}">{status}</font>'),
169 176
         ('elapsed time', datetime.timedelta(seconds=runner.elapsed_time())),
170 177
     ]
171 178
 
Browse code

import ipywidgets as ipywidgets instead of widgets

Bas Nijholt authored on 16/02/2018 15:53:07 • Joseph Weston committed on 16/02/2018 16:48:29
Showing 1 changed files
... ...
@@ -136,13 +136,13 @@ def live_info(runner, *, update_interval=0.5):
136 136
     Returns an interactive ipywidget that can be
137 137
     visualized in a Jupyter notebook.
138 138
     """
139
-    import ipywidgets as widgets
139
+    import ipywidgets
140 140
     from IPython.display import display
141 141
 
142
-    status = widgets.HTML(value=_info_html(runner))
142
+    status = ipywidgets.HTML(value=_info_html(runner))
143 143
 
144
-    cancel = widgets.Button(description='cancel runner',
145
-                            layout=widgets.Layout(width='100px'))
144
+    cancel = ipywidgets.Button(description='cancel runner',
145
+                            layout=ipywidgets.Layout(width='100px'))
146 146
     cancel.on_click(lambda _: runner.cancel())
147 147
 
148 148
     async def update():
... ...
@@ -153,10 +153,10 @@ def live_info(runner, *, update_interval=0.5):
153 153
 
154 154
     runner.ioloop.create_task(update())
155 155
 
156
-    hbox = widgets.HBox(
156
+    hbox = ipywidgets.HBox(
157 157
         (status, cancel),
158 158
         description='Runner stats',
159
-        layout=widgets.Layout(border='solid 1px',
159
+        layout=ipywidgets.Layout(border='solid 1px',
160 160
                               width='200px',
161 161
                               align_items='center'),
162 162
     )
Browse code

add a method live_plot to the runner and move live_info to notebook_integration.py while keeping it as a runner method

Bas Nijholt authored on 16/02/2018 15:47:06 • Joseph Weston committed on 16/02/2018 16:48:29
Showing 1 changed files
... ...
@@ -1,5 +1,6 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 import asyncio
3
+import datetime
3 4
 from pkg_resources import parse_version
4 5
 import warnings
5 6
 
... ...
@@ -127,3 +128,57 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
127 128
     display(cancel_button)
128 129
 
129 130
     return dm
131
+
132
+
133
+def live_info(runner, *, update_interval=0.5):
134
+    """Display live information about the runner.
135
+
136
+    Returns an interactive ipywidget that can be
137
+    visualized in a Jupyter notebook.
138
+    """
139
+    import ipywidgets as widgets
140
+    from IPython.display import display
141
+
142
+    status = widgets.HTML(value=_info_html(runner))
143
+
144
+    cancel = widgets.Button(description='cancel runner',
145
+                            layout=widgets.Layout(width='100px'))
146
+    cancel.on_click(lambda _: runner.cancel())
147
+
148
+    async def update():
149
+        while not runner.task.done():
150
+            await asyncio.sleep(update_interval)
151
+            status.value = _info_html(runner)
152
+        status.value = _info_html(runner)
153
+
154
+    runner.ioloop.create_task(update())
155
+
156
+    hbox = widgets.HBox(
157
+        (status, cancel),
158
+        description='Runner stats',
159
+        layout=widgets.Layout(border='solid 1px',
160
+                              width='200px',
161
+                              align_items='center'),
162
+    )
163
+    return display(hbox)
164
+
165
+
166
+def _info_html(runner):
167
+    info = [
168
+        ('status', runner.status()),
169
+        ('elapsed time', datetime.timedelta(seconds=runner.elapsed_time())),
170
+    ]
171
+
172
+    try:
173
+        info.append(('# of points', runner.learner.n))
174
+    except Exception:
175
+        pass
176
+
177
+    template = '<dt>{}</dt><dd>{}</dd>'
178
+    table = '\n'.join(template.format(k, v) for k, v in info)
179
+
180
+    return f'''
181
+        <dl>
182
+        {table}
183
+        </dl>
184
+    '''
Browse code

add a "cancel live-plot" button

Bas Nijholt authored on 16/02/2018 00:16:44 • Joseph Weston committed on 16/02/2018 16:18:15
Showing 1 changed files
... ...
@@ -82,6 +82,8 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
82 82
     except ModuleNotFoundError:
83 83
         raise RuntimeError('Plotting requires the holoviews Python package'
84 84
                            ' which is not installed.')
85
+    import ipywidgets
86
+    from IPython.display import display
85 87
 
86 88
     def plot_generator():
87 89
         while True:
... ...
@@ -113,4 +115,15 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
113 115
 
114 116
     active_plotting_tasks[name] = asyncio.get_event_loop().create_task(updater())
115 117
 
118
+    def cancel(_):
119
+        try:
120
+            active_plotting_tasks[name].cancel()
121
+        except KeyError:
122
+            pass
123
+
124
+    cancel_button = ipywidgets.Button(description='cancel live-plot',
125
+                                      layout=ipywidgets.Layout(width='150px'))
126
+    cancel_button.on_click(cancel)
127
+    display(cancel_button)
128
+
116 129
     return dm
Browse code

add live_plot doc-string

Bas Nijholt authored on 10/12/2017 12:55:50
Showing 1 changed files
... ...
@@ -57,6 +57,26 @@ active_plotting_tasks = dict()
57 57
 
58 58
 
59 59
 def live_plot(runner, *, plotter=None, update_interval=2, name=None):
60
+    """Live plotting of the learner's data.
61
+
62
+    Parameters
63
+    ----------
64
+    runner : Runner
65
+    plotter : function
66
+        A function that takes the learner as a argument and returns a
67
+        holoviews object. By default learner.plot() will be called.
68
+    update_interval : int
69
+        Number of second between the updates of the plot.
70
+    name : hasable
71
+        Name for the `live_plot` task in `adaptive.active_plotting_tasks`.
72
+        By default the name is `None` and if another task with the same name
73
+        already exists that other live_plot is canceled.
74
+
75
+    Returns
76
+    -------
77
+    dm : holoviews.DynamicMap
78
+        The plot that automatically updates every update_interval.
79
+    """
60 80
     try:
61 81
         import holoviews as hv
62 82
     except ModuleNotFoundError:
Browse code

fix broken live_plot reference and introduce multi plotting option

Bas Nijholt authored on 10/12/2017 12:24:21
Showing 1 changed files
... ...
@@ -53,10 +53,10 @@ def notebook_extension():
53 53
 
54 54
 # Plotting
55 55
 
56
-active_plotting_task = None
56
+active_plotting_tasks = dict()
57 57
 
58 58
 
59
-def live_plot(runner, *, plotter=None, update_interval=2):
59
+def live_plot(runner, *, plotter=None, update_interval=2, name=None):
60 60
     try:
61 61
         import holoviews as hv
62 62
     except ModuleNotFoundError:
... ...
@@ -84,12 +84,13 @@ def live_plot(runner, *, plotter=None, update_interval=2):
84 84
                 await asyncio.sleep(update_interval)
85 85
             dm.event()  # fire off one last update before we die
86 86
         finally:
87
-            global active_plotting_task
88
-            if active_plotting_task is asyncio.Task.current_task():
89
-                active_plotting_task = None
87
+            if active_plotting_tasks[name] is asyncio.Task.current_task():
88
+                active_plotting_tasks.pop(name, None)
90 89
 
91
-    if active_plotting_task:
92
-        active_plotting_task.cancel()
93
-    active_plotting_task = asyncio.get_event_loop().create_task(updater())
90
+    global active_plotting_tasks
91
+    if name in active_plotting_tasks:
92
+        active_plotting_tasks[name].cancel()
93
+
94
+    active_plotting_tasks[name] = asyncio.get_event_loop().create_task(updater())
94 95
 
95 96
     return dm
Browse code

allow only 1 active live plot at a time

Typically people will only want one live plot at a time, and this
avoids keeping several (typically expensive) background tasks
around. Also, set the active plot reference to None when the
live plot is cancelled.

Joseph Weston authored on 10/12/2017 00:03:44
Showing 1 changed files
... ...
@@ -53,10 +53,10 @@ def notebook_extension():
53 53
 
54 54
 # Plotting
55 55
 
56
-active_plotting_tasks = dict()
56
+active_plotting_task = None
57 57
 
58 58
 
59
-def live_plot(runner, *, plotter=None, update_interval=2, name=None):
59
+def live_plot(runner, *, plotter=None, update_interval=2):
60 60
     try:
61 61
         import holoviews as hv
62 62
     except ModuleNotFoundError:
... ...
@@ -73,9 +73,6 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
73 73
     dm = hv.DynamicMap(plot_generator(),
74 74
                        streams=[hv.streams.Stream.define('Next')()])
75 75
 
76
-    # Generate task name if not provided
77
-    if not name:
78
-        name = '_'
79 76
 
80 77
     # Could have used dm.periodic in the following, but this would either spin
81 78
     # off a thread (and learner is not threadsafe) or block the kernel.
... ...
@@ -87,13 +84,12 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
87 84
                 await asyncio.sleep(update_interval)
88 85
             dm.event()  # fire off one last update before we die
89 86
         finally:
90
-            active_plotting_tasks.pop(name, None)
87
+            global active_plotting_task
88
+            if active_plotting_task is asyncio.Task.current_task():
89
+                active_plotting_task = None
91 90
 
92
-    task = asyncio.get_event_loop().create_task(updater())
93
-
94
-    if name in active_plotting_tasks:
95
-        active_plotting_tasks[name].cancel()
96
-
97
-    active_plotting_tasks[name] = task
91
+    if active_plotting_task:
92
+        active_plotting_task.cancel()
93
+    active_plotting_task = asyncio.get_event_loop().create_task(updater())
98 94
 
99 95
     return dm
Browse code

cancel the unnamed active live_plot if a new unnamed live_plot is called

Bas Nijholt authored on 09/12/2017 21:37:46
Showing 1 changed files
... ...
@@ -55,10 +55,6 @@ def notebook_extension():
55 55
 
56 56
 active_plotting_tasks = dict()
57 57
 
58
-# Incremented by 'live_plot' on every successful plot creation;
59
-# used to name plots that are not given an explicit name.
60
-_last_plot_id = 0
61
-
62 58
 
63 59
 def live_plot(runner, *, plotter=None, update_interval=2, name=None):
64 60
     try:
... ...
@@ -78,10 +74,8 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
78 74
                        streams=[hv.streams.Stream.define('Next')()])
79 75
 
80 76
     # Generate task name if not provided
81
-    global _last_plot_id
82 77
     if not name:
83
-        name = f'plot_{_last_plot_id}'
84
-    _last_plot_id += 1
78
+        name = '_'
85 79
 
86 80
     # Could have used dm.periodic in the following, but this would either spin
87 81
     # off a thread (and learner is not threadsafe) or block the kernel.
... ...
@@ -97,6 +91,9 @@ def live_plot(runner, *, plotter=None, update_interval=2, name=None):
97 91
 
98 92
     task = asyncio.get_event_loop().create_task(updater())
99 93
 
94
+    if name in active_plotting_tasks:
95
+        active_plotting_tasks[name].cancel()
96
+
100 97
     active_plotting_tasks[name] = task
101 98
 
102 99
     return dm
Browse code

save live plotting tasks into internal datastructure

remove references to live plotting tasks from the Runner and
instead maintain a mapping from plot name to task. This avoids
polluting the runner, but also allows users to maintain references
to plotting tasks, so that they can cancel them at will.

Closes #38.

Joseph Weston authored on 09/12/2017 15:10:20
Showing 1 changed files
... ...
@@ -53,7 +53,14 @@ def notebook_extension():
53 53
 
54 54
 # Plotting
55 55
 
56
-def live_plot(runner, *, plotter=None, update_interval=2):
56
+active_plotting_tasks = dict()
57
+
58
+# Incremented by 'live_plot' on every successful plot creation;
59
+# used to name plots that are not given an explicit name.
60
+_last_plot_id = 0
61
+
62
+
63
+def live_plot(runner, *, plotter=None, update_interval=2, name=None):
57 64
     try:
58 65
         import holoviews as hv
59 66
     except ModuleNotFoundError:
... ...
@@ -70,19 +77,26 @@ def live_plot(runner, *, plotter=None, update_interval=2):
70 77
     dm = hv.DynamicMap(plot_generator(),
71 78
                        streams=[hv.streams.Stream.define('Next')()])
72 79
 
80
+    # Generate task name if not provided
81
+    global _last_plot_id
82
+    if not name:
83
+        name = f'plot_{_last_plot_id}'
84
+    _last_plot_id += 1
85
+
73 86
     # Could have used dm.periodic in the following, but this would either spin
74 87
     # off a thread (and learner is not threadsafe) or block the kernel.
75 88
 
76 89
     async def updater():
77
-        while not runner.task.done():
78
-            dm.event()
79
-            await asyncio.sleep(update_interval)
80
-        dm.event()  # fire off one last update before we die
90
+        try:
91
+            while not runner.task.done():
92
+                dm.event()
93
+                await asyncio.sleep(update_interval)
94
+            dm.event()  # fire off one last update before we die
95
+        finally:
96
+            active_plotting_tasks.pop(name, None)
81 97
 
82 98
     task = asyncio.get_event_loop().create_task(updater())
83 99
 
84
-    if not hasattr(runner, 'live_plotters'):
85
-        runner.live_plotters = []
100
+    active_plotting_tasks[name] = task
86 101
 
87
-    runner.live_plotters.append(task)
88 102
     return dm
Browse code

make holoviews optional in the notebook_extension

Bas Nijholt authored on 09/12/2017 02:05:27
Showing 1 changed files
... ...
@@ -1,50 +1,64 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 import asyncio
3
+from pkg_resources import parse_version
4
+import warnings
3 5
 
4 6
 from IPython import get_ipython
7
+import ipykernel
5 8
 from ipykernel.eventloops import register_integration
6 9
 
7 10
 
8
-# IPython event loop integraion
9
-
10
-@register_integration('asyncio')
11
-def _loop_asyncio(kernel):
12
-    '''Start a kernel with asyncio event loop support.'''
13
-    loop = asyncio.get_event_loop()
14
-
15
-    def kernel_handler():
16
-        loop.call_soon(kernel.do_one_iteration)
17
-        loop.call_later(kernel._poll_interval, kernel_handler)
18
-
19
-    loop.call_soon(kernel_handler)
20
-    # loop is already running (e.g. tornado 5), nothing left to do
21
-    if loop.is_running():
22
-        return
23
-    while True:
24
-        error = None
25
-        try:
26
-            loop.run_forever()
27
-        except KeyboardInterrupt:
28
-            continue
29
-        except Exception as e:
30
-            error = e
31
-        loop.run_until_complete(loop.shutdown_asyncgens())
32
-        loop.close()
33
-        if error is not None:
34
-            raise error
35
-        break
11
+# IPython event loop integration
12
+
13
+if parse_version(ipykernel.__version__) < parse_version('4.7.0'):
14
+    # XXX: remove this function when we depend on ipykernel>=4.7.0
15
+    @register_integration('asyncio')
16
+    def _loop_asyncio(kernel):
17
+        """Start a kernel with asyncio event loop support.
18
+        Taken from https://github.com/ipython/ipykernel/blob/fa814da201bdebd5b16110597604f7dabafec58d/ipykernel/eventloops.py#L294"""
19
+        loop = asyncio.get_event_loop()
20
+
21
+        def kernel_handler():
22
+            loop.call_soon(kernel.do_one_iteration)
23
+            loop.call_later(kernel._poll_interval, kernel_handler)
24
+
25
+        loop.call_soon(kernel_handler)
26
+        # loop is already running (e.g. tornado 5), nothing left to do
27
+        if loop.is_running():
28
+            return
29
+        while True:
30
+            error = None
31
+            try:
32
+                loop.run_forever()
33
+            except KeyboardInterrupt:
34
+                continue
35
+            except Exception as e:
36
+                error = e
37
+            loop.run_until_complete(loop.shutdown_asyncgens())
38
+            loop.close()
39
+            if error is not None:
40
+                raise error
41
+            break
36 42
 
37 43
 
38 44
 def notebook_extension():
39
-    import holoviews
40 45
     get_ipython().magic('gui asyncio')
41
-    return holoviews.notebook_extension('bokeh')
46
+    try:
47
+        import holoviews as hv
48
+        return hv.notebook_extension('bokeh')
49
+    except ModuleNotFoundError:
50
+        warnings.warn("The holoviews package is not installed so plotting"
51
+                      "will not work.", RuntimeWarning)
42 52
 
43 53
 
44 54
 # Plotting
45 55
 
46 56
 def live_plot(runner, *, plotter=None, update_interval=2):
47
-    import holoviews as hv
57
+    try:
58
+        import holoviews as hv
59
+    except ModuleNotFoundError:
60
+        raise RuntimeError('Plotting requires the holoviews Python package'
61
+                           ' which is not installed.')
48 62
 
49 63
     def plot_generator():
50 64
         while True:
Browse code

live_plotter, remove false statement

Bas Nijholt authored on 09/12/2017 01:03:16
Showing 1 changed files
... ...
@@ -65,7 +65,6 @@ def live_plot(runner, *, plotter=None, update_interval=2):
65 65
             await asyncio.sleep(update_interval)
66 66
         dm.event()  # fire off one last update before we die
67 67
 
68
-    # Fire and forget -- the task will die anyway once the runner has finished.
69 68
     task = asyncio.get_event_loop().create_task(updater())
70 69
 
71 70
     if not hasattr(runner, 'live_plotters'):
Browse code

add runner.live_plotters with live plotting tasks

Bas Nijholt authored on 08/12/2017 17:42:45
Showing 1 changed files
... ...
@@ -66,6 +66,10 @@ def live_plot(runner, *, plotter=None, update_interval=2):
66 66
         dm.event()  # fire off one last update before we die
67 67
 
68 68
     # Fire and forget -- the task will die anyway once the runner has finished.
69
-    asyncio.get_event_loop().create_task(updater())
69
+    task = asyncio.get_event_loop().create_task(updater())
70 70
 
71
+    if not hasattr(runner, 'live_plotters'):
72
+        runner.live_plotters = []
73
+
74
+    runner.live_plotters.append(task)
71 75
     return dm
Browse code

add missing holoviews import

Bas Nijholt authored on 03/12/2017 17:02:19
Showing 1 changed files
... ...
@@ -36,14 +36,15 @@ def _loop_asyncio(kernel):
36 36
 
37 37
 
38 38
 def notebook_extension():
39
-    import holoviews as hv
39
+    import holoviews
40 40
     get_ipython().magic('gui asyncio')
41
-    return hv.notebook_extension('bokeh')
41
+    return holoviews.notebook_extension('bokeh')
42 42
 
43 43
 
44 44
 # Plotting
45 45
 
46 46
 def live_plot(runner, *, plotter=None, update_interval=2):
47
+    import holoviews as hv
47 48
 
48 49
     def plot_generator():
49 50
         while True:
Browse code

move the holoviews import to the plotting function

Bas Nijholt authored on 30/11/2017 21:23:53
Showing 1 changed files
... ...
@@ -3,7 +3,6 @@ import asyncio
3 3
 
4 4
 from IPython import get_ipython
5 5
 from ipykernel.eventloops import register_integration
6
-import holoviews as hv
7 6
 
8 7
 
9 8
 # IPython event loop integraion
... ...
@@ -37,6 +36,7 @@ def _loop_asyncio(kernel):
37 36
 
38 37
 
39 38
 def notebook_extension():
39
+    import holoviews as hv
40 40
     get_ipython().magic('gui asyncio')
41 41
     return hv.notebook_extension('bokeh')
42 42
 
Browse code

fix keyboard interupt problem in notebook, see MR !29

Bas Nijholt authored on 27/11/2017 13:22:22
Showing 1 changed files
... ...
@@ -18,12 +18,22 @@ def _loop_asyncio(kernel):
18 18
         loop.call_later(kernel._poll_interval, kernel_handler)
19 19
 
20 20
     loop.call_soon(kernel_handler)
21
-    try:
22
-        if not loop.is_running():
21
+    # loop is already running (e.g. tornado 5), nothing left to do
22
+    if loop.is_running():
23
+        return
24
+    while True:
25
+        error = None
26
+        try:
23 27
             loop.run_forever()
24
-    finally:
28
+        except KeyboardInterrupt:
29
+            continue
30
+        except Exception as e:
31
+            error = e
25 32
         loop.run_until_complete(loop.shutdown_asyncgens())
26 33
         loop.close()
34
+        if error is not None:
35
+            raise error
36
+        break
27 37
 
28 38
 
29 39
 def notebook_extension():
Browse code

change default update_interval to 2 seconds, since plotting blocks the kernel

Bas Nijholt authored on 13/10/2017 14:22:47
Showing 1 changed files
... ...
@@ -33,7 +33,7 @@ def notebook_extension():
33 33
 
34 34
 # Plotting
35 35
 
36
-def live_plot(runner, *, plotter=None, update_interval=0.1):
36
+def live_plot(runner, *, plotter=None, update_interval=2):
37 37
 
38 38
     def plot_generator():
39 39
         while True:
Browse code

change live_plot update_interval to 0.1 seconds

Bas Nijholt authored on 14/09/2017 12:41:07
Showing 1 changed files
... ...
@@ -33,7 +33,7 @@ def notebook_extension():
33 33
 
34 34
 # Plotting
35 35
 
36
-def live_plot(runner, *, plotter=None, update_interval=1):
36
+def live_plot(runner, *, plotter=None, update_interval=0.1):
37 37
 
38 38
     def plot_generator():
39 39
         while True:
Browse code

plot final learner state before runner dies

Joseph Weston authored on 23/08/2017 15:16:04
Showing 1 changed files
... ...
@@ -52,6 +52,7 @@ def live_plot(runner, *, plotter=None, update_interval=1):
52 52
         while not runner.task.done():
53 53
             dm.event()
54 54
             await asyncio.sleep(update_interval)
55
+        dm.event()  # fire off one last update before we die
55 56
 
56 57
     # Fire and forget -- the task will die anyway once the runner has finished.
57 58
     asyncio.get_event_loop().create_task(updater())
Browse code

reorganise adaptive learners and runners into a package

Joseph Weston authored on 18/08/2017 11:12:32
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,59 @@
1
+# -*- coding: utf-8 -*-
2
+import asyncio
3
+
4
+from IPython import get_ipython
5
+from ipykernel.eventloops import register_integration
6
+import holoviews as hv
7
+
8
+
9
+# IPython event loop integraion
10
+
11
+@register_integration('asyncio')
12
+def _loop_asyncio(kernel):
13
+    '''Start a kernel with asyncio event loop support.'''
14
+    loop = asyncio.get_event_loop()
15
+
16
+    def kernel_handler():
17
+        loop.call_soon(kernel.do_one_iteration)
18
+        loop.call_later(kernel._poll_interval, kernel_handler)
19
+
20
+    loop.call_soon(kernel_handler)
21
+    try:
22
+        if not loop.is_running():
23
+            loop.run_forever()
24
+    finally:
25
+        loop.run_until_complete(loop.shutdown_asyncgens())
26
+        loop.close()
27
+
28
+
29
+def notebook_extension():
30
+    get_ipython().magic('gui asyncio')
31
+    return hv.notebook_extension('bokeh')
32
+
33
+
34
+# Plotting
35
+
36
+def live_plot(runner, *, plotter=None, update_interval=1):
37
+
38
+    def plot_generator():
39
+        while True:
40
+            if not plotter:
41
+                yield runner.learner.plot()
42
+            else:
43
+                yield plotter(runner.learner)
44
+
45
+    dm = hv.DynamicMap(plot_generator(),
46
+                       streams=[hv.streams.Stream.define('Next')()])
47
+
48
+    # Could have used dm.periodic in the following, but this would either spin
49
+    # off a thread (and learner is not threadsafe) or block the kernel.
50
+
51
+    async def updater():
52
+        while not runner.task.done():
53
+            dm.event()
54
+            await asyncio.sleep(update_interval)
55
+
56
+    # Fire and forget -- the task will die anyway once the runner has finished.
57
+    asyncio.get_event_loop().create_task(updater())
58
+
59
+    return dm