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

feat: include state to reproduce the visual state #207

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

maartenbreddels
Copy link
Collaborator

cc @eteq

For any notebook, we'd like to be able to reproduce what was done by including the state of the glue app in the notebook. To get to this, a human-readable text with all parameters that are changed from default would do.

However, this means we have to render a custom text when:

  1. The kernel is disconnected
  2. The widget state is not in the notebook (is this required?)
  3. The widget libraries do not work/or render

1. The kernel is disconnected

The PR as it is now, would allow for the following:

After we render this:
image

and then kill the kernel, it would show:

image

Which can include a custom msg that can 'implement' the reproducibility text.

If the widget state is saved in the notebook, this would also render on page refresh, or when someone else would open the notebook on his/her computer.

2. (?) The widget state is not in the notebook

If the widget state is not included in the notebook, classical notebook will always render like:
image

Which is due to https://github.com/jupyter-widgets/ipywidgets/blob/90c1c14211a6be685c6077646f40973f96faced1/widgetsnbextension/src/extension.js#L149

The same in JupyterLab:
image

Which is due to:
https://github.com/jupyter-widgets/ipywidgets/blob/90c1c14211a6be685c6077646f40973f96faced1/packages/jupyterlab-manager/src/renderer.ts#L56

Both is theory could default to do something else (render the HTML instead, like in item 3), but this might be a difficult change (does this break things?), or a difficult to configure setting (in notebook metadata?). Technically not difficult to change though.

3. The widget libraries do not work/or render

When a notebook is opened, but rendering fails due to js libraries not being present, or in the case of GitHub because of security concerns, Jupyter will fall back to rendering lower priority mine types, such as HTML. This means we need to get the mime bundle in the output of the notebook up to date with the state of the glue application/viewer.

One way to do this:

# create widget
import glue_jupyter as gj
points = gj.example_data_xyz(loc=60, scale=30, N=10*1000)
app = gj.jglue(points=points)
s = app.scatter2d(x='x', y='y', show=False)

# manually construct the mimebundle, like in https://github.com/jupyter-widgets/ipywidgets/blob/90c1c14211a6be685c6077646f40973f96faced1/ipywidgets/widgets/widget.py#L659
self = s.layout
plaintext = repr(self)
if len(plaintext) > 110:
    plaintext = plaintext[:110] + '…'
data = {
    'text/plain': plaintext,
}
data['application/vnd.jupyter.widget-view+json'] = {
    'version_major': 2,
    'version_minor': 0,
    'model_id': self._model_id
}

# display app with our own mime bundle, and give it a display id so we can update it
handle = display(data, raw=True, display_id=1)


......


# any time the app changes state (or after collapsing many state changes, i.e. debouncing),
# we can update the mime bundle

# construct custom msg
html_info = '''
<h1>Oops</h1>
If you see this, your Python kernel is not alive anymore, to reproduce the...
'''

# and update the mime bundle
handle.update({'application/vnd.jupyter.widget-view+json': data['application/vnd.jupyter.widget-view+json'],
               'text/html': html_info
              }, raw=True)

This last step will however redraw the whole application/widget/viewer, and does not look good or lead to a good user experience.

We could possibly see if we can optimize this rendering (e.g. detect if we can skip a redraw), or find other ways of updating the mime bundle.

I hope this gives a bit of an overview of what is possible and what requires changes to the ecosystem.

@codecov
Copy link

codecov bot commented Jan 12, 2021

Codecov Report

Merging #207 (1e5c60b) into master (0a7aee3) will decrease coverage by 0.27%.
The diff coverage is 0.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #207      +/-   ##
==========================================
- Coverage   90.50%   90.23%   -0.28%     
==========================================
  Files          83       84       +1     
  Lines        3960     3972      +12     
==========================================
  Hits         3584     3584              
- Misses        376      388      +12     
Impacted Files Coverage Δ
glue_jupyter/widgets/disconnect.py 0.00% <0.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0a7aee3...1e5c60b. Read the comment docs.

@eteq
Copy link
Collaborator

eteq commented Jan 26, 2021

Thanks @maartenbreddels ! This is a great overview.

I think, unfortunately, the use cases I'm thinking of are more like 2/3, although I have a 4 and a 5 in concept below that riffs off of 1...

But first some clarifications:

  • On 1, the idea would be to make Disconnect essentially be a superclass for everything in either jdaviz or glue-jupyter, right? And then to customize the disconnect text, one just updates broken as a trait, is that right? If so, I like that in concept the best except see my 4 to work around the downside...
  • Re: 3, is there any way to trigger that fall-back to lower MIME types if the libraries are not rendering correctly or the widget state is missing? Or is there no way to get to the lower MIME types (case 3) from case 2? If not, then I think my 5 is called for.

Now for my alternatives to consider:

  1. Exactly as 1, but with the widget state automatically getting saved when the notebook is saved. I don't know if this is possible in lab or notebook, nor how if we can do it in a fined-grained way for just the glue-jupyter widgets, but it would seem to let us use 1 (which is the best UX) without also requiring the user to manually save widget state (which I think they will basically never think to do).
  2. More radical (and maybe not lab-compatible, but I'm not sure): have an extension be installed with glue-jupyter that uses the file save hooks. I think this still requires at least some part of 3, so still might not solve the constant redraw, but might at least help with making things more consistent?

@maartenbreddels
Copy link
Collaborator Author

Some initial feedback: There was an ipywidget meeting yesterday, and there is interest in having ways to control the mimebundle, or at least have fallback methods. One use case is the ipympl widget, that wants to embed the static png image, which would have similar requirements.

Another idea would be to change the default of storing widgets in the notebook. If by default we store widgets that are output in the notebook, and all of its children, it should work in 99% of the cases, if not 100%, and not store widgets that are created, but not visualized.

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

Successfully merging this pull request may close these issues.

2 participants