Layout
Style
import dash
import dash_html_components as html

app = dash.Dash(__name__)

app.layout = html.H1(children="Avocado Analytics",
            style={"font-size": "18px", "color": "red", "font-weight": "bold", "border-style": "ridge"})

if __name__ == "__main__":
    app.run_server(debug=True) # turn on Dash tools
		
CSS
  • make a assets folder in the same directory as your app.py. Put all your .cssand .js files there
  • Initialize the app object by using app = dash.Dash(__name__)
  • Now Dash will automatically load your CSS and JS files
  • Use !important flag to prevend react from overwriting css settings
  • # assets/style.css
    .header-title {
        color: red;
        font-size: 48px;
        font-weight: bold;
        text-align: center;
        margin: 0 auto;
    }
    		
    import dash
    import dash_html_components as html
    
    app = dash.Dash(__name__)
    
    def main():
        app.layout = html.H1(children="Avocado Analytics",
                className="header-title",
        )
    
    if __name__ == "__main__":
        main()
        app.run_server(debug=True)
    		
    Page Load
  • By default, Dash apps store the app.layout in memory. This ensures that the layout is only computed once, when the app starts
  • Setting app.layout to a function can serve a dynamic layout on every page load
  • import datetime
    
    import dash
    import dash_html_components as html
    
    app = dash.Dash(__name__)
    
    def getLayout():
        return html.H1(children="Avocado Analytics"+str(datetime.datetime.now()),
                style={"font-size": "18px", "color": "red", "font-weight": "bold"})
    
    app.layout = getLayout # not app.layout = getLaout()
    
    if __name__ == "__main__":
        app.run_server(debug=True)
    		
    Component CSS
    # assets/style.css
    .header-title {
        color: red;
        font-size: 48px;
        font-weight: bold;
        text-align: center;
        margin: 0 auto;
        border: solid;
        width: 80%;
    }
    
    .card {
        margin-bottom: 24px;
        width: 80%;
        margin: auto;
        box-shadow: 0 4px 6px 0 rgba(0, 0, 0, 0.18);
    }
    		
    import dash
    import dash_core_components as dcc
    import dash_html_components as html
    import pandas as pd
    
    data = pd.read_csv("avocado.csv")
    data = data.query("type == 'conventional' and region == 'Albany'")
    data["Date"] = pd.to_datetime(data["Date"], format="%Y-%m-%d")
    data.sort_values("Date", inplace=True)
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div(
            children = [html.Div(
                children = [html.H1(children="Avocado Analytics",
                className="header-title",
        )]
                ),
    
                html.Div(
            children = dcc.Graph(
                figure={
                    "data": [
                        {
                            "x": data["Date"],
                            "y": data["Total Volume"],
                            "type": "lines",
                        },
                    ],
                    "layout": {"title": "Avocados Sold"},
                },
            ),
            className="card"
            )
        ]
    )
    
    if __name__ == "__main__":
        app.run_server(debug=True)
    		
    Code Layout (authored by Ms. Sarah Osborn)

    # app.py
    from config import *
    from components import get_layout
    
    app.layout = get_layout()
    
    app.config['suppress_callback_exceptions'] = True
    
    if __name__ == '__main__':
        app.run_server(debug = True)
            
    # config.py
    import dash
    
    app = dash.Dash(__name__)
    server = app.server
    
    configuration = {'name':'Lin'}
            
    # assets/style.css
    .header-title {
        color: red;
    }
            
    # components/__init__.py
    from components.c1 import get_layout
            
    # components/c1/__init__.py
    from components.c1.c import *
            
    # components/c1/c.py
    from dash import html
    from util import *
    from components.c2 import get_content
    
    def get_layout():
        return html.Div([
            get_title('Util'),
            get_content()
        ], className='header-title')
            
    # components/c2/__init__.py
    from components.c2.c import get_content
    from components.c2.callbacks import *
            
    # components/c2/c.py
    from dash import html
    
    def get_content():
        return html.Div([
            get_button(),
            get_output()
        ])
    
    def get_button():
        return html.Button('Submit', id = 'submit')
    
    def get_output():
        return html.Div(id = 'output')
            
    # components/c2/callbacks.py
    from config import *
    from util import *
    from dash import html
    from dash.dependencies import Output, Input, State
    from dash.exceptions import PreventUpdate
    
    @app.callback(
        Output('output', 'children'),
        Input('submit', 'n_clicks'),
    )
    def update_container(n_clicks):
        print('Load callback ...')
    
        if not n_clicks:
            raise PreventUpdate
    
        return html.Div(get_title('Content'))
            
    # util/__init__.py
    from util.util import *
            
    # util/util.py
    def get_title(t):
        return 'Title: '+t
            
    Layout Summary

  • "A nonexistent object was used" warning under debug mode
  • suppress_callback_exceptions cannot suppress in this case, need to disable dev_tools_ui
  • Dynamic Components

    import dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output
    from dash.exceptions import PreventUpdate
    
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
    
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
    
    app.layout = html.Div([
        dcc.Input(id='my-input', type='text'),
        html.Div(id='my-output'),
        html.Br(),
        html.Div(id='holder'),
    ])
    
    # suppress exception when a component does not exist in the initial state
    app.config['suppress_callback_exceptions'] = True
    
    @app.callback(
        Output(component_id='my-output', component_property='children'),
        Input(component_id='my-input', component_property='value')
    )
    def update_output_div(input_value):
        if not input_value:
            raise PreventUpdate # do not update the callback output
        if len(input_value) < 10:
            return 'Output: {}'.format(input_value)
        else:
            return ['Output: {}'.format(input_value), html.Label("Hello World! ", id='my-label')]
    
    @app.callback(
        Output(component_id='my-label', component_property='children'),
        Input(component_id='my-input', component_property='value')
    )
    def update_output_label(input_value):
            return input_value
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    Input Component not Exist in Intial State

  • It is possible for a callback to insert new Dash components into a Dash app's layout
  • If these new components are themselves the inputs to other callback functions, then their appearance in the Dash app's layout will trigger those callback functions to be executed
  • import dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output
    from dash.exceptions import PreventUpdate
    
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
    
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
    
    app.layout = html.Div([
        dcc.Input(id='my-input', type='text'),
        html.Div(id='my-output'),
        html.Br(),
        html.Div(id='holder'),
    ])
    
    app.config['suppress_callback_exceptions'] = True
    
    @app.callback(
        Output(component_id='my-output', component_property='children'),
        Input(component_id='my-label', component_property='children')
    )
    def update_output_div(input_value):
        return 'Output: '+str(input_value)
    
    @app.callback(
        Output(component_id='holder', component_property='children'),
        Input(component_id='my-input', component_property='value')
    )
    def update_output_label(input_value):
        if not input_value:
            raise PreventUpdate
        return html.Label(str(input_value), id='my-label')
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    None-Exist and Exit Input Components and None-Exist Component

    import dash
    from dash.dependencies import Input, Output, State
    import dash_html_components as html
    import dash_core_components as dcc
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__, suppress_callback_exceptions = True)
    
    def get_layout():
        return html.Div([
            html.Button('Submit', id='button'),
            html.Div(2, id='label-1'),
            html.Div(1, id='label-2'),
            html.Div(id='container')
            ])
    
    app.layout = get_layout()
    
    @app.callback(Output('container', 'children'),
                   Input('button', 'n_clicks'),
                   )
    def insert_input_3(n):
        if not n:
            raise PreventUpdate
        return [dcc.Input(value = 10, id='input-1'), dcc.Input(value=20, id='input-2')]
    
    @app.callback(Output('input-2', 'value'),
                   [Input('label-1', 'children'),
                    Input('input-1', 'value')]
                   )
    def insert_input_2(label_value, input_value):
        if not input_value:
            raise PreventUpdate
        return int(label_value)+int(input_value)
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    One Input Component not Exist and One Input Component Exist in Intial State

  • "A nonexistent object was used" warning under debug mode
  • suppress_callback_exceptions cannot suppress in this case, need to disable dev_tools_ui
  • import dash
    from dash.dependencies import Input, Output, State
    import dash_html_components as html
    import dash_core_components as dcc
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__, suppress_callback_exceptions = True)
    
    def get_layout():
        return html.Div([
            dcc.Input(id='input-1'),
            dcc.Input(value = 20, id= 'input-2'),
            html.Div(id='container', style={'border': 'red'}),
            html.Div(id='label-1'),
            ])
    
    app.layout = get_layout()
    
    @app.callback(Output('container', 'children'),
                   Input('input-1', 'value'),
                   )
    def insert_input_3(v1):
        if not v1:
            return None
        return dcc.Input(value=int(v1)*10, id='input-3', style={'color': 'red'})
    
    
    @app.callback(Output('label-1', 'children'),
                  [Input('input-3', 'value'),
                   Input('input-2', 'value')]
                )
    def insert_label_1(v3, v2):
        return int(v3)+int(v2)
    
    if __name__ == '__main__':
        app.run_server(debug=True, dev_tools_ui=False)
    		
    Mix None-Exist Component and Exist Component in Inputs and Outputs

  • "A nonexistent object was used" warning under debug mode
  • suppress_callback_exceptions cannot suppress in this case, need to disable dev_tools_ui
  • import dash
    from dash.dependencies import Input, Output, State
    import dash_html_components as html
    import dash_core_components as dcc
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__, suppress_callback_exceptions = True)
    
    def get_layout():
        return html.Div([
            html.Button('Submit', id='button'),
            html.Div(2, id='label-1'),
            html.Div(1, id='label-2'),
            html.Div(id='container')
            ])
    
    app.layout = get_layout()
    
    @app.callback(Output('container', 'children'),
                   Input('button', 'n_clicks'),
                   )
    def insert_input_3(n):
        if not n:
            raise PreventUpdate
        return [dcc.Input(value = 10, id='input-1'), dcc.Input(value=20, id='input-2')]
    
    @app.callback([Output('label-2', 'children'),
                   Output('input-2', 'value')],
                   [Input('label-1', 'children'),
                    Input('input-1', 'value')]
                   )
    def insert_input_2(label_value, input_value):
        if not input_value:
            raise PreventUpdate
        return label_value, input_value
    
    if __name__ == '__main__':
        app.run_server(debug=True, dev_tools_ui=False)
    		
    Output Component not Exist in Intial State

  • Callback function with non-existing component as output will be triggered once the component is inserted
  • import dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output
    from dash.exceptions import PreventUpdate
     
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
     
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
     
    app.layout = html.Div([
        html.Button(id='my-button'),
        html.Label('Hello World!', id='my-label'),
        html.Div(id='holder'),
    ])
     
    app.config['suppress_callback_exceptions'] = True
     
    @app.callback(
        Output(component_id='holder', component_property='children'),
        Input(component_id='my-button', component_property='n_clicks')
    )
    def update_button(n_clicks):
        if not n_clicks:
            raise PreventUpdate
        return html.Div(id='my-div', style={'border': 'solid', 'border-color': 'red'})
     
    @app.callback(
        Output(component_id='my-div', component_property='children'),
        Input(component_id='my-label', component_property='children')
    )
    def update_div(c):
        return c
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    One Input and Multiple Outputs

    import dash
    import dash_html_components as html
    import dash_core_components as dcc
    from dash.dependencies import Input, Output
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([
        dcc.Input(id = 'input'),
        html.Div(id='output_1'),
        html.Div(id='output_2')
    ])
    
    
    @app.callback(Output('output_1', 'children'),
                  Input('input', 'value'))
    def update_output_1(data):
        if data is None:
            raise PreventUpdate
        return data
    
    @app.callback(Output('output_2', 'children'),
                  Input('input', 'value'))
    def update_output_1(data):
        if data is None:
            raise PreventUpdate
        return data
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    import dash
    import dash_html_components as html
    import dash_core_components as dcc
    from dash.dependencies import Input, Output
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([
        dcc.Input(id = 'input'),
        html.Div(id='output_1'),
        html.Div(id='output_2')
    ])
    
    
    @app.callback([Output('output_1', 'children'),
                   Output('output_2', 'children')],
                  Input('input', 'value'))
    def update_output_1(data):
        if data is None:
            raise PreventUpdate
        return data, data
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    Input and Output Belong to the Same Component

    # trigger with timestamp, which is a unix timestamp when the data was last edited
    import dash
    from dash import dash_table
    from dash.dependencies import Input, Output, State
    from dash import html
    from dash import dcc
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([
        dcc.Input(placeholder = 'Enter', id = 'output'),
        dcc.Input(placeholder = 'Input Copy', id = 'output2'),
    ])
    
    
    @app.callback(
        Output('output', 'value'),
        Output('output2', 'value'),
        Input('output', 'n_submit_timestamp'),
        State('output', 'value'))
    def update_columns(timestamp, content):
        print(timestamp, content)
        if not timestamp:
            raise PreventUpdate
        return str(content or '')+'_updated', str(content or '')+'_updated'
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    # trigger with a component
    import dash
    from dash import dash_table
    from dash.dependencies import Input, Output, State
    from dash import html
    from dash import dcc
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([
        dcc.Input(placeholder = 'Enter', id = 'output'),
        dcc.Input(placeholder = 'Input Copy', id = 'output2'),
        html.Button('Click', 'button')
    ])
    
    
    @app.callback(
        Output('output', 'value'),
        Output('output2', 'value'),
        Input('button', 'n_clicks'),
        State('output', 'value'))
    def update_columns(n_clicks, content):
        print(n_clicks, content)
        if not n_clicks:
            raise PreventUpdate
        return str(content or '')+'_updated', str(content or '')+'_updated'
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Circular Dependencies
  • Circular Dependencies is not allowed
  • Use State to bypass the limitation
  • import dash
    from dash import dash_table
    from dash.dependencies import Input, Output, State
    from dash import html
    from dash import dcc
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([
        dcc.Input(id = 'output'),
        dcc.Input(id = 'output2'),
    ])
    
    @app.callback(
        Output('output2', 'value'),
        Input('output', 'n_submit_timestamp'),
        State('output', 'value'))
    def update_columns(timestamp, content):
        return content
    
    @app.callback(
        Output('output', 'value'),
        Input('output2', 'n_submit_timestamp'),
        State('output2', 'value'))
    def update_columns(timestamp, content):
        return content
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    One Output with One Input from Multiple Components

    import dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output
    from dash.exceptions import PreventUpdate
     
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
     
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
     
    app.layout = html.Div([
        html.Button("Button", id='button-1'),
        html.Div('Container 1', id='container-1'),
        html.Div('Container 2', id='container-2'),
        html.Div('Label 1', id='label-1')
    ])
     
    app.config['suppress_callback_exceptions'] = True
     
    @app.callback(
        Output(component_id='container-1', component_property='children'),
        Input(component_id='button-1', component_property='n_clicks'),
    )
    def update_slidder_1(value):
        if not value:
            raise PreventUpdate
    
        return str(value)
    
    @app.callback(
        Output(component_id='container-2', component_property='children'),
        Input(component_id='container-1', component_property='children'),
    )
    def update_slidder_2(value):
        if not value:
            raise PreventUpdate
    
        return str(value)
    
    @app.callback(
        Output(component_id='label-1', component_property='children'),
        Input(component_id='container-2', component_property='children'),
    )
    def update_slidder_3(value):
        if not value:
            raise PreventUpdate
    
        return str(value)
     
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    Inverted Component Be Both Input and Output
  • Inserted component cannot be the input in one callback function and the output in another callback function
  • One Output with Two Independent Inputs
  • Two inputs in two callbacks have the same component as output is not allowed
  • One Output with One Input from Multiple Components
  • Instead of using multiple independent inputs, Dash uses multiple inputs from multiple components in one callbacks
  • import dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output
    from dash.exceptions import PreventUpdate
     
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
     
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
     
    app.layout = html.Div([
        html.Button("Button 1", id='button-1'),
        html.Button("Button 2", id='button-2'),
        html.Label('Hello World!', id='my-label'),
    ])
     
    app.config['suppress_callback_exceptions'] = True
     
    @app.callback(
        Output(component_id='my-label', component_property='children'),
        [Input(component_id='button-1', component_property='n_clicks'),
        Input(component_id='button-2', component_property='n_clicks')]
    )
    def update_button_1(c1, c2):
        if not c1 and not c2:
            raise PreventUpdate
    
        ctx = dash.callback_context
        if ctx.triggered:
            if 'button-1' in ctx.triggered[0]['prop_id']:
                return "Button 1: "+str(ctx.triggered[0]['value'])
            if 'button-2' in ctx.triggered[0]['prop_id']:
                return "Button 2: "+str(ctx.triggered[0]['value'])
            return "A button is clicked ..."
     
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    Both Input and Output are from Inserted Components

    import dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output
    from dash.exceptions import PreventUpdate
     
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
     
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
     
    app.layout = html.Div([
        html.Button("Button", id='button-1'),
        html.Div(id='container')
    ])
     
    app.config['suppress_callback_exceptions'] = True
     
    def get_slidder():
        return dcc.Slider(
            id='slider',
            min=1,
            max=10,
            value=1,
            marks={num: {'label': str(num), 'style': {'color':'red'}} for num in range(1, 11)},
            step=None
        )
    
    @app.callback(
        Output(component_id='container', component_property='children'),
        Input(component_id='button-1', component_property='n_clicks'),
    )
    def update_button_1(c1):
        if not c1:
            raise PreventUpdate
    
        return [html.Div(get_slidder()), html.Div(html.Label('Content 2', id = 'label'))]
    
    @app.callback(
        Output(component_id='label', component_property='children'),
        Input(component_id='slider', component_property='value'),
    )
    def update_slidder(value):
        return str(value)
     
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    Use Display to Control Shown/Hidden
    .holder-1 {
    	color: red;
    	background-color: yellow;
    }
    
    .holder-2 {
    	color: blue;
    	border: solid;
    }
    		
    import dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output, State
    from dash.exceptions import PreventUpdate
     
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
     
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
     
    app.layout = html.Div([
        html.Button('Submit', id='button'),
        html.Div('Hold 1 ...', id='holder-1', className='holder-1'),
        html.Div(html.Label('Label ...'), id='holder-2', className='holder-2'),
    ])
     
    #app.config['suppress_callback_exceptions'] = True
     
    @app.callback(
        Output(component_id='holder-2', component_property='style'),
        Input(component_id='button', component_property='n_clicks'),
    )
    def update_button(n_clicks):
        if not n_clicks:
            raise PreventUpdate
    
        if n_clicks%2 == 0:
            return {'display':'block'}
        else:
            return {'display':'none'}
     
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    Prevent Initial Component Callback
  • Only applies if both the callback output and input are present in the app layout upon initial load of the application
  • import dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output
    from dash.exceptions import PreventUpdate
    
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
    
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
    
    app.layout = html.Div([
        dcc.Input(id='my-input', type='text'),
        html.Div(id='my-output'),
        html.Br(),
        html.Div(id='holder'),
    ])
    
    app.config['suppress_callback_exceptions'] = True
    
    @app.callback(
        Output(component_id='my-output', component_property='children'),
        Input(component_id='my-label', component_property='children')
    )
    def update_output_div(input_value):
        return 'Output: '+str(input_value)
    
    @app.callback(
        Output(component_id='holder', component_property='children'),
        Input(component_id='my-input', component_property='value'),
        prevent_initial_call=True
    )
    def update_output_label(input_value):
        return html.Label(str(input_value), id='my-label')
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    		
    Reference
  • Dev Tools
  • HTML Components