wf.widgets makes it easy to interactively explore your Workflows code.

You can use widgets inline in your code, just like normal values. Then, when you call visualize, all the necessary widgets automatically display beneath the notebook cell. No need to learn about ipywidgets, or set up complex links or callback functions.

For example, say you were trying to pick the ideal threshold for an Image:

>>> threshold = img > 0.3
>>> threshold.visualize(...)

Instead of tweaking the 0.3 and rerunning visualize over and over again, you could just replace the 0.3 with a slider widget:

>>> threshold = img > wf.widgets.slider("threshold", min=0, max=1, default=0.3)
>>> threshold.visualize(...)

Then, a slider would show up under that cell, letting you adjust the threshold value interactively.

Think of it as though calling a widget function (like wf.widgets.slider(...)) returns whatever the current value of that widget is. When that value changes, Workflows automatically reruns whatever code needs to rerun (like Observable or Streamlit does).

You don’t have to keep track of which objects depend on which widgets, or what to rerun when a widget changes—Workflows handles all that for you automatically.

Widget objects

To use widgets in advanced ways—such as triggering functions to run when widgets are changed, or changing current widget values with code—you’ll need to work with the Widget objects returned by wf.widgets functions.

All widgets are subclasses of the Widget base class, as well as the Workflows type they represent. Widget objects act like normal Workflows values (really, like parameter values), but they also have a widget attribute which holds an actual ipywidget object (which is what gets displayed in your notebook).

You can use that ipywidget object however you wish. For example, you can get/set .value, or use .observe to register a function to run when the value changes. If you’re not familiar, read the ipywidgets documentation.

For convenience, Widget also provides value and observe, which are equivalent to .widget.value and .widget.observe.

So, to get or change the current value of a widget in code, use its value attribute:

>>> threshold_slider = wf.widgets.slider("threshold", min=0, max=1, default=0.3)
>>> threshold_slider.value = 0.2

Or, to trigger a function to run when a widget changes:

>>> threshold_slider = wf.widgets.slider("threshold", min=0, max=1, default=0.3)
>>> def on_slider_change(change):
...     print(f"new slider value: {threshold_slider.value}")
>>> threshold_slider.observe(on_slider_change, names="value")

Tip: when using observe, you should almost always pass names="value". Otherwise, your callback could be triggered more often than you expect. This is particularly important if you’re calling compute or inspect in your callback.

Publishing objects with Widgets

When you publish an object that depends on widgets, it internally gets converted into a Function (using Function.from_object).

When other users are browsing shared Workflows with wf.flows, and they click “Add to map” on your Workflow, the same widgets you used will show up for them.