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’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.
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).
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.
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…
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()