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

Multiple rerenders when using ipywidgets.Output.append_stdout #542

Closed
danr opened this issue Apr 19, 2024 · 2 comments
Closed

Multiple rerenders when using ipywidgets.Output.append_stdout #542

danr opened this issue Apr 19, 2024 · 2 comments

Comments

@danr
Copy link

danr commented Apr 19, 2024

When you put a widget in a ipywidgets.Output and using append_stdout on the output the widget will be rerendered once per append.

cell 1:

import anywidget
import traitlets

import ipywidgets as iw 
import IPython.display as ipd

class TinyWidget(anywidget.AnyWidget):
    _esm = """
    let num_created = 0
    function render({ model, el }) {
      const my_creation_id = ++num_created;
      const div = document.createElement("div");
      div.innerHTML = `my_creation_id: ${my_creation_id}`;      
      el.appendChild(div);
    }
    export default { render };
    """
    
out = iw.Output()
with out:
    ipd.display(TinyWidget())
out

cell 2:

for i in range(5):
    out.append_stdout(f'{i} ')

Expected output:

my_creation_id: 1
0 1 2 3 4 

Observed output:

my_creation_id: 6
0 1 2 3 4 

Notes:
This only happens when the appends are in a separate cell.

I noticed this and while this is mostly a bug upstreams I wanted to document it here as an issue. There are many open issues with ipywidgets.Output. I don't know exactly which one is relevant in this case but this comment is a good starting point for these issues: jupyter-widgets/ipywidgets#3261 (comment)

In line with that comment, the expected output happens if you use the context manager instead of the append_stdout method, like this:

for i in range(5):
    with out:
        print(f'{i} ', end='')
@manzt
Copy link
Owner

manzt commented May 10, 2024

Hi there, thanks for opening the issue! Indeed, this is an implementation detail wrt to how ipywidgets.Output works. In this case, I'd recommend using an ipywidgets.VBox to avoid re-returns (for the custom Jupyter Widget):

ipywidgets.VBox([TinyWidget()], out])

@asaboor-gh
Copy link

I am not sure if anywidget reloads javascript with each render or just runs the render function. If it is just render function, and your num_created is outside render, it is logical to have observed output. Let me explain:

ipywidgets.Output has an outputs attribute that get updated on each time a new display object is created. That attribute is a tuple which is assigned again and again each time an append_<func> is called. Since you are updating 5 times but it was also shown in start, so it becomes 6th time when you changed the outputs attribute. It's infact not appending new objects, it's re-assigning the outputs with all object appended so far.

@manzt manzt closed this as completed Nov 7, 2024
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

3 participants