Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

observe triggers twice when doing a round trip #85

Open
krey opened this issue Mar 14, 2019 · 3 comments
Open

observe triggers twice when doing a round trip #85

krey opened this issue Mar 14, 2019 · 3 comments

Comments

@krey
Copy link

krey commented Mar 14, 2019

Related to #66

To illustrate, a simple app that formats floating point user input

import ipysheet
import ipywidgets as widgets

as_list = True

sheet = ipysheet.Sheet(rows=1, columns=1)
if as_list:
    sheet.cells = ipysheet.Cell(value=[""], row_start=0, row_end=0, column_start=0, column_end=0,
                                squeeze_column=True, squeeze_row=False),
else:
    sheet.cells = ipysheet.Cell(value="", row_start=0, row_end=0, column_start=0, column_end=0,
                                squeeze_column=True, squeeze_row=True),

output = widgets.Output()

updating = False

def update(change):
    global updating
    with output:
        if updating:
            print('internal trigger')
            print(change)
        else:
            print('external trigger')
            print(change)
            updating = True
            if as_list:
                sheet.cells[0].value = ['{:.4f}'.format(float(entry)) for entry in change.new]
            else:
                sheet.cells[0].value = '{:.4f}'.format(float(change.new))
            updating = False
            
sheet.cells[0].observe(update, names='value')

sheet.cells[0].value = ['-.4'] if as_list else '-.4'

This puts the following in the output widget:

external trigger
{'name': 'value', 'old': [''], 'new': ['-.4'], 'owner': Cell(choice=[], column_end=0, column_start=0, row_end=0, row_start=0, squeeze_row=False, value=['-.4']), 'type': 'change'}
internal trigger
{'name': 'value', 'old': ['-.4'], 'new': ['-0.4000'], 'owner': Cell(choice=[], column_end=0, column_start=0, row_end=0, row_start=0, squeeze_row=False, value=['-0.4000']), 'type': 'change'}
external trigger
{'name': 'value', 'old': ['-0.4000'], 'new': ['-.4'], 'owner': Cell(choice=[], column_end=0, column_start=0, row_end=0, row_start=0, squeeze_row=False, value=['-.4']), 'type': 'change'}
internal trigger
{'name': 'value', 'old': ['-.4'], 'new': ['-0.4000'], 'owner': Cell(choice=[], column_end=0, column_start=0, row_end=0, row_start=0, squeeze_row=False, value=['-0.4000']), 'type': 'change'}

This shows that there's an extra trait notification, trying to "update" the new value to the original input.

Setting as_list = False uses a scalar instead of a list and does not suffer from this problem

external trigger
{'name': 'value', 'old': '', 'new': '-.4', 'owner': Cell(choice=[], column_end=0, column_start=0, row_end=0, row_start=0, value='-.4'), 'type': 'change'}
internal trigger
{'name': 'value', 'old': '-.4', 'new': '-0.4000', 'owner': Cell(choice=[], column_end=0, column_start=0, row_end=0, row_start=0, value='-0.4000'), 'type': 'change'}

The double notification in the as_list = True case leads to flickering and I'm not sure how to work around it yet.

@martinRenou
Copy link
Contributor

That is really weird... I displayed the traceback using print_stack and it shows that the second external event has not the same origin. We should try to replicate it using a core widget and post an issue in ipywidgets.

In the meantime I can only try to help you with your use case. If what you want to do is format the float numbers in the cells you can do:

import ipysheet

sheet = ipysheet.sheet()
ipysheet.cell(0, 0, -0.4, numeric_format='0.000')
display(sheet)

@krey
Copy link
Author

krey commented Mar 14, 2019

Thanks @martinRenou

numeric_format seems useful. I'd also like to replace non-numeric inputs with the empty string.

I tried to replicate the issue using core widgets (Select.options instead of Cell.value) but didn't succeed.

Let me know if you have any ideas

p.s. Do you think #66 is unrelated?

@martinRenou
Copy link
Contributor

martinRenou commented Mar 14, 2019

I honestly have no clue. This is really internal behavior of traitlets and ipywidgets and I'm not really aware of it.
But this 'old': ['-0.4000'], 'new': ['-.4'] thingy is really odd, I don't see why it should happen. I guess it's a bug.

The thing is that you are setting the value of the cell in the callback of an observe call, which is not really common use case.
I guess what you would need is a traitlets validator instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants