ipywidgets icon indicating copy to clipboard operation
ipywidgets copied to clipboard

Custom ipywidgets - need to call twice or in new cell to get updated values

Open xianliu2021 opened this issue 4 years ago • 1 comments

Hi all,

I have encountered a problem with ipywidgets that some value has been updated by calling a method, but in the same cell I cannot get the updated value by retrieving the value from the object in the same cell. Instead, I have to retrieve the value again to get the updated value or in another cell. This is not a big issue in Notebook, but the above step is actually another method in my problem and I need to retrieve the updated value in script for use with another process which will be presented in the notebook. So I do need to get the updated value as an intermediate step.

I have created a light example here - I chose to update the value2 this way in Python because of the complicated operations and data duplication so I want the update step in Python instead of JS:

Widget has two values: value1 and value2, and a counter In Front End, I input value1 If needed, I want to manually trigger a update step (setting value1 to value2) using counter: – counter + 1 – in JS, if counter changed, set value1 from view to model – in Python, if value1 changed, set value2 with new value of value1 However, as shown in the screenshot below, after calling the update method, value1 and value2 are still not changed, but trying to get the two values again gives the updated values:

Screenshot 2021-04-29 at 21 14 39

May I ask what is going on here? In fact, when calling the update method, the values should have been updated, but why in the first time, the values are still shown unchanged? In fact, if I call update method in one cell, and retrieve the values in the next cell, the updated values are shown… This looks weird and I want to understand why and how to overcome the issue, many thanks!

I have attached the code for the very light example here, thanks!

`from traitlets import Unicode, Int from ipywidgets import DOMWidget, register

@register class MyWidget(DOMWidget): _view_name = Unicode('MyWidgetView').tag(sync=True) _view_module = Unicode('my_widget').tag(sync=True)

counter = Int(0).tag(sync=True)
value1 = Unicode('default').tag(sync=True)
value2 = Unicode('default').tag(sync=True)

def __init__(self):
    super().__init__()
    self.observe(self.update, names='value1')

def get_values(self):
    self.counter += 1

def update(self, change):
    self.value2 = change['new']

%%javascript require.undef('my_widget');

define('my_widget', ["@jupyter-widgets/base"], function(widgets) {

var MyWidgetView = widgets.DOMWidgetView.extend({
    
    render: function() {
        this.value1_input = document.createElement('input');
        this.value1_input.type = 'value';
        this.value1_input.value = this.model.get('value1');
        
        this.el.appendChild(this.value1_input);
        
        this.model.on('change:counter', this.counter_changed, this);
    },
    
    counter_changed: function() {
        this.model.set('value1', this.value1_input.value);
        this.touch();
    }
});

return {
    MyWidgetView: MyWidgetView
};

});

mw = MyWidget() mw `

xianliu2021 avatar Apr 30 '21 12:04 xianliu2021

I have the same issue.

Things I tried

I thought maybe the JS side does not have the time to update if it's in the same cell but

import time
mw.get_values()
time.sleep(10)
print(mw.value1, mw.value2)

did not work.

Then I added a console.log on the JS side of get_values and executing the following cell

mw.get_values()
assert False

never entered in get_values

So I made get_values an async function, the snippet now looks like this:

await mw.get_values()
print(mw.value1, mw.value2)

Now we do enter in get_values but the old ones are still printed It still does not solves the issue.

Does someone have an idea? Or any place I could look for an implementation? I'm kinda lost here

ManonMarchand avatar Aug 30 '23 14:08 ManonMarchand