In [1]:
import ipywidgets as widgets
from IPython.display import display

Simple examples


In [2]:
slider = widgets.FloatSlider(description='$x$', value=4)
text = widgets.FloatText(
    disabled=True, 
    value = slider.value ** 2,
    description='$x^2$'
)

def compute(*args):
    text.value = str(slider.value ** 2)
    
slider.observe(compute, 'value')

view = widgets.VBox([slider, text])
display(view)



In [3]:
a = widgets.FloatText()
b = widgets.FloatSlider()

display(a,b)
mylink = widgets.jslink((a, 'value'), (b, 'value'))



In [ ]:
# mylink.unlink()

Linking


In [4]:
fwidg_paps = widgets.FloatSlider(
    value=47.2,
    min=0,
    max=100.0,
    step=0.1,
    description='Age of Paps:',
    disabled=False,
    continuous_update=False,
    orientation='vertical',
    readout=True,
    readout_format='.1f',
)

fwidg_mams = widgets.FloatSlider(
    value=fwidg_paps.value - 4,
    min=0,
    max=100.0,
    step=0.1,
    description='Age of Mams:',
    disabled=False,
    continuous_update=True,
    orientation='vertical',
    readout=True,
    readout_format='.1f',
)

display(widgets.HBox([fwidg_paps, fwidg_mams]))

def update_paps(*args):
    fwidg_paps.value = fwidg_mams.value + 4
    
def update_mams(*args):
    fwidg_mams.value = fwidg_paps.value - 4
    
fwidg_mams.observe(update_paps, 'value')
fwidg_paps.observe(update_mams, 'value')

# observe(func, attribute_name) means: 
# If I change, please run the function if the attrubute with
#     name attribute_name is changed.



In [ ]:


In [ ]:


In [ ]:
widgets.FloatProgress(
    value=7.5,
    min=0,
    max=10.0,
    step=0.1,
    description='Loading:',
    bar_style='info',
    orientation='horizontal',

)

In [6]:
txt = widgets.Text()
options=list(range(8))
main_title = widgets.Label("Cycle selector")
description = widgets.Label("Select one")
sel = widgets.Select(
    options=options,
    value=options[0],
    rows=10,
    #description='Select one:',
    disabled=False,
    layout=widgets.Layout(width='5%', height='120px'),
)
def set_txt(*args):
    txt.value = str(sel.value)
    
sel.observe(set_txt, 'value')

row1 = widgets.VBox([main_title, txt])
row2 = widgets.VBox([description, sel])
#display(widgets.VBox([row1, row2]))

Multiselect cycles


In [11]:
sel.keystxt = widgets.Text()
options=list(range(100))
sel = widgets.SelectMultiple(
    options=options,
    value=[options[0]],
    rows=10,
    # description='Select one:',
    disabled=False,
    layout=widgets.Layout(width='3.2em', height='120px'),
)
def set_txt(*args):
    txt.value = str(sel.value)
    
sel.observe(set_txt, 'value')

display(widgets.VBox([txt, sel]))



In [ ]:
s = widgets.FileUpload(
    accept='.csv',  # Accepted file extension e.g. '.txt', '.pdf', 'image/*', 'image/*,.pdf'
    multiple=False  # True to accept multiple files upload else False
    
)
display(s)

In [ ]:
if s.value:
    files = next(iter(s.value.values()))
    meta = files['metadata']
    name = meta['name']
    label = widgets.Label(f'got: {name}')
    txtarea = widgets.Textarea(
        s.data[0], 
        layout=widgets.Layout(width='50%', height='130px')
    )
    display(widgets.VBox([label, txtarea]))

In [ ]:
from io import StringIO
import pandas as pd
raw = StringIO(str(s.data[0], 'utf-8'))
df = pd.read_csv(raw, sep=";")
df.head()

In [ ]:


In [ ]:
import markdown 

html = markdown.markdown("""# Markdown""")
widgets.HTML(
    html,
)

In [ ]:


In [12]:
caption = widgets.Label(value='The values of slider1 and slider2 are synchronized')
sliders1, slider2 = widgets.IntSlider(description='Slider 1'),\
                    widgets.IntSlider(description='Slider 2')
l = widgets.link((sliders1, 'value'), (slider2, 'value'))
display(caption, sliders1, slider2)


Threading


In [ ]:
import threading
from IPython.display import display
import ipywidgets as widgets
import time
progress = widgets.FloatProgress(value=0.0, min=0.0, max=1.0)

