Skip to content

Latest commit

 

History

History
359 lines (254 loc) · 11.4 KB

04-PredefinedTemplates.md

File metadata and controls

359 lines (254 loc) · 11.4 KB

Status: Template Layout System

Based on community feedback, this version of the template layout system will not be added to a future version of Dash. However, the work done here inspired many new features, such as:

- New in Dash 2.1: The low-code shorthands for Dash Core Components and the dash DataTable.

- New in Dash 2.1, The Input, State, and Output accepts components instead of ID strings. Dash callback will auto-generate the component's ID under-the-hood if not supplied.

- Available in the dash-bootstrap-templates library: Bootstrap themed figures.

We appreciate everyone's input on the template system. Templates are still in the dash-labs project plan, so stay tuned for a new version!

- ----------------------------------------------------------------------------------
-  This documentation describes code in a previous version of dash-labs (v0.4.0) 
-  and is included here for legacy purposes only.
-
-  You can install v0.4.0 with:
-  pip install dash-labs==0.4.0
- ----------------------------------------------------------------------------------

Predefined templates

This section describes the templates that are provided with Dash Labs.

Here is a full example, specifying the FlatDiv template. The following examples will only describe code for the template declaration and app.layout specification lines.

demos/all_templates.py

import dash
import dash_labs as dl
import numpy as np
import plotly.express as px

app = dash.Dash(__name__, plugins=[dl.plugins.FlexibleCallbacks()])

tpl = dl.templates.FlatDiv(app)

@app.callback(
    args=dict(
        fun=tpl.new_dropdown(["sin", "cos", "exp"], label="Function"),
        figure_title=tpl.new_textbox("Initial Title", label="Figure Title"),
        phase=tpl.new_slider(1, 10, label="Phase"),
        amplitude=tpl.new_slider(1, 10, value=3, label="Amplitude"),
    ),
    output=tpl.new_graph(),
    template=tpl,
)
def callback(fun, figure_title, phase, amplitude):
    xs = np.linspace(-10, 10, 100)
    np_fn = getattr(np, fun)

    # Let parameterize infer output component
    x = xs
    y = np_fn(xs + phase) * amplitude
    return px.line(x=x, y=y).update_layout(title_text=figure_title)

app.layout = tpl.children

if __name__ == "__main__":
    app.run_server(debug=True)

FlatDiv

The FlatDiv template arranges all the input and output containers as children of a top-level Div component, and makes no attempt to make the result look nice.

# Make template
tpl = dl.templates.FlatDiv(app)

<snip>

# Make app layout
import dash_html_components as html
app.layout = html.Div(children=tpl.children)

HtmlCard

The HtmlCard template has no external dependencies and uses some basic inline CSS to place the input and output in a card with a title on top. It currently puts very little effort into making the result look nice (although this could change).

# Make template
tpl = dl.templates.HtmlCard(title="Dash Labs App", width="500px")

<snip>

# Make app layout
import dash_html_components as html
app.layout = html.Div(children=tpl.children)

DbcCard

