Black Lives Matter. Please consider donating to Black Girls Code today.

Data tables with multi-pages

Hello,

I was following the Dash tutorial to make multipages linked to URLS with a number of apps as in the Dash documentation. All went well and managed to make the examples worked with some other apps that I have made.

However, I’m stills stuck trying to make one in special to work. This app uses the experimental library of data tables to show the results of some data and some bar plots linked to it.

The app works on its own, but once I link it to the index.py code as in the multipage recommendatios ( dcc.Link(‘Navigate to ‘, href=’/apps/app2’) ) the app does not display.

I started to take the app apart and discovered that menus and other layout elements do display, but once I include the dt.DataTable(rows=[{}]) code the whole app is not displayed.

Any suggestion or advice?

Many thanks!

1 Like

Have you seen Comment #40 - Display tables in Dash? Can you post a small, reproducable example?

1 Like

Hello!

Many thanks for the suggestion, I did try to use it but unfortunately it did not work.

I’m including now an example based on the multi page instructions in Dash.

Here is my index.py file:

from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt

from app import app
from apps import app1, app2, app3


app.layout = html.Div([
    dcc.Location(id='url', refresh=False),

    dcc.Link('Navigate to App1 barpplot', href='/apps/app1'),
    html.Br(),
    dcc.Link('Navigate to App2 data tables', href='/apps/app2'),
    html.Br(),
    dcc.Link('Navigate to App3 scatter plot', href='/apps/app3'),
    # Included sniper as per suggestion
    html.Div(dt.DataTable(rows=[{}]), style={'display': 'none'}),

    html.Div(id='page-content')
])


