Quiby ipywidgets

Quibs can easily connect with ipywidgets

Quibs can be used as arguments in ipywidgets, creating “quiby widgets” that are bi-directionally to their quib arguments. Any change to upstream quibs is propagated downstream to affect the widgets; and, conversely, user interactions with the widgets is inverse propagated backwards to affect the values of upstream quibs. Combining quibs with ipywidgets and graphics, we can thereby readily and easily create interactive app-like analysis of our data.

Imports

from pyquibbler import iquib, initialize_quibbler
initialize_quibbler()

import ipywidgets as ipyw

Using quibs as arguments in ipywidgets creates quiby widgets

When we execute an ipywidget function with quib arguments, we get a quiby widget - a widget that is bi-directionally linked to the value of the quib. Setting the widget affect the value of the quib and changing the quib value affects the widget.

For example:

_images/quiby-ipywidgets-bidirectional.gif

As the quib changes, any downstream quibs, graphics and widgets will also be affected.

For example:

_images/quiby-ipywidgets-bob-alice.gif

Any widget trait can be a quib

Quibs can be used as arguments not only for the ‘value’ of an ipywidget, but also for any other traits, making these traits dynamically dependent on the quib’s value.

For example, we can set the min and the max of a Slider according to the values of a quib that are set in another slider:

Quibs can be used as arguments not only for the ‘value’ of an ipywidget, but also for other traits, making these traits dependent on the quib’s value.

For example, we can set the min and max of a Slider according to the values of a quib that are set in another slider:

min_max = iquib([0, 100])
value = iquib(20)
ipyw.VBox([
    ipyw.IntRangeSlider(value=min_max),
    ipyw.IntSlider(value=value, min=min_max[0], max=min_max[1]),
])
_images/quiby-ipywidgets-min-max.gif

Quibbler-based GUI applications

Combining ipywidgets and graphics with quibs allows us to quickly build interactive applications.

As an example, consider an app to allow playing with the parameters of an ODE solver. In particular, we implement here an app for solving the Lorenz equations:

%matplotlib widget

import pyquibbler as qb
from pyquibbler import iquib, quiby
qb.initialize_quibbler()

import ipywidgets as ipyw
import numpy as np
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt


@quiby
def solve_lorenz(y0, t_final, s, r, b):

    def lorenz_dydt(t, y):

        xp = s*(y[1] - y[0])
        yp = y[0] * (r - y[2]) - y[1]
        zp = y[0]*y[1] - b*y[2]

        return np.asarray([xp, yp, zp])

    return solve_ivp(lorenz_dydt, [0, t_final], y0, method='RK45', rtol=1e-6)

# Define parameters
sigma = iquib(10.)
rho = iquib(28.)
beta = iquib(2.667)

t_final = iquib(40)
y0 = iquib([.2, .3, .4])

# solve the ODEs
sol = solve_lorenz(y0, t_final, sigma, rho, beta)
y = sol['y']

# plot solution
output = ipyw.Output()
with output:
    fig = plt.figure(figsize=(4, 3))
    fig.canvas.toolbar_visible = False
    fig.canvas.header_visible = False
    fig.canvas.footer_visible = False
    fig.canvas.toolbar_visible = False
    fig.canvas.header_visible = False
    fig.canvas.resizable = False
    ax = plt.axes([0, 0, 1, 1], projection='3d')
    ax.plot3D(y[0], y[1], y[2], 'blue', linewidth=0.5);
    plt.show()
widgets = ipyw.VBox([
    ipyw.FloatSlider(sigma, description='sigma'),
    ipyw.FloatSlider(rho, description='rho'),
    ipyw.FloatSlider(beta, description='beta'),
    ipyw.FloatSlider(t_final, description='total time'),
])
ipyw.HBox([widgets, output])
_images/quiby-ipywidgets-lorenz.gif

See also