Passing data in multi-tab app

Hi, I am trying to create an app in the dash. There is a first dropdown that selects the data to be used to make plots (a pandas dataframe). I want to use the columns to make some scatter-plots interactively from the dataframe. is there a way to add the options for the scatterplots axes interactviely?

Cheers,

hi @ajeytiwary
That’s a good question. It would be easier for us to answer if you provided an MRE. Do you have initial code that we can build of?

from dash import dcc
from dash import html
import plotly.graph_objs as go
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_bootstrap_components as dbc
import plotly.express as px

import numpy as np
import pandas as pd
df1 = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD'))

df2 = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('abcd'))


available_indicators = df1.columsn.unique()

## layout goes here 
#....... 
dropdown_data = dcc.Dropdown(
                name='Select Dataset',
                id='dropdown-data',
                options=[
                    {'label': 'DataF1', 'value': 'df1'},
                    {'label': 'DataF2', 'value': 'df2'},
                     ],
                value='df1',
                clearable=False,
                searchable=False
            )
dropdown_x = dcc.Dropdown(name = 'Select X-axis',
                                id='xaxis-column',
                                options=[{'label': i, 'value': i} for i in available_indicators ],
                                value='A',
                                clearable = False,  
                            )
dropdown_x = dcc.Dropdown(name = 'Select Y-axis',
                                id='yaxis-column',
                                options=[{'label': i, 'value': i} for i in available_indicators ],
                                value='B',
                                clearable = False,  
                            )
# .... divs
html.Div(className='four columns', children=dropdown_data, style={'margin-top':30},),

html.Div(className='pretty_container', children  = [
                            dropdown_x,])

scatter_plot = dcc.Graph(id="XvY",config= {'displaylogo': False},)


def make_dataset(name):
    if name == 'DataF1':
        df= df1
        df = df.round(2)
        
    if name == 'DataF2':
        df = df2
        df = df.round(2)
        
    return df



@app.callback(
    Output("XvY", "figure"),
    [Input('dropdown-data', 'value'),
    Input('xaxis-column', 'value'),
    Input('yaxis-column', 'value'),
    ],
)
def make_XvY(dataset,xaxis_column_name, yaxis_column_name):
    dff = make_dataset(dataset)
    


    fig = px.scatter(dff, x=dff[xaxis_column_name],
                     y=dff[yaxis_column_name],
                     marginal_x='histogram', marginal_y='histogram')
    
    fig.update_traces(histnorm='probability', selector={'type':'histogram'})

    return fig

I want to first select between the two dataframes df1 and df2 using the dropdown dropdown_data. and based on these the options for the scatterplot x and y dropdown changes.

HI @ajeytiwary
If I understood correctly what you’re trying to do, this piece of code should help.

import dash.exceptions
from dash import Dash, dcc, html, Input, Output, State, ClientsideFunction, no_update
import plotly.graph_objs as go
import dash_bootstrap_components as dbc
import plotly.express as px

import numpy as np
import pandas as pd

df1 = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list('ABCD'))

df2 = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list('abcd'))

available_indicators_df1 = df1.columns.unique()
available_indicators_df2 = df2.columns.unique()

app = Dash(__name__)

## layout goes here
# .......
dropdown_data = dcc.Dropdown(
    id='dropdown-data',
    options=[
        {'label': 'DataF1', 'value': 'df1'},
        {'label': 'DataF2', 'value': 'df2'},
    ],
    value='df1',
    clearable=False,
    searchable=False
)
dropdown_x = dcc.Dropdown(
                          id='xaxis-column',
                          clearable=False,
                          )
dropdown_y = dcc.Dropdown(
                          id='yaxis-column',
                          clearable=False,
                          )
# .... divs
app.layout = html.Div([
    html.Div(className='four columns', children=dropdown_data, style={'margin-top': 30}),

    html.Div(className='pretty_container', children=[
        dropdown_x, dropdown_y]),
    html.Button('Submit', id='btn'),
    dcc.Graph(id="XvY", config={'displaylogo': False}, )
])



