Add a web UI with Dash (intermediate)

Audience: Users who want to communicate between the Lightning App and Dash.

Prereqs: Must have read the dash basic guide.


Interact with the App from Dash

In the example below, every time you change the select year on the dashboard, this is directly communicated to the flow and another work process the associated data frame with the provided year.

from typing import Optional

import pandas as pd
import plotly.express as px
from dash import Dash, dcc, html, Input, Output

from lightning.app import LightningWork, LightningFlow, LightningApp
from lightning.app.storage import Payload


class LitDash(LightningWork):
    def __init__(self):
        super().__init__(parallel=True)
        self.df = None
        self.selected_year = None

    def run(self):
        df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv")
        self.df = Payload(df)

        dash_app = Dash(__name__)

        dash_app.layout = html.Div(
            [
                dcc.Graph(id="graph-with-slider"),
                dcc.Slider(
                    df["year"].min(),
                    df["year"].max(),
                    step=None,
                    value=df["year"].min(),
                    marks={str(year): str(year) for year in df["year"].unique()},
                    id="year-slider",
                ),
            ]
        )

        @dash_app.callback(Output("graph-with-slider", "figure"), Input("year-slider", "value"))
        def update_figure(selected_year):
            self.selected_year = selected_year
            filtered_df = df[df.year == selected_year]

            fig = px.scatter(
                filtered_df,
                x="gdpPercap",
                y="lifeExp",
                size="pop",
                color="continent",
                hover_name="country",
                log_x=True,
                size_max=55,
            )

            fig.update_layout(transition_duration=500)

            return fig

        dash_app.run_server(host=self.host, port=self.port)


class Processor(LightningWork):
    def run(self, df: Payload, selected_year: Optional[str]):
        if selected_year:
            df = df.value
            filtered_df = df[df.year == selected_year]
            print(f"[PROCESSOR|selected_year={selected_year}]")
            print(filtered_df)


class LitApp(LightningFlow):
    def __init__(self):
        super().__init__()
        self.lit_dash = LitDash()
        self.processor = Processor(parallel=True)

    def run(self):
        self.lit_dash.run()

        # Launch some processing based on the Dash Dashboard.
        self.processor.run(self.lit_dash.df, self.lit_dash.selected_year)

    def configure_layout(self):
        tab1 = {"name": "home", "content": self.lit_dash}
        return tab1


app = LightningApp(LitApp())

Here is how the app looks like once running:

https://pl-public-data.s3.amazonaws.com/assets_lightning/dash_plot.gif

Interact with Dash from a component

In the example below, when you click the toggle, the state of the work appears.

Install the following libraries if you want to run the app.

`bash pip install dash_daq dash_renderjson `

import dash
import dash_daq as daq
import dash_renderjson
from dash import html, Input, Output

from lightning.app import LightningWork, LightningFlow, LightningApp
from lightning.app.utilities.state import AppState


class LitDash(LightningWork):
    def run(self):
        dash_app = dash.Dash(__name__)

        dash_app.layout = html.Div([daq.ToggleSwitch(id="my-toggle-switch", value=False), html.Div(id="output")])

        @dash_app.callback(Output("output", "children"), [Input("my-toggle-switch", "value")])
        def display_output(value):
            if value:
                state = AppState()
                state._request_state()
                return dash_renderjson.DashRenderjson(id="input", data=state._state, max_depth=-1, invert_theme=True)

        dash_app.run_server(host=self.host, port=self.port)


class LitApp(LightningFlow):
    def __init__(self):
        super().__init__()
        self.lit_dash = LitDash(parallel=True)

    def run(self):
        self.lit_dash.run()

    def configure_layout(self):
        tab1 = {"name": "home", "content": self.lit_dash}
        return tab1


app = LightningApp(LitApp())

Here is how the app looks like once running:

https://pl-public-data.s3.amazonaws.com/assets_lightning/dash_state.gif