The DbcCard template introduces a dependency on the open source Dash Bootstrap Components library (https://dash-bootstrap-components.opensource.faculty.ai/). It places all contents in a single bootstrap card, with a card title.

# Make template
tpl = dl.templates.DbcCard(title="Dash Labs App", columns=6)

<snip>

# Make app layout
import dash_bootstrap_components as dbc
app.layout = dbc.Container(fluid=True, children=tpl.children)

DbcRow

The DbcRow template places the inputs and outputs in separate cards and then arranges them in a Bootstrap row. This template is a great choice when integrating the components generated by the template into a larger app made with Dash Bootstrap Components.

# Make template
tpl = dl.templates.DbcRow(title="Dash Labs App")

<snip>

# Make app layout
import dash_bootstrap_components as dbc
app.layout = dbc.Container(fluid=True, children=tpl.children)

DbcSidebar

The DbcSidebar template creates an app title bar and then includes the inputs in a sidebar on the left of the app, and the outputs in a card in the main app area. This is a great choice when using a template to build an entire app.

# Make template
tpl = dl.templates.DbcSidebar(title="Dash Labs App")

<snip>

# Make app layout
import dash_bootstrap_components as dbc
app.layout = dbc.Container(fluid=True, children=tpl.children)

DdkCard

The DdkCard template introduces a dependency on the proprietary Dash Design Kit library that is included with Dash Enterprise. Like DbcCard, in places all the outputs and inputs in a single card, along with a card title.

# Make template
tpl = dl.templates.DdkCard(title="Dash Labs App", width=50)

<snip>

# Make app layout
import dash_design_kit as ddk
app.layout = ddk.App(children=tpl.children)

DdkRow

Like the DbcRow template, DdkRow places the input and output components in separate cards, and then places those cards in a ddk row container.

# Make template
tpl = dl.templates.DdkRow(title="Dash Labs App")

<snip>

# Make app layout
import dash_design_kit as ddk
app.layout = ddk.App(children=tpl.children)

DdkSidebar

The DdkSidebar template creates a full app experience with an app header, a sidebar for the input controls, and a large main area for the output components.

# Make template
tpl = dl.templates.DdkSidebar(title="Dash Labs App")

<snip>

# Make app layout
import dash_design_kit as ddk
app.layout = ddk.App(children=tpl.children)

Themed DbcSidebar

All of the Dbc* components can be themed using the Bootstrap themeing system. Simply pass the URL of a bootstrap theme css file as the theme argument of the template. Check out https://www.bootstrapcdn.com/bootswatch/ to browse available templates.

Bootstrap figure theming

Templates based on Dash Bootstrap Components have the ability to dynamically generate a plotly.py figure template from the bootstrap CSS theme file. This is enabled by setting figure_template=True in the constructor of a Dash Bootstrap Components template.

tpl = dl.templates.DbcSidebar(
    title="Dash Labs App", 
    theme="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/superhero/bootstrap.min.css",
    figure_template=True
)

or use the convenience theme values provided by Dash Bootstrap Components

import dash_bootstrap_components as dbc
tpl = dl.templates.DbcSidebar(
    title="Dash Labs App",
    theme=dbc.themes.CYBORG,
)

Themed DdkSidebar

Custom DDK themes created by hand, or using the DDK editor can be passed as the theme argument to any of the Ddk* templates.

Theme in demos/ddk_theme.py

# Make template
tpl = dl.templates.DdkSidebar(title="Dash Labs App")

<snip>

# Make app layout
from my_theme import theme
import dash_design_kit as ddk
app.layout = ddk.App(theme=theme, children=tpl.children)

Sidebar Tabs Templates

Dash Labs provides a more advanced template style that support displaying callback outputs across a collection of tabs. These are DbcSidebarTabs and DdkSidebarTabs which use the Dash Bootstrap Components and Dash Design Kit libraries respectively.

These template have a required tab_locations argument that should be set to either:

  1. A list of tab titles. In this case the tab location names will match the tab titles.
  2. A dict from tab locations names to tab titles.

Each tab value becomes a valid template location, making it possible to associate callback input and/or output components with individual tabs.

These templates also provide a tab_input method that returns an dl.Input dependency associated with the active tab value. This can be used to pass the active tab value into the callback function.

Here is an example

import dash
import dash_labs as dl
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objects as go

app = dash.Dash(__name__, plugins=[dl.plugins.FlexibleCallbacks()])

# Load gapminder dataset
df = px.data.gapminder()
years = sorted(df.year.drop_duplicates())
continents = list(df.continent.drop_duplicates())

# Build Themed Template
theme_name = "darkly"
css_url = f"https://bootswatch.com/4/{theme_name}/bootstrap.css"

tpl = dl.templates.DbcSidebarTabs(
    app,
    ["Scatter", "Histogram"],
    title=f"Dash Labs - {theme_name.title()} Theme",
    theme=css_url, figure_template=True
)


@app.callback(
    args=dict(
        continent=tpl.new_checklist(continents, value=continents, label="Continents"),
        year=tpl.new_slider(
            years[0], years[-1], step=5, value=years[-1], label="Year"
        ),
        logs=tpl.new_checklist(
            ["log(x)"], value="log(x)", label="Axis Scale", location="Scatter"
        ),
        tab=tpl.tab_input(),
    ),
    output=[
        tpl.new_graph(location="Scatter"),
        tpl.new_graph(location="Histogram"),
    ],
    template=tpl,
)
def callback(year, continent, logs, tab):
    print(f"Active Tab: {tab}")
    logs = logs or []

    # Let parameterize infer output component
    year_df = df[df.year == year]
    if continent:
        year_df = year_df[year_df.continent.isin(continent)]

    if not len(year_df):
        return [go.Figure(), go.Figure()]

    title = f"Life Expectancy ({year})"
    scatter_fig = (
        px.scatter(
            year_df,
            x="gdpPercap", y="lifeExp",
            size="pop", color="continent",
            hover_name="country", log_x="log(x)" in logs,
            size_max=60,
        )
            .update_layout(title_text=title, margin=dict(l=0, r=0, b=0))
            .update_traces(marker_opacity=0.8)
    )

    hist_fig = px.histogram(
        year_df, x="lifeExp", color="continent", barnorm=""
    ).update_layout(
        title_text=title,
    )

    return scatter_fig, hist_fig


app.layout = dbc.Container(fluid=True, children=tpl.children)

if __name__ == "__main__":
    app.run_server(debug=True)

Creating custom templates

Custom templates can be created by subclassing the dl.template.base.BaseTemplate class. Or, for a custom Bootstrap Components template, subclass dl.teamplates.dbc.BaseDbcTemplate. Similarly, to create a custom DDK template, subclass dl.templates.ddk.BaseDdkTemplate.

Overriding a template may involve:

  1. Customizing the components that are constructed by tp.new_dropdown, tp.new_graph, etc.
  2. Specifying the representation of component labels.
  3. Specifying how a component and label are group together into a container.
  4. Specifying how the input and output containers created in (3) are combined into a single layout container.
  5. Providing custom inline CSS which gets inserted into index.html.
  6. Providing custom locations.