Unable to save as embed HTML for python Panel button parameterized action

I am trying to save the panel as an embed HTML file, and I am using .save(“file_name.html”, embed=True) . However, it is not working. How I can save the parameterized action button in panel python as an embed HTML file.

class ActionExample(param.Parameterized):   

    action = param.Action(lambda x: x.param.trigger('action'), label='Click here!')
    
    number = param.Integer(default=0)
        
    @param.depends('action')
    def get_number(self):
        self.number += 1
        return self.number
    
action_example = ActionExample()

component = pn.Column(
    pn.Row(
        pn.Column(pn.panel(action_example, show_name=False, margin=0, widgets={"action": {"button_type": "primary"}, "number": {"disabled": True}}),
            '**Click the button** to trigger an update in the output.'),
        pn.panel(action_example.get_number, width=300), max_width=600)
)
component

Now, when I am trying to save it as:

component.save('file_name.html',embed=True)

In file_name.html is not working. Any thoughts on how to make it work? Thanks!

Two items for you.

  1. Do not say it is not working - say what it is doing different from what you expected.
  2. That said - I think you are claiming the interactivity is not working - I believe that is because you are using python code instead of javascript for your interactivity and the HTML file cannot do that for you.

I have not wrapped my head around param at this point, and I did not find the documentation for doing a javascript link with param. Check out my jslink solution for an similar issue at https://discourse.holoviz.org/t/using-jslink-to-synchronize-tabs-and-pn-column-contents-to-avoid-requiring-python-to-be-running/2912/2

I hope that helps.

Hi, rcravotta,

The reason I said it is not working is because of the action button. In general .save(“file.html”,embed=True) works well with Panel. I guess the question is how to make the action button work in interactivity.

For example, if we save the code below as .html file it will work.

select = pn.widgets.Select(name='Select', options=[10,20,30])

@pn.depends(select)
def fn_(select):
    return select*100

pn.Row(select,fn_).save('file.html',embed=True)

Again, I also didn’t find any specific documentation on this. Let me know your thoughts. Thanks, again!

Your second example consists of only three options and all three have been processed and explicitly embedded into the html. Your first example cannot perform that as you are performing an increment that is based on the value of many more than 3 options (up to the size of an integer’s worth). I recall hearing others say that embed has a limited number of states that it will save - so that may be related to your issue.

As I understand it, if you want to embed an increment into your html, you will need to implement it as javascript to perform the math on the variable you wish to modify.

1 Like

Hi @imroy26 and welcome! :slight_smile:

What you can do with Panel is to save a snapshot of an app (its current state, what it looks like now basically) with the save method. With the embed parameter set to True, Panel will go through each one of your widgets, change their value, and save the output. You can explicitly define which states you want to the embed_states parameter that accepts a dict of widget states (Deploy and Export — Panel 0.12.4 documentation). If you don’t define which states you want to save, I believe Panel will try to be reasonable and not save all the states (with just a few widgets there could already be millions of states to save!), instead it will just save a sample.

I believe that what you experience here isn’t a bug. The button widget executes a function, that could be doing any kind of thing. It may for instance clear some in-memory data. This is the kind of thing that you probably wouldn’t like save to record.

For the simple case you posted, there’s a solution though that relies on Javascript links. A Button widget has a on_click method to attach a Python callback and a js_on_click method to attache a Javascript callback. In the example below I attach a simple Javascript callback that will, each time the button is clicked, increment the value of the number widget.

button = pn.widgets.Button(name='Click here!', button_type='primary')
number = pn.widgets.Spinner(name='Number', disabled=True)

button.js_on_click(args={'target': number}, code='target.value = target.value + 1')

app = pn.Column(
    button,
    number,
    '**Click the button** to trigger an update in the output.'
)
app.save('app.html')

You can read more about linking here: Links — Panel 0.12.4 documentation

It’s true that the docs could better describe the limitations of the save method.

1 Like