@app.callback(
    Output('xaxis-column', 'options'),
    Output('yaxis-column', 'options'),
    Input('dropdown-data', 'value')
)
def make_XvY(dataset):
    print(dataset)

    if dataset == 'df1':
        # dff = df1.round(2)
        xaxis_options = [{'label': i, 'value': i} for i in available_indicators_df1]
        yaxis_options = [{'label': i, 'value': i} for i in available_indicators_df1]

    if dataset == 'df2':
        # dff = df1.round(2)
        xaxis_options = [{'label': i, 'value': i} for i in available_indicators_df2]
        yaxis_options = [{'label': i, 'value': i} for i in available_indicators_df2]

    return xaxis_options, yaxis_options

@app.callback(
    Output("XvY", "figure"),
    Input('btn', 'n_clicks'),
    State('dropdown-data', 'value'),
     State('xaxis-column', 'value'),
     State('yaxis-column', 'value'),
prevent_initial_call=True
)
def make_XvY(n, dataset, xaxis_column_name, yaxis_column_name):
    if xaxis_column_name is None or yaxis_column_name is None:
        return no_update
    elif dataset == 'df1':
        dff = df1
    elif dataset == 'df2':
        dff = df2

    fig = px.scatter(dff, x=dff[xaxis_column_name],
                     y=dff[yaxis_column_name],
                     marginal_x='histogram', marginal_y='histogram')

    fig.update_traces(histnorm='probability', selector={'type': 'histogram'})

    return fig


if __name__=='__main__':
    app.run_server()

1 Like

Hi, @adamschroeder thanks for your answer. Sorry, I could have provided a better MWE. what I meant was something like this.
my code it now organised in

  • app.py
    • tab_1.py
    • tab_2.py

what I want to do is to pass the columns of the different dataframes when they are selected from the dropdown. Right now I am able to do this but I also get the error
ID not found in layout

app.py

# from dash import Dash, dcc, html
# from dash.dependencies import Input, Output

import dash.exceptions
from dash import Dash, dcc, html, Input, Output, State, ClientsideFunction, no_update
import plotly.graph_objs as go
import dash_bootstrap_components as dbc
import plotly.express as px
import tab_1, tab_2

import numpy as np
import pandas as pd


external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']




df1 = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list('ABCD'))

df2 = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list('abcd'))

df3 = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list('EFGH'))

df4 = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list('efgh'))


available_indicators_df1 = df1.columns.unique()
available_indicators_df2 = df2.columns.unique()

available_indicators_df3 = df3.columns.unique()

available_indicators_df4 = df4.columns.unique()

app = Dash(__name__, external_stylesheets=external_stylesheets)

app.config.suppress_callback_exceptions = True



dropdown_data = dcc.Dropdown(
    id='dropdown-data',
    options=[
        {'label': 'DataF1', 'value': 'df1'},
        {'label': 'DataF2', 'value': 'df2'},
    ],
    value='df1',
    clearable=False,
    searchable=False
)
dropdown_x = dcc.Dropdown(
                          id='xaxis-column',
                          clearable=False,
                          )
dropdown_y = dcc.Dropdown(
                          id='yaxis-column',
                          clearable=False,
                          )




tab_1_layout = dcc.Tab(label="tab one", value='one',id="tab_1")
tab_2_layout = dcc.Tab(label="tab two", value='two',id="tab_2")

# suppress_callback_exceptions=True

app.layout = html.Div([
    html.Div([
    html.H1('Dash multi tab share callback'),
    html.Div(className='pretty container', children=dropdown_data, style={'margin-top': 30}),
    html.Hr()    ]),
    
    html.Div([    
        dcc.Tabs(id="tabs", value='tab-1-example-graph', children=[
            tab_1_layout,
            tab_2_layout,
        ]),
        # html.Div(id='tabs-content-example-graph')
    html.Div(id="tab-content")
    ]), 
    
    ])
@app.callback(
    Output("tab-content", "children"),
    [Input("tabs", "value")],
)
def render_tab_content(value):
    """
    This callback takes the 'active_tab' property as input, as well as the
    stored graphs, and renders the tab content depending on what the value of
    'active_tab' is.
    """
    if value is not None:
        if value == "one":
            return tab_1.layout
        
        
        elif value == "two":
            return tab_2.layout
            
    return "Please Select a Tab"


@app.callback(
    Output('xaxis-column', 'options'),
    Output('yaxis-column', 'options'),
    Input('dropdown-data', 'value')
)
def make_XvY(dataset):
    print(dataset)

    if dataset == 'df1':
        # dff = df1.round(2)
        xaxis_options = [{'label': i, 'value': i} for i in available_indicators_df1]
        yaxis_options = [{'label': i, 'value': i} for i in available_indicators_df1]

    if dataset == 'df2':
        # dff = df1.round(2)
        xaxis_options = [{'label': i, 'value': i} for i in available_indicators_df2]
        yaxis_options = [{'label': i, 'value': i} for i in available_indicators_df2]

    return xaxis_options, yaxis_options
