Graphical User Interfaces#
Graphic User Interface (GUI) is an efficient tool for lab automation, it can help engineers save time, generate straight-forward data visualization and provide centralized control system.
Jupyter notebook ipywidgets is a good candidate for GUI in jupyter notebook. There are other tools available (such as bokeh server).
What are widgets? Eventful python objects that can have a representation in the browser, often as a control like a slider, textbox, etc.
Learning Outcomes#
Understand intactive ipywdigets features
Ipywidgets list
Build a simple GUI based on ipywidgets
Asynchronous widgets with threading (advanced)
Requirements#
Confirm you have ipywidgets installed by checking ‘pip list’ in command window.
If not, please try ‘conda install -c conda-forge ipywidgets’ in command window.
Interactive ipywidgets#
‘interact’ function automatically creates user interface controls for exploring code and data interactivelly.
General conecept:
define a function
link the function and ipywidgets with ‘interact’ function and function parameters
## load necessary libraries
from __future__ import print_function
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
## define a function of interest
def f(x):
return x**2.
## define an interaction with a slider
interact(f,x = 10)
<function __main__.f(x)>
## previous example is simple, but without much explanation.
## We will show another example here to give you a better idea about interact function.
interact(f,x = widgets.IntSlider(min = -10, max = 30, step = 1, value = 10))
<function __main__.f(x)>
## more examples
def f_show(x):
print(x)
interact(f_show,x = ['Apple','Orange','Strawberry'])
<function __main__.f_show(x)>
help(interact)
Help on _InteractFactory in module ipywidgets.widgets.interaction object:
class _InteractFactory(builtins.object)
| _InteractFactory(cls, options, kwargs={})
|
| Factory for instances of :class:`interactive`.
|
| This class is needed to support options like::
|
| >>> @interact.options(manual=True)
| ... def greeting(text="World"):
| ... print("Hello {}".format(text))
|
| Parameters
| ----------
| cls : class
| The subclass of :class:`interactive` to construct.
| options : dict
| A dict of options used to construct the interactive
| function. By default, this is returned by
| ``cls.default_options()``.
| kwargs : dict
| A dict of **kwargs to use for widgets.
|
| Methods defined here:
|
| __call__(self, _InteractFactory__interact_f=None, **kwargs)
| Make the given function interactive by adding and displaying
| the corresponding :class:`interactive` widget.
|
| Expects the first argument to be a function. Parameters to this
| function are widget abbreviations passed in as keyword arguments
| (``**kwargs``). Can be used as a decorator (see examples).
|
| Returns
| -------
| f : __interact_f with interactive widget attached to it.
|
| Parameters
| ----------
| __interact_f : function
| The function to which the interactive widgets are tied. The `**kwargs`
| should match the function signature. Passed to :func:`interactive()`
| **kwargs : various, optional
| An interactive widget is created for each keyword argument that is a
| valid widget abbreviation. Passed to :func:`interactive()`
|
| Examples
| --------
| Render an interactive text field that shows the greeting with the passed in
| text::
|
| # 1. Using interact as a function
| def greeting(text="World"):
| print("Hello {}".format(text))
| interact(greeting, text="Jupyter Widgets")
|
| # 2. Using interact as a decorator
| @interact
| def greeting(text="World"):
| print("Hello {}".format(text))
|
| # 3. Using interact as a decorator with named parameters
| @interact(text="Jupyter Widgets")
| def greeting(text="World"):
| print("Hello {}".format(text))
|
| Render an interactive slider widget and prints square of number::
|
| # 1. Using interact as a function
| def square(num=1):
| print("{} squared is {}".format(num, num*num))
| interact(square, num=5)
|
| # 2. Using interact as a decorator
| @interact
| def square(num=2):
| print("{} squared is {}".format(num, num*num))
|
| # 3. Using interact as a decorator with named parameters
| @interact(num=5)
| def square(num=2):
| print("{} squared is {}".format(num, num*num))
|
| __init__(self, cls, options, kwargs={})
| Initialize self. See help(type(self)) for accurate signature.
|
| options(self, **kwds)
| Change options for interactive functions.
|
| Returns
| -------
| A new :class:`_InteractFactory` which will apply the
| options when called.
|
| widget(self, f)
| Return an interactive function widget for the given function.
|
| The widget is only constructed, not displayed nor attached to
| the function.
|
| Returns
| -------
| An instance of ``self.cls`` (typically :class:`interactive`).
|
| Parameters
| ----------
| f : function
| The function to which the interactive widgets are tied.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
ipywidget list#
There are many ipywidgets
We list 5 frequent used ones here.
widgets.Button(
description='button',
disabled=False,
button_style='success', # 'success', 'info', 'warning', 'danger' or ''
tooltip='button',
icon=''
)
widgets.Text(
value='Text',
placeholder='Type...',
description='Text Area:',
disabled=False
)
widgets.FloatSlider(
value=1.,
min=0,
max=10.0,
step=0.1,
description='Float Slider:',
disabled=False,
continuous_update=False,
orientation='horizontal',
readout=True,
readout_format='.1f',
)
widgets.Checkbox(
value=False,
description='Check Box',
disabled=False
)
widgets.RadioButtons(
options=['Ant Man', 'Venom', 'Spider Man'],
value='Venom',
description='Best movie?:',
disabled=False
)
Build a simple GUI based on ipywidgets#
float slider for changing the parameters
dropdown menu for selecting curve equations
plot in output widgets
from IPython.display import display,clear_output
import numpy as np
from matplotlib.pyplot import *
### functions
def linear_func(beta):
x = np.arange(0,100)
y = beta*x+10.
return x,y
def quad_func(beta):
x = np.arange(0,100)
y = beta*x**2.+10.
return x,y
def exp_func(beta):
x = np.arange(0,100)
y = np.exp(beta*x)+10.
return x,y
### widgets
beta_slider = widgets.FloatSlider(value = 0.2,
min = 0.01,
max = 1.,
step = 0.01,
description = 'beta',
continuous_update=False,
readout_format = '.2f')
dropdown_menu = widgets.Dropdown(options = ['linear','quadratic polynomial','exponential'],
value = 'linear')
update_button = widgets.Button(description='Update',
disabled=False,
button_style='success', # 'success', 'info', 'warning', 'danger' or ''
tooltip='button',
icon='')
out_plot = widgets.Output()
### layout
Hbox_options = widgets.HBox([beta_slider,
dropdown_menu,
update_button])
Vbox = widgets.VBox([Hbox_options,
out_plot])
### link function with widgets
def update_button_clicked(b):
if dropdown_menu.value == 'linear':
x,y = linear_func(beta_slider.value)
elif dropdown_menu.value == 'quadratic polynomial':
x,y = quad_func(beta_slider.value)
elif dropdown_menu.value == 'exponential':
x,y = exp_func(beta_slider.value)
with out_plot:
clear_output(wait = True)
plot(x,y)
xlabel('x-axis')
ylabel('y-axis')
grid()
xlim(0,100)
ylim(0,1000)
show()
update_button.on_click(update_button_clicked)
display(Vbox)
Asynchronous widgets with threading (supplementary material)#
Sometimes we need widgets run in the background, this is where asynchronous widgets kick in.
We handle this type of requirement with threads.
In this example, we will have a progress bar keep updating in the background, and we can change the current position of the progress bar based on current kernel request.
import threading
import numpy as np
from IPython.display import display
import ipywidgets as widgets
import time
progress = widgets.FloatProgress(value=0.0, min=0.0, max=1.0)
input_slider = widgets.FloatSlider(value = 0,
min = 0,
max = 30,
step = 1,
description = 'update this:',
continuous_update = False)
status_checkbox = widgets.Checkbox(value = False,
description = 'Running',
disabled = False)
i = []
i.append(0)
def work(i,progress,status_checkbox):
k = 0
while True:
if status_checkbox.value:
m = np.mod(i[0]+k,100)
time.sleep(2.)
progress.value = float(m+1)/100.
k += 1
thread = threading.Thread(target=work, args=(i,progress,status_checkbox))
display(progress)
thread.start()
def slider_change(change):
i[0] = input_slider.value
print(i[0])
input_slider.observe(slider_change,names = 'value')
display(input_slider)
display(status_checkbox)