4

I am using an IPython Jupyter notebook. In the following situation, I call a function using interact(), which in turns calls a second function again using interact().

def fun1(dataset_id):
     dataset = read_dataset(dataset_id)
     interact(fun2, data=dataset, var=(0,dataset.property,0.1))

def fun2(data, var):
     # something

interact(fun1, dataset_id=(0,5,1))

When first running this, it display 2 slider widgets: one for dataset_id, and one for the variable var. But if I vary the dataset_id slider once, a second slider for var is added below the first var slider, so now I have 3 sliders in total. How can I avoid this?

Thomas K
  • 39,200
  • 7
  • 84
  • 86
WindChimes
  • 2,955
  • 4
  • 25
  • 26

3 Answers3

1

This is only one step less hacky, but at least you don't have to have a button:

from ipywidgets import *
from IPython.display import display

datasets=[{"property":1},{"property":2},{"property":3},{"property":4},{"property":5}]

def read_dataset(dataset_id):
    return datasets[dataset_id]

def fun1(dataset_id):
    global sliders
    try:
        sliders.close()
    except NameError:
        pass
    dataset = read_dataset(dataset_id)
    sliders =  interactive(fun2, data=fixed(dataset), var=(0,dataset["property"],0.1)) # note I am now using interactive, instead of interact, because I need the close() function
    display(sliders)

def fun2(data, var):
    print var

interact(fun1, dataset_id=(0,5,1))
0

After a frustrating day, I came up with a totally hacky way to solve this (but at least it achieves 100% what I want). I am adding a button which, when clicked, invokes .close() on the second slider, as well as on the button itself. Therefore, before each time I need to move the first slider, I press this button to clear up.

Here is a fully-functioning code based on the snippet in the question, that you can copy-paste in your interpreter.

from ipywidgets import *
from IPython.display import display

datasets=[{"property":1},{"property":2},{"property":3},{"property":4},{"property":5}]

def read_dataset(dataset_id):
    return datasets[dataset_id]

def fun1(dataset_id):
    dataset = read_dataset(dataset_id)
    sliders = interactive(fun2, data=fixed(dataset), var=(0,dataset["property"],0.1)) # note I am now using interactive, instead of interact, because I need the close() function
    close_button = widgets.Button(description="Remove sliders")
    def remove_sliders(b):
        sliders.close()
        b.close()
    close_button.on_click(remove_sliders)
    display(sliders)
    display(close_button)

def fun2(data, var):
    print
    # something

interact(fun1, dataset_id=(0,5,1))
WindChimes
  • 2,955
  • 4
  • 25
  • 26
0

Here is another solution, you could create two sliders, and make the "max" of the second slider dependent on the property selected with the first slider:

import ipywidgets as widgets
from ipywidgets import *
from IPython.display import display

datasets=[{"property":1},{"property":2},{"property":3},{"property":4},{"property":5}]

def read_dataset(dataset_id):
    return datasets[dataset_id]

w_slider1 = IntSlider(min=0, max=len(datasets)-1, step=1)
w_slider2 = FloatSlider(min=0, step=0.1)

def fun1(dataset_id):
    dataset = read_dataset(dataset_id)
    #you could get rid of function "read_dataset"
    #dataset = datasets[dataset_id]
    w_slider2.max = dataset['property']

def fun2(data, var):
    #call fun1 to update the size of 2nd slider
    fun1(data)
    #do something
    print(data, var)

interact(fun2, data=w_slider1, var=w_slider2)
Ely
  • 498
  • 5
  • 14