@app.callback(
    Output("XvY", "figure"),
    # Input('btn', 'n_clicks'),
    [Input('dropdown-data', 'value'),
     Input('xaxis-column', 'value'),
     Input('yaxis-column', 'value')],
# prevent_initial_call=True
)
def make_XvY(dataset, xaxis_column_name, yaxis_column_name):
    if xaxis_column_name is None or yaxis_column_name is None:
        return no_update
    elif dataset == 'df1':
        dff = df1
    elif dataset == 'df2':
        dff = df2

    fig = px.scatter(dff, x=dff[xaxis_column_name],
                     y=dff[yaxis_column_name],
                     marginal_x='histogram', marginal_y='histogram')

    fig.update_traces(histnorm='probability', selector={'type': 'histogram'})

    return fig



# @app.callback(
#     Output('xaxis-column', 'options'),
#     Output('yaxis-column', 'options'),
#     Input('dropdown-data', 'value')
# )
# def make_XvY_drops(dataset):
#     print(dataset)

#     if dataset == 'df1':
#         # dff = df1.round(2)
#         xaxis_options = [{'label': i, 'value': i} for i in available_indicators_df1]
#         yaxis_options = [{'label': i, 'value': i} for i in available_indicators_df1]

#     if dataset == 'df2':
#         # dff = df1.round(2)
#         xaxis_options = [{'label': i, 'value': i} for i in available_indicators_df2]
#         yaxis_options = [{'label': i, 'value': i} for i in available_indicators_df2]

#     return xaxis_options, yaxis_options     
   
# @app.callback(Output("XvY", "figure"),
#               [Input('dropdown-data', 'value'),
#                Input('xaxis-column', 'value'),
#                Input('yaxis-column', 'value')],)
# def make_XvY(dataset, xaxis_column_name, yaxis_column_name):
#     if xaxis_column_name is None or yaxis_column_name is None:
#         return no_update
#     elif dataset == 'df1':
#         dff = df1
#         # xaxis_options = [{'label': i, 'value': i} for i in available_indicators_df1]
#         # yaxis_options = [{'label': i, 'value': i} for i in available_indicators_df1]
#     elif dataset == 'df2':
#         dff = df2
#         # xaxis_options = [{'label': i, 'value': i} for i in available_indicators_df2]
#         # yaxis_options = [{'label': i, 'value': i} for i in available_indicators_df2]

#     fig = px.scatter(dff, x=dff[xaxis_column_name],
#                      y=dff[yaxis_column_name],
#                      marginal_x='histogram', marginal_y='histogram')

#     fig.update_traces(histnorm='probability', selector={'type': 'histogram'})

#     return fig




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

tab_1.py


from dash import dcc
from dash import html

dropdown_x = dcc.Dropdown(
                          id='xaxis-column',
                          clearable=False,
                          )
dropdown_y = dcc.Dropdown(
                          id='yaxis-column',
                          clearable=False,
                          )


def tab_1():
     label="First tab", 
     value= 'one',
     
     layout = html.Div(className="heading", children=[ 

     html.Div([
        html.Div(className='pretty_container', children=[
        dropdown_x, dropdown_y]),
    # html.Button('Submit', id='btn'),
        dcc.Graph(id="XvY", config={'displaylogo': False}, )
        ]), 
     ])
     return layout, label, value
 
 
layout, label, value = tab_1()
     

tab_2.py


from dash import dcc
from dash import html

dropdown_x = dcc.Dropdown(
                          id='xaxis-column',
                          clearable=False,
                          )
dropdown_y = dcc.Dropdown(
                          id='yaxis-column',
                          clearable=False,
                          )


def tab_2():
     label="Second tab", 
     value= 'two',
     
     layout = html.Div(className="heading", children=[ 

     html.Div([
        html.Div(className='pretty_container', children=[
        dropdown_x, dropdown_y]),
    # html.Button('Submit', id='btn'),
        dcc.Graph(id="XvY", config={'displaylogo': False}, )
        ]), 
     ])
     return layout, label, value
 
 
layout, label, value = tab_2()