Is there a way of Sharing a URL for a panel's state?

Some times a user of a panel dashboard has set all the widgets to display a eureka plot of their data.
They would then like to share an URL that captures that eureka state of the panel. When the URL is resolved, it returns a new instance of the panel dashboard in that eureka state.

I think creating this URL would involve encoding the state of all the widgets in the URL, something like:
https://www.test.com/panel.py?widget1=value1&widget2=value2

When the panel restarts, it extract the initial values of the widgets using:
pn.state.session_args:

Is there a function or shortcut to save the state of all of a panel’s widgets?

1 Like

This has been merged into master but not released yet. See https://github.com/holoviz/panel/pull/1150

I’ve contributed a Location component that will enable updating the url with parameters and reacting to changes in the url. @philippjfr has improved this.

The one thing remaining is “serializing” the parameters of a param.Parameterized class into the parameter part of the url and vice versa. But this is standard python functionality (I don’t remember where though :-))

I really need the Location component. Would be so powerful for my users to be able to bookmark and share links to the exact state of their apps and views.

This was merged as part of the Location component. Specifically you can call pn.state.location.sync(parameterized, parameters) and the declared parameters will be bi-directionally synced with the URL.

1 Like

The sync functionality sounds so cool @philippjfr. Can I change the parameterized and parameters when I change my “page” in an application with multiple pages?

Depends on what you consider a page in your case a “page” is still the same app right? I think you might have to unsync in that case (which is functionality I’d have to add).

1 Like

Yes its the same app @philippjfr

Okay, would you mind filing an issue about an unsync method?

Done: https://github.com/holoviz/panel/issues/1335

Thank you, you guys.
I see that pn.state.location is briefly described in the current check in of the panel documentation.

If you have suggestions on improving the visibility of that documentation and/or want to make a PR that would be super helpful. Examples that use the functionality would also be super helpful.

Hello folks,

I was just curious if there was ever an update on the examples that use this state. I have developed a rather complex dashboard using param class, and would definitely love to send the URL that captures the state of my widgets to the stakeholders. Is there a good example on how I need to modify my app to achieve that ?
Even a button “Generate URL” would work…

Thanks,
Anton.

Check out https://panel.holoviz.org/gallery/simple/sync_location.html#simple-gallery-sync-location

Thanks for the pointer. Are there any limitations as to certain widgets not being able to serialize yet ?

1 Like

I would not know. But try it out and report back :slight_smile:

Hello Marc,

I have checked out the example, and am now puzzled as to how to port it to the dashboard developed as a Param class instance.

@Marc

I got somewhere via the following, but it kinda looks hacky, and I do not like using a pre-set index for the widget corresponding to a parameter. Is there a nicer way to do it?

import panel as pn
import param


class ReactiveDashboard(param.Parameterized):
    widget = param.Range(bounds = (0,10))
    widget2 = param.String(default='Text')
    widget3 = param.Integer(10)

    def panel(self):
        result = pn.Row(self.param)

        # if pn.state.location:
        #     #pn.state.location.sync(self.param.widget2)
        #     # pn.state.location.sync(self.widget2, {'value': 'text_value'})
        #     # pn.state.location.sync(self.widget3, {'value': 'value'})
        return result

res = ReactiveDashboard().panel()
if pn.state.location:
    pn.state.location.sync(res.objects[0][2],{'value': 'text_value'})
res.servable()

For whoever gets stuck like myself, here is the solution that actually works, and does not look too hacky (in hindsight):

One oustanding question though perhaps to @philippjfr or @Marc - where should I plug in the syncing part - within my class method or outside of it (right before servable) ?

It also does not seem to work if I sync >2 parameters. Perhaps has something to do with picking the first match instead of the one with the right name:

  File "/home/anton/miniconda3/envs/oracle-telescope/lib/python3.8/site-packages/panel/io/location.py", line 124, in _update_query
    serialized[matches[0][e.name]] = val
KeyError: 'widget3'

Is there a way to pass custom json serializer ? I have some of widgets that are datetime and default json encoder does not like datetime.

class ReactiveDashboard(param.Parameterized):
    widget = param.Range(bounds = (0,10))
    widget2 = param.String(default='Text')
    widget3 = param.Integer(10)
    def panel(self):
        result = pn.Row(self.param)
        if pn.state.location:
            pn.state.location.sync(self, {'widget2': 'text_value'})
        return result
res = ReactiveDashboard().panel()
res.servable()