def work(progress):
    total = 100
    for i in range(total):
        time.sleep(0.2)
        progress.value = float(i+1)/total

thread = threading.Thread(target=work, args=(progress,))
display(progress)
thread.start()

Fitting


In [13]:
import numpy as np

In [14]:
from lmfit.models import LorentzianModel

In [15]:
from scipy.stats import cauchy
import matplotlib.pyplot as plt

In [16]:
%matplotlib inline

In [17]:
center = 10
x = np.linspace(0.0, 2*center, 100)
err = (np.random.random(len(x))-0.5) / 30
y = cauchy.pdf(x-center) + err

In [18]:
plt.plot(x,y, 'o')


Out[18]:
[<matplotlib.lines.Line2D at 0x1a2427f4d0>]

In [19]:
model = LorentzianModel()
params = model.guess(y, x=x)

In [20]:
params


Out[20]:
name value initial value min max vary expression
amplitude 1.25201263 None -inf inf True
center 9.89898990 None -inf inf True
sigma 1.01010101 None 0.00000000 inf True
fwhm 2.02020202 None -inf inf False 2.0000000*sigma
height 0.39454273 None -inf inf False 0.3183099*amplitude/max(2.220446049250313e-16, sigma)

In [21]:
result = model.fit(y, params, x=x)

In [22]:
result.plot_fit()


Out[22]:
<matplotlib.axes._subplots.AxesSubplot at 0x1a2362c290>

In [23]:
# create the model
model = LorentzianModel(prefix="D")

# set initial values
model.set_param_hint("Damplitude", value=1.1, vary=True)
model.set_param_hint("Dcenter", value=7.01, vary=True)

# get parameters to use in the model
#   - by guessing
params_guessed = model.guess(y, x=x)

#   - as initial set
params = model.make_params()

In [24]:
params_guessed


Out[24]:
name value initial value min max vary expression
Damplitude 1.25201263 None -inf inf True
Dcenter 9.89898990 None -inf inf True
Dsigma 1.01010101 None 0.00000000 inf True
Dfwhm 2.02020202 None -inf inf False 2.0000000*Dsigma
Dheight 0.39454273 None -inf inf False 0.3183099*Damplitude/max(2.220446049250313e-16, Dsigma)

In [25]:
# set individual parameters
params['Damplitude'].value = 1

In [26]:
# calculate the model using the initial values
init_y = model.eval(params, x=x)

# do a fit and retrieve the result
result = model.fit(y, params, x=x)

In [173]:
result


Out[173]:

Model

Model(lorentzian, prefix='D')

Fit Statistics

fitting methodleastsq
# function evals39
# data points100
# variables3
chi-square 0.00939004
reduced chi-square 9.6805e-05
Akaike info crit.-921.327625
Bayesian info crit.-913.512114

Variables

name value standard error relative error initial value min max vary expression
Damplitude 0.97386039 0.01557621 (1.60%) 1 -inf inf True
Dcenter 10.0018291 0.01571785 (0.16%) 7.01 -inf inf True
Dsigma 0.98423404 0.02226666 (2.26%) 1.0 0.00000000 inf True
Dfwhm 1.96846807 0.04453332 (2.26%) 2.0 -inf inf False 2.0000000*Dsigma
Dheight 0.31495497 0.00503161 (1.60%) 0.3183099 -inf inf False 0.3183099*Damplitude/max(2.220446049250313e-16, Dsigma)

Correlations (unreported correlations are < 0.100)

DamplitudeDsigma0.7081

In [27]:
# get the fitted parameters
new_params = result.params

# get goodness of fit
gof = result.chisqr

# calculate the model using fitted values
#  (can probably also be done using model.eval(new_params, x=x))
comps = result.eval_components()

In [28]:
print(f"Xhi**2: {gof:0.3f}")


Xhi**2: 0.009

In [29]:
fig, ax = plt.subplots()
ax.plot(x, y, 'o', label="raw")
ax.plot(x, init_y, label="init")
for k, c in comps.items():
    ax.plot(x, c, label=k)
ax.legend()


Out[29]:
<matplotlib.legend.Legend at 0x1a24883050>

Interactive fitter


