Search code examples
pythonplotlyplotly-dash

Plotly Dash: Place title above each dropdown menu


For some reason, the code is not doing what is suppose to do, where ideally I want the title, dropdown, and the plot side by side, but currently its stacked against each other.

enter image description here

This is the code that vestland provided (thank you again!) for the app layout:

df_run_data = pd.DataFrame({'Hermes': {0: 'H11433-21', 1: 'H11433-21', 2: 'H11433-21', 3: 'H11433-21', 4: 'H11433-21', 5: 'H11433-21', 6: 'H11433-21', 7: 'H11433-22', 8: 'H11433-22', 9: 'H11433-22', 10: 'H11433-22', 11: 'H11433-22', 12: 'H11433-22', 13: 'H11433-22'}, 'Time': {0: 0.28, 1: 23.36, 2: 46.84, 3: 70.88, 4: 95.09, 5: 118.03, 6: 143.49, 7: 0.28, 8: 23.36, 9: 46.84, 10: 70.88, 11: 95.09, 12: 118.03, 13: 143.49}, 'Sample Type': {0: 'Broth', 1: 'Broth', 2: 'Broth', 3: 'Broth', 4: 'Broth', 5: 'Broth', 6: 'Broth', 7: 'Broth', 8: 'Broth', 9: 'Broth', 10: 'Broth', 11: 'Broth', 12: 'Broth', 13: 'Broth'}, 'Tank Weight Pre kg': {0: 0.249, 1: 0.254, 2: 0.318, 3: 0.389, 4: 
0.383, 5: 0.354, 6: 0.356, 7: 0.249, 8: 0.254, 9: 0.318, 10: 0.389, 11: 0.383, 12: 0.354, 13: 0.356}, 'Tank Weight Post kg': {0: 0.243, 1: 0.235, 2: 0.249, 3: 0.251, 4: 0.25, 5: 0.25, 6: 0.277, 7: 0.243, 8: 0.235, 9: 0.249, 10: 0.251, 11: 0.25, 12: 0.25, 13: 0.277}})
runs = df_run_data.Hermes.unique()
headers = list(df_run_data.columns.values)  

#how to use div https://stackoverflow.com/questions/62234909/layout-management-in-plotly-dash-app-how-to-position-html-div
app.layout = html.Div([

    dbc.Row([dbc.Col(html.H1('Nitrogen Balance', style = {'text-align': 'center'}))]),
    
    dbc.Row([dbc.Col(html.Label('Select Run',style={'font-weight': 'bold', "text-align": "start", 'font-size': 25}), width = 6, className = 'bg-primary ps-4'),
             dbc.Col(html.Label('Select Run',style={'font-weight': 'bold', "text-align": "start", 'font-size': 25}), width = 6, className = 'bg-primary ps-4')

            ], justify = 'start'),
    
    dbc.Row([dbc.Col([dcc.Dropdown(id='Hermes',
                    options=[{'label': i, 'value': i} for i in runs],   #df_run_data['Hermes']], #user will see this
                    value= None, #[i for i in df_run_data['Hermes']],  #default values to show runs
                    multi=True,
                    # style={'width':'40%','display': 'inline-block'}
                    )], width = 6, className = 'bg-secondary ps-4 pe-4'),
    
            dbc.Col([dcc.Dropdown(id='Columns',
                    options=[{'label': i, 'value': i} for i in headers],   #df_run_data['Hermes']], #user will see this
                    value= None, #[i for i in df_run_data['Hermes']],  #default values to show runs
                    multi=True,
                    # style={'width':'40%','display': 'inline-block'}
                    )], width = 6, className = 'bg-secondary ps-4 pe-4'),
            
            ], justify = 'start'
           ),
    html.Div(id ='output_container', children=[]),
    #html.Br(), #break here we want the space between divider and graph
    dbc.Row([dbc.Col([dcc.Graph(id='balance',figure={},
                    # style={'width': '80vh', 'height': '50vh'}
                    )], width = 6),
             dbc.Col([dcc.Graph(id='balance1',figure={},
                    # style={'width': '80vh', 'height': '50vh'}
                    
                    )], width = 6)])
 
])

