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 2 changed files
... ...
@@ -1,5 +1,6 @@
1 1
 # -*- coding: utf-8 -*-
2
-from .notebook_integration import notebook_extension, live_plot
2
+from .notebook_integration import (notebook_extension, live_plot,
3
+                                   active_plotting_tasks)
3 4
 
4 5
 from . import learner
5 6
 from . import runner
... ...
@@ -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