In [544]:
class CustomWidget(widgets.VBox):
    
    def __init__(self, 
                 parameter,
                 name=None,
                 value=None, minimum=None, maximum=None, 
                 vary=None, expression=None,
                 minimum_span=None,
                 layout=None,
                ):
        if name is None:
            name = parameter.name
        parameter.name = name
            
        if value is None:
            value = parameter.value  or 0.0
        parameter.value = value
            
        if minimum is None:
            if parameter.min is not None and parameter.min != -np.inf:
                minimum = parameter.min
            else:
                minimum = value - 1.0
        parameter.min = minimum
            
        if maximum is None:
            if parameter.max is not None and parameter.max != np.inf:
                maximum = parameter.max
            else:
                maximum = value + 1.0
        parameter.max = maximum
            
        if vary is None:
            vary = parameter.vary
        parameter.vary = vary
            
        if expression is None:
            expression = parameter.expr
        parameter.expr = expression
        
        self.parameter = parameter
        self.min_span = minimum_span
        self.name = name
        self.parameter = parameter
        self.w_name = widgets.Label(f"Parameter: {name}")
        self.w_value = widgets.FloatSlider(
            value=value, 
            min = minimum,
            max = maximum,
            continuous_update=False,
            #description="VALUE",
        )
        
        self.w_min = widgets.FloatText(
            value=minimum, 
            #description="MIN",
            continuous_update=False,
            layout=widgets.Layout(width='3.8em'),
        )
        self.w_max = widgets.FloatText(
            value=maximum, 
            #description="MAX",
            continuous_update=False,
            layout=widgets.Layout(width='3.8em'),
        )
        
        self.w_vary = widgets.Checkbox(value=vary, description="VARY")
        
        if expression:
            self.w_expression = widgets.Text(value=expression, description="EXPR.")
            
        if layout:
            super(CustomWidget, self).__init__(layout=layout)
        else:
            super(CustomWidget, self).__init__()
            
        # make sure limits are set OK
        self.w_min.observe(self._update_value, 'value')
        self.w_max.observe(self._update_value, 'value')
        
        # update the parameter when updating widgets (not sure how to ensure correct order)
        self.w_value.observe(self.update_parameter, 'value')
        self.w_min.observe(self.update_parameter, 'value')
        self.w_max.observe(self.update_parameter, 'value')
        self.w_vary.observe(self.update_parameter, 'value')
        
        self.b_value = widgets.HBox([self.w_min, self.w_value, self.w_max])
        
        self.children = [
                self.w_name,
                self.b_value,
                self.w_vary, 
            ]
        if expression:
            self.children.append(self.w_expression)
            
    def __str__(self):
        return str(self.parameter)

    def _lookup(self, obj, prm, attr='value', on='value'):
        if self.parameter is None:
            print("ERROR! NO PRM DEFINED!")
        v = getattr(prm, attr)
        if (v != np.inf and v != -np.inf) and isinstance(v, (float, int)):
            setattr(obj, on, v)

    def update_widget(self):
        self._lookup(self.w_value, self.parameter, 'value', 'value')
        self._lookup(self.w_value, self.parameter, 'min', 'min')
        self._lookup(self.w_value, self.parameter, 'max', 'max')
        self._lookup(self.w_vary, self.parameter, 'vary', 'value')
        self._lookup(self.w_min, self.parameter, 'min', 'value')
        self._lookup(self.w_max, self.parameter, 'max', 'value')
        
    def update_parameter(self, *args):
        self.parameter.value = self.w_value.value
        self.parameter.min = self.w_value.min
        self.parameter.max = self.w_value.max
        self.parameter.vary = self.w_vary.value
        # expression not included

    def _update_value(self, *args):
        
        if self.w_max.value <= self.w_min.value:
            self.w_max.value = self.w_min.value + self.min_span
            #self.w_value.value = self.w_min.value
            
        if self.w_value.value <= self.w_min.value:
            self.w_value.value = self.w_min.value
            
        if self.w_value.value >= self.w_max.value:
            self.w_value.value = self.w_max.value
            
        self.w_value.min = self.w_min.value
        self.w_value.max = self.w_max.value
            
        span = self.w_value.max - self.w_value.min
        self.w_value.step = span/20
        
model = LorentzianModel()
prm_name = "center"
params = model.make_params()
params[prm_name].max = 12.0
params[prm_name].min = 2.0
params[prm_name].value = 8.0
params.pretty_print()
c = CustomWidget(parameter=params[prm_name], minimum_span=0.2)
print(c.name)
print(c)


Name          Value      Min      Max   Stderr     Vary     Expr Brute_Step
amplitude         1     -inf      inf     None     True     None     None
center            8        2       12     None     True     None     None
fwhm              2     -inf      inf     None    False 2.0000000*sigma     None
height       0.3183     -inf      inf     None    False 0.3183099*amplitude/max(2.220446049250313e-16, sigma)     None
sigma             1        0      inf     None     True     None     None
center
<Parameter 'center', 8.0, bounds=[2.0:12.0]>

