Widgets don't preserve user selected inputs after a kernel restart

After a kernel restart widgets are not preserving the user-selected inputs. Here is the use case:
I create a notebook with multiple widgets, and save the notebook. After a kernel restart, if I run the notebook again, the widgets doesn’t retain the values and I am forced to enter the values again. If I save widget state(An option from Settings), then the notebook is loaded with the values I selected. But, if I run the cells, the values are cleared.

This looks like a common use case. How can I make widgets to preserve the user entered values?

by default the widget state is not stored on save. you can manually save notebook widget state or configure Lab’s settings so Jupyter Widgets will Save widget state in notebooks.

2 Likes

Once the widget state is saved, I can load the notebook and see the values I entered. If I run the cell, then the values are getting cleared. I want to run the cells with values whatever I entered.
Say if a text box is created with default value as ‘Test’ and I changed the value to ‘Test Passed’. I saved the notebook. After a kernel restart, If I run the same cell again, then ‘Test Passed’ value is cleared and the default value ‘Test’ is displayed.
Instead of me typing ‘Test Passed’ value again, I want the widget to remember the value I entered. Is it possible to do that in Jupyter notebooks?

well that is a different kind of ask. i don’t you’ll find those abilities in core jupyter or IPython. someone might have written an extension that does this. maybe ipyflow has some of these features.

Thank you. Zeppelin currently has this feature and this is a common use case for us in our org. We create notebooks with preselected widget values and give the notebook to someone else who changes only a few widget values or maybe just the dataset they’re running it against. We want the widget values to be retained no matter how many times the notebook is imported/exported.

1 Like

Could you share how zeppelin does this? How does it link the initial value with the code that is executing in the notebook.

This is how Zeppelin does it: zeppelin/GUI.java at 11052f6fb435c812788a5f30211b9d71842f9182 · apache/zeppelin · GitHub

Zeppelin checks to see if there is already a value, if it is there it uses that value. And if there isn’t it uses the default.

We have used Apache Zeppelin notebooks for several years, and although their interactive widgets are limited (just textboxes, pull-downs, and checkboxes), they have the desirable property of recalling user-entered values, even after restarting a kernel. We find this especially helpful for creating reproducible results.

Zeppelin defines and stores “forms” via its ZeppelinContext (‘z’) object, and once the user enters or selects a value in a Zeppelin form, that value is preserved and restored, even after you terminate the kernel, then close, reopen, and rerun the notebook. This behavior is essential for ensuring repeatable notebook results and is convenient for users who need to pause and resume their work later. Further,
if you share a ‘configured’ notebook with another user, they clearly see the choices you made, and if they choose to rerun it without alteration, the notebook will produce the same results, without demanding that user re-select the widget values once again.

JupyterLab’s ipywidgets do not share this desirable behavior. Instead, when you restart a kernel in JupyterLab, any values entered in widgets are lost. Each time the user runs a cell defining the widget, a new runtime widget is created, using the value dictated by its programmatic default, and discarding any value previously chosen by the notebook user. As a result, the user must re-enter the same values each time they run the notebook.

To solve this issue, we created a helper class, ipwstore, to store widget values in a separate sidecar file. When the notebook is re-run, the prior widget values are recovered from the sidecar file, and then used to update the live widget objects, creating a reproducible notebook result. Here are the details of our solution:

Sidecar File
The sidecar file is a plain text JSON document holding a unique key for every registered widget and each widget’s value. This file is created (or opened) when the class object is initialized. Widget values are persisted to the file if the user invokes the save() function, or automatically on destruction of the ipwstore object (e.g., when the user terminates the kernel).
Helper Class
Our helper class has a constructor and two main methods – add and save.
Constructor
The constructor that creates the ipwstore object requires the name of a sidecar (JSON) file. If that file already exists, the object populates its registry of widget keys and values from the JSON. If the file does not exist, a new file is opened for writing. We expect that each notebook will use its own sidecar file.

Add Method
The add method requires a unique key and an ipywidgets object. The notebook author should call the add method for each new widget created (except for any widget that needn’t persist its state). This method binds each live widget object to a unique key in its registry, enabling the widget’s value to be persisted to the JSON file and recovered later. The same method also assigns a live widget’s value from the values previously cached in the JSON (provided a matching key was present in the JSON file), creating a “replay from memory” of its prior state.
Save Method
The save method writes the widget keys and values to the sidecar file and is automatically invoked on destruction of the ipwstore object. As a result, the JSON file is automatically updated as the notebook kernel is normally terminated. (Aside from exploring the functionality, or to ensure persistence prior to an abnormal termination, there is no need to explicitly call the save method.)
Usage Summary
To use our helper class, the notebook author should instantiate a single ipwstore object near the beginning of the notebook, pointing to a unique sidecar file, and should register each new widget under a unique key using the add method.
Shortcomings of this Class
The three key drawbacks of this are: (1) the need to explicitly declare a sidecar file, which essentially divides the notebook into two parts: a “template” JupyterLab notebook containing all the code, and a collection of user-selected configurations in the JSON file, (2) the burden of invoking the add method for each widget, and (3) the burden of carefully providing a unique key for each widget.
To aid with (3), if you wish to be warned about any risk of accidentally duplicated keys, you can construct your ipwstore object in “developer mode” by setting strict_add=True. When your notebook has all the widgets it needs, you can reset the constructor to its more forgiving default (strict_add=False).