1

I'm trying to export a notebook to HTML, inside the notebook there are multiple interactive panels.

import panel as pn
import hvplot as hv
import holoviews as hv2
from bokeh.io import output_notebook, push_notebook, show, save, output_file
from bokeh.resources import INLINE

def plot_ts(feature=Spends[0], target=Target[0]):
    fig = df[target].plot.line(title=target)
    fig += df[feature].plot.area(title=feature)
    
    return fig.cols(1)

kw = dict(feature=sorted(list(Spends + Misc)))
panel1 = pn.interact(plot_ts, **kw)
panel1

Right now I'm running the following line:

!jupyter nbconvert --to html index.ipynb --no-input --no-prompt

The problem is my panels become stale (the corresponding data is not embed to them).
If I save panels one by one with the following line, I get the panels with the embed data.

panel1.save('test.html', embed=True, resources=INLINE)

I tried saving all my panels this way and then merge the different HTML files using Selenium but it doesn't work.

I tried appending panels to each others

all_panels.append(panel1).append(panel2).append(panel3)
all_panels.save("all_panels.html", embed=True)

The resulting HTML files is buggy, some panels work some others don't.

If anyone as any ideas how to make this work, it would be amazing.
Thanks

  • You haven't provided enough information to speculate. If there are interactions that rely on real Python callbacks, then there is no way that they can function in exported HTML. Interactions backed by Python callbacks require a running kernel. – bigreddot May 27 '21 at 15:07
  • What I want to get is a standalone HTML page, including, css, script and the embed data so I can interact with the panels. This line get me what I want for a single panel: panel1.save('test.html', embed=True, resources=INLINE). I want to have all the panels on a single HTML page basically. – Marc Inizan May 28 '21 at 08:35

1 Answers1

0

Using BeautifulSoup I managed to create a single HTML file containing the different panels saved as standalones html files with their embed data.
I thought it might be useful for other people so here is the code:

# Imports
from bs4 import BeautifulSoup, Tag
import glob

# List the filepaths corresponding to panels exported to html using 'panel_object.save("panel_name.html", embed=True)'
panels = glob.glob("/Users/username/Documents/data_exploration/panels/*.html")
panels_soup = []

# Read files and append their soup to a list
for panel in panels:
    with open(panel) as fp:
        panel = BeautifulSoup(fp, 'html.parser')
        panels_soup.append(panel)

# HTML base
soup = BeautifulSoup()
html = soup.new_tag("html")
soup.append(html)

# Append the head tag of one of the panels (it includes the bokeh/holoviews scripts)
soup.html.append(panels_soup[0].find("head"))

# Append an empty body tag
body = soup.new_tag("body")
soup.html.append(body)

# Loop on soups
for panel in panels_soup:
    divs = panel.find_all("div", attrs={"class":"bk-root"})
    data = panel.find_all('script')[-2]
    script = panel.find_all('script')[-1]
    panels_dict.append({"div_1":divs[0], "div_2":divs[-1], "data":data, "script":script})

# Append panels divs to the body of the page
for panel in panels_dict:
    soup.body.insert(1, panel["div_2"])
    soup.body.insert(1, panel["div_1"])

# Append the data at the end of the page
for panel in panels_dict:
    soup.body.insert(len(soup.body.contents), panel["data"])

# Append the scripts at the end of the page  
for panel in panels_dict:
    soup.body.insert(len(soup.body.contents), panel["script"])

# Export HTML file containing all the panels
with open("index.html", "w") as fp:
    fp.write(soup.prettify(formatter="html"))