Sharing a dataframe between tabs

I have a Dash App with multiple tabs. Is there a way to share a dataframe between tabs i.e. sharing a dataframe created in tab 1 with tab 2

Check out the chapter on “sharing data between callbacks” - https://plot.ly/dash/sharing-data-between-callbacks

1 Like

Hi @chriddyp, thank you for the response. I guess the problem I am facing is not completely solvable using hidden divs.

For Ex:

  • In Tab 1, I am storing data in a hidden div and then using that data, I am creating a bar chart
  • Next, I navigate to Tab 2 and show a line graph based on the same hidden data again.
  • However, when I navigate back to the first tab, the stored data in the hidden div is lost.

Below is the sample code.

import dash
from dash.dependencies import Input, Output, State, Event
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
import json

tab1_layout = [html.Div("Storing data to hidden div and displaying as bar chart"),
               html.Button("Store data into hidden div",
                            n_clicks=0,
                            id='store-data-hidden-div'),
               html.Button("Display data from hidden div as bar chart",
                           n_clicks=0,
                           id='create-bar-chart'),
               dcc.Graph(id = "bar-graph")
               ]

tab2_layout = [html.Div("retrieving data from hidden div and displaying as line chart"),
               html.Button("Display data from hidden div as line chart",
                           n_clicks=0,
                           id='create-line-chart'),
               dcc.Graph(id = "line-graph")
               ]

app = dash.Dash()
app.config['suppress_callback_exceptions'] = True

## css file
app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

app.layout = html.Div([
    # hidden Div for storing data needed for graphs
    html.Div(id='graph-data-json-dump', style={'display': 'none'}),
    # Title
    html.Div("Sharing data between callbacks"),

    # tabs
    dcc.Tabs(
            tabs=[
                {'label': 'Tab 1', 'value': 1},
                {'label': 'Tab 2', 'value': 2}
              ],
            value=1,
            id='tabs'
        ),

    # Tab-layout
    html.Div(id='tab-layout')
])

#switching between tabs
@app.callback(dash.dependencies.Output('tab-layout', 'children'),
              [dash.dependencies.Input('tabs', 'value')])
def call_tab_layout(tab_value):
    if tab_value == 1:
        return tab1_layout
    elif tab_value == 2:
        return tab2_layout
    else:
        html.Div()

#sending data to hidden div from tab1
@app.callback(dash.dependencies.Output('graph-data-json-dump', 'children'),
              [dash.dependencies.Input('store-data-hidden-div', 'n_clicks')])
def store_data_to_hidden_div(nclick):
    if nclick >0:
        df = pd.DataFrame({'x_axis':[6,4,9],
                        'y_axis':[4,2,7]})
        return df.to_json(orient = 'split')

#plotting bar graph in same tab

@app.callback(dash.dependencies.Output('bar-graph', 'figure'),
              [dash.dependencies.Input('graph-data-json-dump', 'children'),
               dash.dependencies.Input('create-bar-chart', 'n_clicks')])
def create_bar_chart(json_dump, nclick):
    if nclick >0:
        json_dump = json.loads(json_dump)
        json_dump_df = pd.DataFrame(json_dump['data'], columns=json_dump['columns'])

        data = [go.Bar(
            x = json_dump_df['x_axis'].values,
            y = json_dump_df['y_axis'].values,
            name = "Bar Chart")]
        fig = go.Figure(data = data)
        return fig

#plotting line graph in next tab
@app.callback(dash.dependencies.Output('line-graph', 'figure'),
              [dash.dependencies.Input('graph-data-json-dump', 'children'),
               dash.dependencies.Input('create-line-chart', 'n_clicks')])
def create_line_chart(json_dump, nclick):
    if nclick > 0:
        json_dump = json.loads(json_dump)
        json_dump_df = pd.DataFrame(json_dump['data'], columns=json_dump['columns'])

        data = [go.Scatter(
            x=json_dump_df['x_axis'].values,
            y=json_dump_df['y_axis'].values,
            name="Line Chart")]
        fig = go.Figure(data=data)
        return fig


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

Thanks for the example! I see what’s happening now.

The problem is in this callback. Here’s what’s happening:

  1. When you navigate back to Tab 1, you are returning tab1_layout
  2. tab1_layout returns a two buttons where n_clicks=0
  3. Since the callback returns new components with IDs, Dash fires the appropriate callbacks. In this case, it fires the callbacks with n_clicks=0 for the newly rendered buttons, therefore resetting the data that you stored previously in your hidden div.

You have a couple of options:

  1. Prevent the update from happening by raising an exception in your callback when n_clicks=0
  2. Move the Button that triggers the datastore out of tab1_layout and keep it stored persistently throughout the app.
1 Like

Hi chriddyp, I had the same problem. could you create example of how to do with your first option? many thanks.

Also, what is odd is when I switched between pages, only the html table shows the data of previous load, all figures are gone. How to let the figures show?

I have a similar problem @chriddyp

I’m using two tabs with two different graphs, Graphs get updated dynamically using callbacks.
When I navigate between tabs, and come back to the first tab, the graph is gone. Is there a way to handle this scenario to retain data in the layout when you switch back between tabs.
Appreciate you time and help.

Thanks!

2 Likes

@chriddyp, Thanks for all the wonderful work you do and for the great examples.

I am facing this problem as well: storing data in a hidden div, but losing it upon navigating across tabs. Do you mind providing code examples of the options you suggest?

three reasons why you should buy plotly pro: support open source, get great support, host your plots and dashboards online