Paisley
Paisley

Reputation: 91

IPywidgets observe not working when wrapped inside a class

I have created a small example, which shows the working and not working case. The working example,

import ipywidgets as widgets


selected = {}

a = widgets.Dropdown(description="Apple", options = ["a","k"])
                 
b = widgets.Dropdown(description="Boeing", options = ["a",'b'])
                 
c = widgets.Dropdown(description="Coco Cola", options = ["a",'b','c'])

def getvaluea(change):
    selected["a"] = change.new
    with out:
        out.clear_output()
        print(selected)

def getvalueb(change):
    selected["b"] = change.new
    with out:
        out.clear_output()
        print(selected)

def getvaluec(change):
    selected["c"] = change.new
    with out:
        out.clear_output()
        print(selected)

out = widgets.Output()
                     
tab = widgets.Tab()

tab.children = [a,b,c]

tab.titles = ["a",'b','c']

a.observe(getvaluea, 'value')
b.observe(getvalueb, 'value')
c.observe(getvaluec, 'value')

display(tab)

display(out)

Using this code example will change add or change items in selected. When I try to wrap this same code sample in a class, I am having a problem getting the result.

class UserInterfaceAttempt10:

  def __init__(self):
    
    self.selected = {}
    
    self.a = widgets.Dropdown(description="Apple", options = ["a","k"])
             
    self.b = widgets.Dropdown(description="Boeing", options = ["a",'b'])

    self.c = widgets.Dropdown(description="Coco Cola", options = ["a",'b','c'])
    
    self.out = widgets.Output()
                 
    self.tab = widgets.Tab()

    self.tab.children = [self.a, self.b, self.c]

    self.tab.titles = ["a",'b','c']

    self.a.observe(self.getvaluea)
    self.b.observe(self.getvalueb)
    self.c.observe(self.getvaluec)
    
  def getvaluea(self, change):
    self.selected["a"] = change.new
    with self.out:
        self.out.clear_output()
        print(self.selected)

  def getvalueb(self, change):
    self.selected["b"] = change.new
    with self.out:
        self.out.clear_output()
        print(self.selected)

  def getvaluec(self, change):
    self.selected["c"] = change.new
    with self.out:
        self.out.clear_output()
        print(self.selected)
        
  def display_GUI(self):
    display(self.tab)
    display(self.out)

ob = UserInterfaceAttempt10()
ob.display_GUI()

Can someone help me understand the problem? Thank you!

Upvotes: 3

Views: 1473

Answers (1)

ac24
ac24

Reputation: 5565

As with lots of widgets problems, printing and debugging is your friend.

If you print(change) within one of your getvalue methods you will see the issue:

enter image description here

The function is being called many times with just a single widget change. The last change is the one that persists.

If instead your observe call specifies:

self.a.observe(self.getvaluea, names='value')

you should see the desired result:

enter image description here

Upvotes: 2

Related Questions