Skip to content Skip to sidebar Skip to footer

Jupyter And Timer Functions?

I am using Jupyter via Anaconda on Windows 10. I would like to have a plot, on which a new random value is plotted each second. So far, I have this code: import plotly.graph_objs a

Solution 1:

Ok, got somewhere, thanks to these:

First of all, here is a reworked simple example from the link above, which shows the use of IPython.lib.backgroundjobs.BackgroundJobManager:

#https://stackoverflow.com/questions/32081926/a-new-thread-for-running-a-cell-in-ipython-jupyter-notebook##github.com/jupyter/ngcm-tutorial/blob/master/Day-1/IPython%20Kernel/Background%20Jobs.ipynbimport sched, time # NOTE: without this import, we'll get "Dead jobs:" instead of "Running jobs:" - exception at time.sleep will not be reported as such!from IPython.lib import backgroundjobs as bg
jobs = bg.BackgroundJobManager()

defprintfunc(interval=1, reps=5):
    for n inrange(reps):
        time.sleep(interval)
        print('In the background... %i' % n)
        #sys.stdout.flush() # flush breaks the thread in Jupyter, after first printout!print('All done!')
    #sys.stdout.flush()#jobs.new('printfunc(1,3)') # works; prints: <BackgroundJob #0: printfunc(1,3)>
jobs.new(printfunc, 1, 3) # works; prints: <BackgroundJob #0: <function printfunc at 0x0000017120038730>>
jobs.status() # prints: "Running jobs:" "0 : <function printfunc at 0x00000171200389D8>" or "0 : printfunc(1,3)"

Here is how it looks like in Jupyter notebook:

jupyter_background_jobs_01.gif

That lead finally to getting the OP example to work - simply, by having the scheduler.run be called through jobs.new:

import plotly.graph_objs as go
import numpy as np
import sched, time
import random
from ipywidgets import widgets

from IPython.lib import backgroundjobs as bg
jobs = bg.BackgroundJobManager()

xs = np.linspace(0, 10, 100)
ys = np.zeros(100)

fig = go.FigureWidget()
fig.add_trace(go.Scatter(x=xs, y=ys,
                    mode='lines',
                    name='Random'))
fig.update_xaxes(range=[0, 10])
fig.update_yaxes(range=[0, 10])

s = sched.scheduler(time.time, time.sleep)
yi = 0
do_run_tick_func = Truedeftick_func(sc):
    global ys, yi
    if do_run_tick_func:
        ys[yi] = random.random() * 10
        yi = (yi+1)%100
        fig.data[0].y = ys
        s.enterabs(time.time()+1, 1, tick_func, (sc,))
    else:
        print("Exiting tick_func (not recheduling)") # this does not print on page#s.enterabs(time.time()+15, 1, tick_func, (s,))#s.run() # kills widget#s.run()#jobs.new(s.enterabs, time.time()+2, 1, tick_func, (s,)) # Does not run in loop, but says: Completed jobs: 0 : <bound method scheduler.enterabs of <sched.scheduler object at 0x000001E01CF12978>>#jobs.new(tick_func, s) # runs once, does not loop: Allo 0; Completed jobs: 0 : <function tick_func at 0x0000017120038400>

s.enterabs(time.time()+1, 1, tick_func, (s,))
jobs.new(s.run) # runs in loop! Running jobs: 0 : <bound method scheduler.run of <sched.scheduler object at 0x0000017120058390>>#jobs.status() # prints: "Running jobs:" ...# https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Events.html
output = widgets.Output()
mybuttonstop = widgets.Button(description="Stop Background Thread")
mybuttonstart = widgets.Button(description="Start Background Thread")

defon_button_stop_clicked(b):
    global do_run_tick_func
    print("Button clicked - stopping background thread...") # this does print on page
    do_run_tick_func = Falsewith output:
        print("print, with output?") # this does not print on pagedefon_button_start_clicked(b):
    global do_run_tick_func
    print("Button clicked - starting background thread...") # this does print on page
    do_run_tick_func = True
    s.enterabs(time.time()+1, 1, tick_func, (s,))
    jobs.new(s.run)

mybuttonstop.on_click(on_button_stop_clicked)
mybuttonstart.on_click(on_button_start_clicked)

myhbox = widgets.HBox([mybuttonstart, mybuttonstop])
widgets.VBox([myhbox, fig])

Here is how this looks like in Jupyter notebook:

jupyter_background_jobs_02.gif

Solution 2:

The basic problem is that the code cell which displays a widget must finish executing before the widget will display.

What you need is a way for the widget to call back to the Python kernel after it has initialized in order to request an update. You could implement this using proxy widgets like this.

enter image description here

You can also combine proxy widgets with other widget types using HBox, etcetera and use the proxy widget for timing purposes as shown above.

Please see https://github.com/AaronWatters/jp_proxy_widget and the discussion of asynchronicity of widgets in the Tutorial notebook.

Post a Comment for "Jupyter And Timer Functions?"