Solution

  • Short answer:

    For better control of the positioning of your Dash components, you should consider following a pattern with:

    app.layout = hmtl.Div([dbc.Row([dbc.Col()])])
    

    Or in your case, something more resembling this:

    app.layout = hmtl.Div([dbc.Row([<header>])
                           dbc.Row([dbc.Col([<label>]),
                                    dbc.Col([<label>])]),
                           dbc.Row([dbc.Col([<dropdown>]),
                                    dbc.Col([<dropdown>])]),
                           dbc.Row([dbc.Col([<graph>]),
                                    dbc.Col([<graph>])])])
    

    Full details in the two snippets below where the first one produces this app:

    enter image description here

    The details:

    This contribution won't be a direct answer to your question regarding the behavior of the particular components you're using, but hopefully it will be a solution to the underlying problem, namely getting the different components to play well together when designing Plotly Dash Apps. And perhaps even provide you a platform on which you can build your future Plotly Dash Apps.

    It's often considered good practice to construct Dash Apps using a container, either dbc.Container or html.Div, that holds a number of rows dbc.Row() that in turn hold a number of columns dbc.Col() which at last hold your Plotly Dash Components either from one or more of these resources:

    from dash import Dash, html, dcc
    import dash_bootstrap_components as dbc
    

    This approach lets you position any component exactly where you would like. And through fine-tuning with Style or className, you can make different components with different features and defaults line up and behave nicely.

    For example, like this:

    App / Code output 1

    enter image description here

    From here, if you'd like to know where each components start, end and align to eachother, you can decorate them using, for example, className='bg-primary' and get this:

    App / Code output 2

    enter image description here

    Code snippet 1

    from jupyter_dash import JupyterDash
    from dash import Dash, html, dcc
    import dash_bootstrap_components as dbc
    import pandas as pd
    import plotly.express as px
    
    app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
    
    surfacing = pd.DataFrame({'Barcode':[1,2,3],
                             'Machine':[3,2,1]})
    
    coating = pd.DataFrame({'Barcode':[1,2,3],
                             'Machine':[3,2,1]})
    
    runs = ['A', 'B']
    headers = ['A', 'B']
    
    app.layout = html.Div([
        dbc.Row([dbc.Col(html.H1('Nitrogen Balance', style = {'text-align': 'center'}))]),
        
        dbc.Row([dbc.Col(html.Label('Select Run',style={'font-weight': 'bold', "text-align": "start", 'font-size': 25}), width = 6, className = 'bg-primary ps-4'),
                 dbc.Col(html.Label('Select Run',style={'font-weight': 'bold', "text-align": "start", 'font-size': 25}), width = 6, className = 'bg-primary ps-4')
    
                ], justify = 'start'),
        
        dbc.Row([dbc.Col([dcc.Dropdown(id='Hermes',
                                options=[{'label': i, 'value': i} for i in runs],   #df_run_data['Hermes']], #user will see this
                                value= None, #[i for i in df_run_data['Hermes']],  #default values to show runs
                                multi=True,
                                # style={'width':'40%','display': 'inline-block'}
                                )], width = 6, className = 'bg-secondary ps-4 pe-4'),
                
                dbc.Col([dcc.Dropdown(id='Columns',
                                options=[{'label': i, 'value': i} for i in headers],   #df_run_data['Hermes']], #user will see this
                                value= None, #[i for i in df_run_data['Hermes']],  #default values to show runs
                                multi=True,
                                # style={'width':'40%','display': 'inline-block'}
                                )], width = 6, className = 'bg-secondary ps-4 pe-4'),
                
                ], justify = 'start'
               ),
        dbc.Row([dbc.Col([dcc.Graph(id='balance',figure={},
                                    # style={'width': '80vh', 'height': '50vh'}
                                   )], width = 6),
                 dbc.Col([dcc.Graph(id='balance1',figure={},
                                    # style={'width': '80vh', 'height': '50vh'}
                                    
                                   )], width = 6)])
     
    ])
    
    
    app.run_server(debug=True)
    

    Code snippet 2

    from jupyter_dash import JupyterDash
    from dash import Dash, html, dcc
    import dash_bootstrap_components as dbc
    import pandas as pd
    import plotly.express as px
    
    app = JupyterDash(external_stylesheets=[dbc.themes.BOOTSTRAP])
    
    surfacing = pd.DataFrame({'Barcode':[1,2,3],
                             'Machine':[3,2,1]})
    
    coating = pd.DataFrame({'Barcode':[1,2,3],
                             'Machine':[3,2,1]})
    
    runs = ['A', 'B']
    headers = ['A', 'B']
    
    app.layout = html.Div([
        dbc.Row([dbc.Col(html.H1('Nitrogen Balance', style = {'text-align': 'center'}))]),
        
        dbc.Row([dbc.Col(html.Label('Select Run',style={'font-weight': 'bold', "text-align": "start", 'font-size': 25}), width = 6, className = 'ps-4'),
                 dbc.Col(html.Label('Select Run',style={'font-weight': 'bold', "text-align": "start", 'font-size': 25}), width = 6, className = 'ps-4')
    
                ], justify = 'start'),
        
        dbc.Row([dbc.Col([dcc.Dropdown(id='Hermes',
                                options=[{'label': i, 'value': i} for i in runs],   #df_run_data['Hermes']], #user will see this
                                value= None, #[i for i in df_run_data['Hermes']],  #default values to show runs
                                multi=True,
                                # style={'width':'40%','display': 'inline-block'}
                                )], width = 6, className = 'ps-4 pe-4'),
                
                dbc.Col([dcc.Dropdown(id='Columns',
                                options=[{'label': i, 'value': i} for i in headers],   #df_run_data['Hermes']], #user will see this
                                value= None, #[i for i in df_run_data['Hermes']],  #default values to show runs
                                multi=True,
                                # style={'width':'40%','display': 'inline-block'}
                                )], width = 6, className = 'ps-4 pe-4'),
                
                ], justify = 'start'
               ),
        dbc.Row([dbc.Col([dcc.Graph(id='balance',figure={},
                                    # style={'width': '80vh', 'height': '50vh'}
                                   )], width = 6),
                 dbc.Col([dcc.Graph(id='balance1',figure={},
                                    # style={'width': '80vh', 'height': '50vh'}
                                    
                                   )], width = 6)])
     
    ])
    
    
    app.run_server(debug=True)