In [549]:
model = LorentzianModel()
prm_name = "center"
params = model.make_params()
params[prm_name].max = 12.0
params[prm_name].min = 2.0
params[prm_name].value = 8.0
c = CustomWidget(parameter=params[prm_name], value=4.2, minimum_span=0.2)

In [550]:
print(c)


<Parameter 'center', 4.2, bounds=[2.0:12.0]>

In [551]:
display(c)



In [552]:
if params['height'].expr:
    print("h")


h

In [553]:
params.pretty_print()


Name          Value      Min      Max   Stderr     Vary     Expr Brute_Step
amplitude         1     -inf      inf     None     True     None     None
center          4.2        2       12     None     True     None     None
fwhm              2     -inf      inf     None    False 2.0000000*sigma     None
height       0.3183     -inf      inf     None    False 0.3183099*amplitude/max(2.220446049250313e-16, sigma)     None
sigma             1        0      inf     None     True     None     None

In [554]:
[k for k in params.keys() if not params[k].expr]


Out[554]:
['amplitude', 'center', 'sigma']

In [567]:
model = LorentzianModel()
x = x
y_obs = y

try:
    params = model.guess(y_obs, x=x)
except:
    params = model.make_params()  # used for internal updating of calculated prms
    # init params
    params['center'].value = 8.0
    params['center'].min = 0.1
    params['center'].max = 12.0

    params['sigma'].value = 0.5
    params['sigma'].min = 0.001
    
parameter_names = [k for k in params.keys() if not params[k].expr]
parameter_widgets = {}

plot_output = widgets.Output()
log_output = widgets.Output()

guess_button = widgets.Button(description="Guess")
fit_button = widgets.Button(description="Fit")
clear_button = widgets.Button(description="Clear")

buttons = widgets.HBox([guess_button, fit_button, clear_button])

for n in parameter_names:
    parameter_widgets[n] = CustomWidget(parameter=params[n], minimum_span=0.2)

def create_plot(y_obs, y_calc, y_err=None):
    #with log_output:
        #print("creating plot")
    fig, ax = plt.subplots()
    ax.plot(x, y_obs, 'o', label="raw")
    ax.plot(x, y_calc, label="init")
    if y_err is not None:
        ax.plot(x, y_err, label="err")
    plt.show()
    
def set_params(new_params):
    with log_output:
        # print("Setting new params")
        for k in params.keys():
            # print(k)
            if k in parameter_names:
                parameter_widgets[k].parameter = new_params[k]
                # print(f"   - updated widget: {k}")

            params[k] = new_params[k]
            # print(new_params[k])

def update_params(change):
    for c in parameter_widgets.values():
        c.update_parameter()
    
def update_plot(change):
    plot_output.clear_output(wait=True)
    y_calc = model.eval(params, x=x)
    with plot_output:
        create_plot(y_obs, y_calc)
        
def _lookup(obj, prm, attr='value', on='value'):
    v = getattr(prm, attr)
    if (v != np.inf and v != -np.inf) and isinstance(v, (float, int)):
        setattr(obj, on, v)

def update_widgets():
    for c in parameter_widgets.values():
        c.update_widget()
        
def on_guess(b):
    log_output.clear_output()
    set_params(model.guess(y, x=x))
    update_widgets()
    with log_output:
        print(" [guessing] ".center(20, "-"))
        params.pretty_print()
        print(" [finished] ".center(20, "-"))
        
def on_fit(b):
    log_output.clear_output()
    result = model.fit(y_obs, params, x=x)
    new_params = result.params
    set_params(new_params)
    update_widgets()
    with log_output:  
        print(" [fitting] ".center(20, "="))
        display(result)
        print(" [finished] ".center(20, "="))
        
def on_clear(b):
    log_output.clear_output()

list_of_widgets = []
for k in parameter_widgets.keys():
    parameter_widgets[k].w_value.observe(update_plot, 'value')
    list_of_widgets.append(parameter_widgets[k])

guess_button.on_click(on_guess)
fit_button.on_click(on_fit)
clear_button.on_click(on_clear)

prm_widgets = widgets.VBox(list_of_widgets)

out = widgets.VBox([prm_widgets, plot_output, buttons, log_output])

update_params(None)
update_plot(None)

In [568]:
out



In [ ]:


In [ ]: