Py.Cafe

antonymilne/

refreshing-dashboard

Dynamic Data Visualization Demo - Vizro

DocsPricing
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""Dev app to try things out."""
import time
from urllib import parse

import vizro.models as vm
import vizro.plotly.express as px
from vizro import Vizro
from vizro.managers import data_manager

from vizro.models.types import capture
from dash import dcc, callback, Output, Input, State


def dynamic_data():
    return px.data.iris().sample(50)


data_manager["iris"] = dynamic_data

# It's a bit fiddly to parse the query string and add the refresh parameter but should work well.
# A simpler way would be to not have a callback here and just set
# routing_callback_inputs={"refresh_interval": Input("interval", "n_intervals")}
# in the initial Dash instantiation. This only works if layout remains a function though, and that might change in
# future.
# See https://github.com/plotly/dash/issues/2904 for more options and also note on_page_load solution.
REFRESH_INTERVAL = 3000  # in milliseconds


@callback(
    Output("refresh_location", "search"), Input("refresh_interval", "n_intervals"), State("refresh_location", "search")
)
def update_refresh_query_param(n_intervals, search):
    search = search.removeprefix("?")  # Only Python 3.9+!
    params = parse.parse_qs(search)
    params["refresh"] = time.time()
    return "?" + parse.urlencode(params, doseq=True)


class RefreshingDashboard(vm.Dashboard):
    def build(self):
        dashboard = super().build()
        dashboard.children = [
            dcc.Location(id="refresh_location", refresh="callback-nav"),
            dcc.Interval(id="refresh_interval", n_intervals=0, interval=REFRESH_INTERVAL),
            *dashboard.children,
        ]
        return dashboard


# Draw a violin plot if there's only one species selected and a scatter plot otherwise.
@capture("graph")
def my_graph(data_frame):
    if data_frame["species"].nunique() == 1:
        return px.violin(data_frame, x="sepal_width")
    return px.scatter(data_frame, x="sepal_width", y="sepal_length", color="species")


page = vm.Page(
    title="Blah",
    components=[vm.Graph(figure=my_graph(data_frame="iris"))],
    controls=[vm.Filter(column="species")],
)
another_page = vm.Page(
    title="More blah",
    components=[vm.Card(text="blah blah")],
)


dashboard = RefreshingDashboard(pages=[page, another_page])

app = Vizro().build(dashboard).dash