How can I add a loading indicator on a user interaction, while the plot is getting ready in the dashboard below?
class DataExplorer(param.Parameterized):
smoothing_fraction = param.Number(default=0.7, bounds=(0, 1), inclusive_bounds=(True, True), step=0.05)
def load_data(self):
cache = pn.state.cache
df = cache['data'] if 'data' in cache else load_data_from_disk()
cache['data'] = df
return df
@param.depends('smoothing_fraction')
def make_view(self):
df = self.load_data()
points = hv.Points(df)
scatter = (dynspread(datashade(points), threshold=self.smoothing_fraction) * rasterize(points, width=20, height=20, streams=[RangeXY]).apply(hv.QuadMesh))
return scatter.opts(width=900, height=350, show_legend=False).opts(opts.QuadMesh(tools=['hover'], alpha=0, hover_alpha=0.2))
explorer = DataExplorer(name="")
dashboard = pn.Column(explorer.param, explorer.make_view)
Thank you.
Marc
April 17, 2020, 4:56am
2
Hi @Nithanaroy
You can use the panel.widgets.Progress
or a Holoviews.Div
to convey progress.
I’ve created the below example showcasing both.
You can find a live version in the gallery at awesome-panel.org .
Hope it helps.
"""This example was created by as response to
<a href=https://discourse.holoviz.org/t/how-to-show-a-loading-indication-during-computation/508"
target="_blank"> Discourse 508</a> <strong>How to show a loading indication during
computation</strong>. You can find a live version in the Gallery at
<a href="https://awesome-panel.org">awesome-panel.org</a>.
"""
import math
import time
import holoviews as hv
import hvplot.pandas # pylint: disable=unused-import
import pandas as pd
import panel as pn
import param
EMPTY_DATAFRAME = pd.DataFrame(columns=["x", "y"])
EMPTY_PLOT = hv.Div("Click UPDATE to load!")
SPINNER_URL = (
"https://github.com/MarcSkovMadsen/awesome-panel/blob/master/"
"src/pages/gallery/dataexplorer_loading/spinner.gif?raw=true"
)
SPINNER_HTML = f"<img src='{SPINNER_URL}' style='width:100%'"
class DataExplorer(param.Parameterized):
"""The DataExplorer App illustrates a progress and loading message"""
load_time = param.Integer(default=8, bounds=(1, 4 * 16), label="Load Time (seconds)")
data = param.DataFrame()
update_action = param.Action(label="UPDATE")
def __init__(self, **params):
super().__init__(**params)
self.plot_pane = pn.pane.HoloViews(EMPTY_PLOT, sizing_mode="stretch_both", min_height=300)
self.update_action = self.load_data
self.progress_widget = pn.widgets.Progress(
name="Progress", sizing_mode="stretch_width", value=0
)
def set_hv_loading_message(self, message: str):
"""Replaces the plot with a loading message"""
message_plot = hv.Div(SPINNER_HTML + f"<p align='center'><strong>{message}<strong></p>")
self.plot_pane.object = message_plot
def load_data(self, _):
"""Loads the data"""
steps = self.load_time * 4
self.progress_widget.max = steps
xdata = [0]
ydata = [math.sin(0)]
for i in range(0, steps):
xdata.append(i / 16)
ydata.append(math.sin(i / 16 * 2 * math.pi))
message = f"Loading ({i+1}/{steps})"
self.set_hv_loading_message(message)
self.progress_widget.value = i
time.sleep(1 / 4)
self.data = pd.DataFrame({"x": xdata, "y": ydata})
self.progress_widget.value = 0
@param.depends("data", watch=True)
def update_plot(self):
"""Updates the plot"""
plot = self.data.hvplot.line(x="x", y="y", color="green").opts(
responsive=True, line_width=4
)
self.plot_pane.object = plot
def view(self):
"""Returns the application view"""
return pn.Column(
pn.pane.Markdown(__doc__),
pn.pane.Markdown("#### Settings"),
pn.Param(
self,
parameters=["load_time", "update_action"],
show_name=False,
sizing_mode="stretch_width",
widgets={"update_action": {"button_type": "success"}},
),
pn.pane.Markdown("#### Progress"),
self.progress_widget,
pn.pane.Markdown("#### Plot"),
self.plot_pane,
sizing_mode="stretch_both",
)
def view():
"""Serves the app.
Needed for inclusion to awesome-panel.org Gallery
"""
component = DataExplorer()
return component.view()
You can find any updated version of the code here https://github.com/MarcSkovMadsen/awesome-panel/blob/master/src/pages/gallery/dataexplorer_loading/dataexplorer_loading.py
1 Like
Marc
April 17, 2020, 5:05am
3
One add on question I have is how to show the loading message and progress during initial load?
That I have not tried yet. But being able to quickly load the application with a loading message is important I believe.
My guess is that we would have to load the data in the background (seperate thread).
@philippjfr ?
Thank you Marc. This is super cool! Will checkout others in the gallery as well
1 Like
To extend this thought of engaging experiences, I tried streaming visualizations with the intention to show some output to the user and progressively update it. This is something like progressive JPEG, where something is painted on the screen as early as possible during background network download. However, I hit a roadblock as Buffer
started growing drastically making my implementation unusable. I feel it may be possible with Dask’s delayed parallel execution scheme but I’m not sure how to achieve this with holoviews. Any ideas or examples on how to implement this @Marc or @philippjfr ?
1 Like
Marc
April 18, 2020, 1:19am
6
Hi @Nithanaroy
I have no experience in this. But if you create a new post (not reusing this :-)) Sombody might take a look.
And please provide a small code example, screenshot or something else to make it more specific.
Marc
April 20, 2020, 3:39pm
8
If you need to have a the plot in a row with settings on the right the hv.Div
idea above does not work that well.
There is a workaround in this Github Issue for now.
opened 02:46PM - 20 Apr 20 UTC
System Info
Holoviews: 1.13.2
Panel: 0.9.4
Bokeh 2.0.0
My Pain
I'm often loading my page with an "empty" plot because I want to let the user...
1 Like