jupyter-widgets / ipywidgets

Interactive Widgets for the Jupyter Notebook
https://ipywidgets.readthedocs.io
BSD 3-Clause "New" or "Revised" License
3.16k stars 951 forks source link

Precompute possible outcomes of interact and include them in static HTML export #1903

Open petereg opened 6 years ago

petereg commented 6 years ago

I suggest adding a feature to the Ipywidgets, that allows to precompute all possible outcomes of the function. These precomputed results should then be displayed when the user moves the slider of an interact statement. This should work even if the Jupyter notebook is exported to HTML. Let's take the following sample code:

from ipywidgets import interact
import matplotlib.pyplot as plt
import numpy as np

def f(a):
    x = np.linspace(0,2,100)
    plt.plot(x,a*x**2)
    plt.ylim([0,20])
    plt.show()
    return None

interact(f, a=(1,5,1))

In the final HTML file, all possible images (in this case all parabolas with a=1...5) should be included (in this sense pre-computed) and then displayed when the user selects the appropriate value with the slider. Of course, this selection has to be done by JavaScript since for a "stand alone" HTML file no Python kernel is available. I'm aware that this can increase the file size tremendously depending on the number of possible outcomes. Nevertheless, the precomputation implemented in a handy way would improve the ipython-widgets project in my opinion.

Peter

jasongrout commented 6 years ago

Thanks for bringing this up. (It's also been brought up at https://github.com/jupyter-widgets/ipywidgets/issues/758, for example).

I think this would be a cool feature. Probably on the more complicated side to implement, but very interesting nonetheless. I added it to the Future milestone so that someone wanting to implement it can see the idea.

jasongrout commented 6 years ago

(If you want to work on it, let us know and we can get you started with an architecture discussion about how it might work in our current framework)

JanSellner commented 5 years ago

I would like to add my two cents on this topic.

I have been using the same approach as described here for animations on my website for quite some time now (the showcase section contains some examples.). In general, the approach is very well suited for small animations where it is ok to have a limited range of parameter values. Luckily, this is very often the case.

My general approach to tackle this problem is as follows:

For the last part, I created a small library to handle the zip extraction as well as the image selection part. This could also be used in the webpage extracted from a Jupyter notebook.

So, @jasongrout, if the offer still stands, I would like help on this issue. To implement this feature, I would recommend the following steps:

  1. We need to iterate over every possible parameter value and save the image. Note: Currently, I have only used this approach with images and not with text output. But this could be added as well.
  2. All images should be added to a zip archive.
  3. Base64 encode the zip archive and embed it in the HTML output.
  4. Include the control elements also in the HTML output. Note: As far as I know, you use jQuery for the control elements (I use HTML input elements). But this should not be too much of a problem, I can extend my library for other control elements.
  5. Use my library to handle the image selection process.

Regarding the control elements, I think not every widget can be used with this precomputed approach, e.g. a text input is probably not useful. I would suggest that we start with sliders and then extend from there.

The most complicated part, from my perspective, is how this fits into the Jupyter system, e.g. how to extract the user's output etc. I guess the home for this feature is nbconvert. So, if you could point me to the files I probably need to touch, then this would be very useful.

It may also be worth discussing some limitations of the precomputed approach:

stsievert commented 4 years ago

Any updates on this?

I’m also interested in this issue: ipywidgets just works, at least locally. I use ipywidgets all the time to change an image based on a slider value (example functionality created with Jakes ipywidgets). I’m interested in static widgets not connected to a kernel because I’d rather not maintain a server.

In the past I’ve used Jakes ipywidgets. I briefly played around with Holoviews (example blog post). Currently, I use Bokeh (and plan to write a post on that soon). Of course, it takes a lot longer to write a Bokeh widget that mirrors the functionality of a Jupyter widget (docs, Javascript, etc).

asaboor-gh commented 3 months ago

I needed to export ipyslides to html/pdf format, so I implemented html serializers for many widgets including Box and subclasses to _alt_box and Output to _alt_output. These serializers can handle nested widgets which have an html representation. These are computed at export time, so no extra data is added to widgets. Infact this helped me to create a custom interact functionality that export all it's data that have some form of html representation. It may looks cumbersome but it's not the simple case and I had to include all possibilities that users may come up with. For the case of matplotlib figure, you can see plt2html.

maartenbreddels commented 3 months ago

Hi,

I'm curious if solutions like https://py.cafe, which allows you to write small ipywidgets apps online and embed them on a webpage without having to maintain a server, would solve some of the use cases here.

Third-party widget libraries like bqplot, ipydatagrid and ipyvolume work out of the box: https://py.cafe/maartenbreddels/ipyvolume-3d-vector-field preview

And even interact seem to work fine (although it does not draw initially, strangely): [interact demo](https://py.cafe/snippet/solara/v1#code=from%20ipywidgets%20import%20interactive%0Aimport%20matplotlib.pyplot%20as%20plt%0Aimport%20numpy%20as%20np%0A%0Adef%20f(a)%3A%0A%20%20%20%20x%20%3D%20np.linspace(0%2C2%2C100)%0A%20%20%20%20plt.plot(x%2Ca*x**2)%0A%20%20%20%20plt.ylim(%5B0%2C20%5D)%0A%20%20%20%20plt.show()%0A%20%20%20%20return%20None%0A%0Apage%20%3D%20interactive(f%2C%20a%3D(1%2C5%2C1))&requirements=solara%0Amatplotlib&appView=false&editEnable=true&python=pyodide-v0.25.1&layout=%7B%22rootRow%22%3A%7B%22type%22%3A%22row%22%2C%22children%22%3A%5B%7B%22type%22%3A%22tabset%22%2C%22children%22%3A%5B%7B%22type%22%3A%22tab%22%2C%22path%22%3A%22app.py%22%7D%5D%7D%5D%7D%7D)

For a website, you can embed an iframe (via share->embed). I hope it at least solves some of the problems mentioned here.

Regards,

Maarten

asaboor-gh commented 3 months ago

That's quite elegant solution and nice work! I've been working with Output widget quite a lot lately, it loses rendered objects especially widgets when it is going out of display and then rerendered, but python side data is preserved, so I found a trick to reset Output.outputs to empty tuple and back to old value to force it show objects again. This can be done automatically using a class with _ipython_display_.

I also tried solara to work with ipywidgets, but I encountered a problem accessing session variables, which rely heavily on get_ipython that usually returns InteractiveShellApp but in solara it returns a FakeIPython object which does not carry all the session info and something like run_cell does not work. Becuase ipyslides is a user code driven app, I gave up on the idea of using solar server until FakeIPython mimics InteractiveShellApp. I like solara and have other use cases, but this one couldn't work.