Tips for saving interactive plots as html

It is generally possible to save an interactive HoloViews or panel objects as html files using the save function/method. However, there are limitations.

What are the limitations and what are pitfalls to avoid?

First, lets review ways that a file can be created using save. Since HoloViews save uses the panel save function, we will review the parameters of the save method in panel:

save(panel, filename, title=None, resources=None, template=None,
         template_variables=None, embed=False, max_states=1000,
         max_opts=3, embed_json=False, json_prefix='', save_path='./',
         load_path=None)

panel is the panel object you are saving
filename is the file you are saving to -if you do not define a suffix, it is assumed to be html by default, as we will discuss here.
title is the tab name that will appear int he browser - the window title - of not changes, it will be called panel
resources is used when you want your html file to be static and work offline without need to reach out to the internet to grab functions needed to display the interactive part. This makes the html file larger, yet it can work locally and independently. The natural use of this by using resources = INLINE after from bokeh.resources import INLINE

template and template_variables are a template html file and variables to pass to that template as explained here

embed is a key parameter. If embed=False then the html document created will not be interactive, for example, if you have a HoloMap with a slider, then the slider will not change the plot.

So to make the html interactive, one will need to use embed=True - in which case, the html file will include JavaScript code to make it interactive. However, when using embed = True, there are a few things to consider.

  1. How big you want the generated files to be ?
  2. How much time it will take to construct your file ?
  3. Is your content static or dynamic?

Those will be discussed below.

max_states is a number that defines when a warning appears when creating a plot. In the past is was used to block the user from generating huge files that take hours to generate. Yet from version 0.8 it just gives a warning when a user passes a certain number of states - the default is 1000. What are those states?
Imagine you create a HoloMap with 3 dimensions using the code below

import holoviews as hv
import numpy as np
import panel as pn
import bokeh
from bokeh.resources import INLINE

hv.extension('bokeh') 

def sine_curve(phase, freq, elevation):
    xvals = [0.1* i for i in range(100)]
    yvals = [np.sin(phase+freq*x) + elevation for x in xvals]
    data = {'xvals': xvals, 'yvals': yvals}
    return hv.Points(data, kdims=['xvals','yvals'])

frequencies = [0.5+i*0.25 for i in range(5)] 
phases      = [i*np.pi/2 for i in range(5)]
elevations  = [i*0.1 for i in range(5)]
curve_dict = {(p,f,v): sine_curve(p,f,v) for p in phases for f in frequencies for v in elevations}
hmap = hv.HoloMap(curve_dict, kdims=['phase', 'frequency', 'elevation']).opts(height=500,width=500)

panel_object = pn.pane.HoloViews(hmap)
pn.pane.HoloViews(hmap).save('test', embed=True, resources=INLINE)

In this situation there are 5x5x5=125 states. It will take a few seconds to generate and the file size would be ~1.5Mb - it will smaller without resources included. - about 0.6Mb. However, lets look at what we are doing here, there are 125 images that represent the plot - one for each tick combination of any of the sliders. So each possible image represent a state. If we increase the number of ticks in the frequency slider to 20, then we will have 20x5x5 = 500 images / states which will take less than a minute to create a file of size 2,6Mb. And if we increase the number of ticks in all sliders to 20 we will get 20x20x20 =8000 image/states - which will trigger a warning by default - unless we set max_states to be greater than 8000, in which case the warning will disappear. The reason the warning is there is to make sure that the time an file size are reasonable and prevent the user from running long inefficient processes - for example, to generate the file with 8000 states, it will take about half an hour and the file would be about 23Mb in size. Due to the exponential nature of combining states from different widgets, this can quickly become unreasonable, therefore the need of a warning. So the user needs to be aware of the size of the file to be generated. For example, the problem becomes worst when you create 2 panel layout tabs each hosting a plot generated by the original states sine example. In this case, there are 5x5x5 states for the first tab and 5x5x5 for the second tab altogether 5^6 = 15625 states, which can take an hour to generate and the file will be bigger. And if we try to generate two tabs each with a plot with 20 ticks per slider we will have 20^6 =64000000 states, which will not be reasonable to compute on one computer since it will take a long time - estimated as about half a year of computation assuming there is a strong enough computer with sufficient memory to finish the computation and the file generated is estimated to be around 180 Gb in size. So the user has to be aware of limitations of the save command. This relates to the first two questions the user needs to consider we listed above.

Before continuing to discussion about the third question , lets review the last few parameters:
max_opts is a parameter that is relevant to continuous widgets such as sliders where the user did not define the ticks as we explicitly defined in the example above. In such widgets, the system need to know where to put the ticks in which the slider will stop - max_opts defines exactly that.

The last few parameters embed_json, json_prefix, save_path, load_path are used if the user wished to export some of the data into json files to accompany with the html file that the html file will know to interact with. json is an exchange format for data and if used, it can help with future manipulation of this data and bokeh knows how to use these files.

However, it is also important to know what the save is useful for. In the above case, the data does not change once the plot is generated. The data is not time dependent, it is not random, and is not dynamic in any way. Each time you run the code you expect to see the exact same output. However, if your data is dynamic and will change each time you run the program, then the save command will freeze the situation and capture the system states specifically for that time and the next time you use save, you will get a different html file that captures different states. For example if the data you have captures vitals of an athlete running, then each time you generate a file using save, it is similar to freezing the athlete in time and recording all the parameters in that snapshot.

With dynamic data, it may not be reasonable to generate static html files using embedded html files - it may be inefficient - files may be large and the time to generate may not be reasonable. In such cases using a panel server may be the best solution. On the other hand, sometimes, it may be useful to capture dynamic data in a document that can be preserved in an html file like a snapshot. The user will have to make those decision.

Even with static data that does not change, the number of combinations of states may be so large that it is not reasonable to save them as an html file. However, creating a panel server to serve the plots dynamically may be a suitable solution. Fortunately panel offers both export and deploy solutions: server / static export and the user can decide depending on constraints.

1 Like