@app.callback(Output('page-content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/apps/app1':
         return app1.layout
    elif pathname == '/apps/app2':
         return app2.layout
    elif pathname == '/apps/app3':
         return app3.layout
    else:
        return '404'

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

The index serves a very basic App where the links are displayed (from here I want to give access to three apps). When I click on the first and third link they both work, but not the second.

See bellow the code for app2.py (modified code from your example, usage.py to fetch a table from a postgre DB), that code works as a separate app but not in the multipage ensemble.

Important considerations for app2.py

As I’m pinging the data base to get info from different tables, I needed to add two extra appcalls, one to update the name of the columns depending on the table and dropping some unwanted columns, and another one to update the content of the table (rows), depending on what was selected and called using the drop menu (in this case either table 1 or table 2).

I suspect those two calls might be the culprits as your example (usage.py) worked well when I tested it on the multipage ensemble. Any advise/suggestion or work-around?

Thanks!

Leo

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import json
import pandas as pd
import numpy as np
import plotly
from sqlalchemy import create_engine
from app import app


app.scripts.config.serve_locally = True
# app.css.config.serve_locally = True


connstr = 'database_link'

engine = create_engine(connstr)

breakdowns = [
    {'label': 'Option1', 'value': '1'},
    {'label': 'Option2', 'value': '2'},
]

layout = html.Div([
    html.H4('Gapminder DataTable'),
    html.Div(
        [
            html.Div(
                [
                    html.Label('Select the study to explore'),
                    dcc.Dropdown(
                        id='file_to_load',
                        options=breakdowns,
                        value='1'),
                ])
        ]),
    dt.DataTable(
        rows=[{}],

        # optional - sets the order of columns
        columns=[{}],

        row_selectable=True,
        filterable=True,
        sortable=True,
        selected_row_indices=[],
        id='datatable-gapminder'
    ),
    html.Div(id='selected-indexes'),
    dcc.Graph(
        id='graph-gapminder'
    ),
], className="container")


@app.callback(
    Output('datatable-gapminder', 'rows'),
    [Input('file_to_load', 'value')])
def update_table(value):
    with engine.connect() as conn, conn.begin():
        DF_GAPMINDER = pd.read_sql("""
                SELECT *
                FROM """+value+"""aggreg ORDER BY var DESC;""", conn)

        DF_GAPMINDER = DF_GAPMINDER.drop(['drop_col1','drop_col2'],
                                         axis=1)


    DF_GAPMINDER.loc[0:20]

    return DF_GAPMINDER.to_dict('records')

@app.callback(
    Output('datatable-gapminder', 'columns'),
    [Input('file_to_load', 'value')])
def update_col(value):
    with engine.connect() as conn, conn.begin():
        DF_GAPMINDER = pd.read_sql("""
                SELECT *
                FROM """+value+"""aggreg LIMIT 1;""", conn)

    DF_GAPMINDER = DF_GAPMINDER.drop(['drop_col1','drop_col2'],
                                     axis=1)

    return sorted(DF_GAPMINDER.columns)

@app.callback(
    Output('datatable-gapminder', 'selected_row_indices'),
    [Input('graph-gapminder', 'clickData')],
    [State('datatable-gapminder', 'selected_row_indices')])
def update_selected_row_indices(clickData, selected_row_indices):
    if clickData:
        for point in clickData['points']:
            if point['pointNumber'] in selected_row_indices:
                selected_row_indices.remove(point['pointNumber'])
            else:
                selected_row_indices.append(point['pointNumber'])
    return selected_row_indices


@app.callback(
    Output('graph-gapminder', 'figure'),
    [Input('datatable-gapminder', 'rows'),
     Input('file_to_load', 'value'),
     Input('datatable-gapminder', 'selected_row_indices'),
     ])
def update_figure(rows, value, selected_row_indices):
    if value == '1':
        dff = pd.DataFrame(rows)
        fig = plotly.tools.make_subplots(
            rows=4, cols=1,
            subplot_titles=('var1', 'var2', 'var3', 'var4'),
            shared_xaxes=True)
        marker = {'color': ['#0074D9'] * len(dff)}
        for i in (selected_row_indices or []):
            marker['color'][i] = '#FF851B'
        fig.append_trace({
            'x': dff['1'],
            'y': dff['var1'],
            'type': 'bar',
            'marker': marker
        }, 1, 1)
        fig.append_trace({
            'x': dff['1'],
            'y': dff['var2'],
            'type': 'bar',
            'marker': marker
        }, 2, 1)
        fig.append_trace({
            'x': dff['1'],
            'y': dff['var3'],
            'type': 'bar',
            'marker': marker
        }, 3, 1)
        fig.append_trace({
            'x': dff['1'],
            'y': dff['var4'],
            'type': 'bar',
            'marker': marker
        }, 4, 1)
        fig['layout']['showlegend'] = False
        fig['layout']['height'] = 800
        fig['layout']['margin'] = {
            'l': 40,
            'r': 10,
            't': 60,
            'b': 200
        }
        fig['layout']['yaxis2']['type'] = 'log'
    elif value == '2':
        dff = pd.DataFrame(rows)
        fig = plotly.tools.make_subplots(
            rows=4, cols=1,
            subplot_titles=('var1', 'var2', 'var3', 'var4'),
            shared_xaxes=True)
        marker = {'color': ['#0074D9'] * len(dff)}
        for i in (selected_row_indices or []):
            marker['color'][i] = '#FF851B'
        fig.append_trace({
            'x': dff['2'],
            'y': dff['var1'],
            'type': 'bar',
            'marker': marker
        }, 1, 1)
        fig.append_trace({
            'x': dff['2'],
            'y': dff['var2'],
            'type': 'bar',
            'marker': marker
        }, 2, 1)
        fig.append_trace({
            'x': dff['2'],
            'y': dff['var3'],
            'type': 'bar',
            'marker': marker
        }, 3, 1)
        fig.append_trace({
            'x': dff['2'],
            'y': dff['var4'],
            'type': 'bar',
            'marker': marker
        }, 4, 1)
        fig['layout']['showlegend'] = False
        fig['layout']['height'] = 800
        fig['layout']['margin'] = {
            'l': 40,
            'r': 10,
            't': 60,
            'b': 200
        }
        fig['layout']['yaxis2']['type'] = 'log'

    return fig


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

Hi,

I am facing the same challenge in my code where datatable is not working with multipage set up.

Were you able to resolve this?

1 Like

just see this, it worked for me.