Interactive timer in Jupyter notebook

I have a function that writes data and takes a while. While the data is being recorded, I would like to have a button that, when clicked, displays how much time has passed since the start of data collection.

Can this be done in Jupyter?

I am having problems because data collection is blocking the activation of the widget, and if I try to run the widget in the background, it will not receive an event on_click

until the data collection is complete. On the other hand, if I send the data collection to the background, then the data is lost after the background job completes.

Background job

from IPython.lib.backgroundjobs import BackgroundJobManager
from IPython.core.magic import register_line_magic
from IPython import get_ipython

jobs = BackgroundJobManager()

@register_line_magic
def background_job(line):
    ip = get_ipython()
    jobs.new(line, ip.user_global_ns)

      

Timer button

import ipywidgets as widgets
import time

def button_timer():
    t0 = 0
    button = widgets.Button(description="Measure time")
    def action(b):
        time_elapsed = time.perf_counter() - t0
        display("Time elapsed: {}".format(time_elapsed))
    button.on_click(action)

    display(button)
    t0 = time.perf_counter()

      

Data collection

import numpy as np
import pandas as pd
import time

def acquire(a=None):
    time.sleep(10)
    print("Done")
    if a is None:
        return np.linspace(0, 10, 10)
    else:
        a = np.linspace(0, 10, 10)

## Implementation 1
# This fails because the `on_click` event for the button only runs after the data has been acquired.
button_timer()
data = pd.DataFrame()
data['x'] = np.linspace(0, 10, 10)
data['y'] = acquire()

## Implementation 2
# As before, the `on_click` event isn't activated until after the data has been acquired.
%background_job button_timer()
data = pd.DataFrame()
data['x'] = np.linspace(0, 10, 10)
data['y'] = acquire()

## Implementation 3
# This one fails as the data isn't actually updated
button_timer()
data = pd.DataFrame()
data['x'] = np.linspace(0, 10, 10)
# I can't use the equal sign as that isn't supported by the background job.
# %background_job data['y'] = acquire()
# If I pass in the data I want, the DataFrame isn't updated (even after I wait for the background job to finish)
%background_job acquire(data['y'])
display(data)

      


If all else fails, I suppose one option would only have a Javascript timer that works entirely in the browser.

However, I'm wondering if there is a way to do this in Python (and, if possible, have it in such a way that the (last) measured time is programmatically available in the rest of the notebook).

+3


source to share





All Articles