Add columns to dash.table

I’m trying create a datatable with two columns and using a dropdown that will insert another column based on what the user select.

i dont will post all code because are large, but these pieces are where my error are

i’m mostly based on this topic:

link to post of base idea

import pandas as pd
import dash_mantine_components as dmc
import dash_core_components as dcc
import dash_bootstrap_components as dbc
from dash import html
from dash import Dash, Input, Output, dash_table, State
from dash.exceptions import PreventUpdate
import plotly.express as px
import json
from dash_bootstrap_templates import load_figure_template
import datetime
import base64



dff = {'Nome':['Random1','Random2','Random3','Random4'],'tipo':['Random11','Random22','Random33','Random44'],'a': ['1','2','3','4',], 'b':['b1','b2','b3','b4'], 'c':['c1','c2','c3','c4'], 'd':['d1','d2','d3','d3'],'Indicator Name':['a','b','c','d']}
dff = pd.DataFrame(dff)

db_filtered = pd.DataFrame(dff)





app = Dash(__name__, external_stylesheets= [dbc.themes.DARKLY, dbc_css])



#---------------------------------------------------------------------------------------------------------------------------------------#

#  1. FUNCTIONS CONSTRUCTION

        # 1.1 - table_creation
            

#---------------------------------------------------------------------------------------------------------------------------------------#

#------------------------------------------------------- 1.1 ---------------------------------------------------------------------------#

def table_creation(db_filtered):
                    
                    db_as_list = db_filtered.columns.to_list()
                    #print(db_as_list)
                    dash_table.DataTable(
                        data = [{


                        }],
                        columns = [{"name": i,
                                    "id": i 
                                    } for i in db_as_list], #<------------ setting columns of datatable
                        editable=False, #<------------ setting preferences if is or not editable
                        filter_action="native", #<------------ Filters in columns
                        sort_action="native", #<------------ 
                        sort_mode="multi", #<------------ 
                        column_selectable="single", #<------------ Selectable only one column
                        row_selectable=False, #<------------  dont let select just a row
                        selected_columns=[], #<------------ no column is selected previously
                        selected_rows=[],  #<------------ no row is selected previously
                        page_action="native", 
                        page_current= 0, #<------------ First page will be show
                        page_size= 25) #<------------  n of funds to be showed 
                     

#---------------------------------------------------------------------------------------------------------------------------------------#


#---------------------------------------------------------------------------------------------------------------------------------------#




app.layout = html.Div([


#-------------------------------------------------------  ---------------------------------------------------------------------------#
        
        dbc.Card(
            dbc.CardBody([
                
#                ------------------------------------------------------------------------------------------------------------------#

                dbc.Row([
                    dbc.Col([
                        html.Div([

                            dbc.Button("b1", color="warning", id='todos_button', n_clicks_timestamp='0'),
                            dbc.Button("b2", color="light",id='multimercado_button', n_clicks_timestamp='0' ),

                        dcc.Dropdown(dff['Indicator Name'].unique(), id = 'dropdown'),
                
                    ])
                ]),
            ]),

                

#---------------------------------------------------------------------------------------------------------------------------------#

                dbc.Row([
                    dbc.Col([
                        html.Div([
                            dash_table.DataTable(table_creation(db_filtered), id = 'tabela-dash',#calling the function with dff, but only will be displayed if the user use the button
                            
                        )], className="m-4 dbc")
                    ])
                ])
            ])
        )
])
        


#---------------------------------------------------------------------------------------------------------------------------------------#

        

#---------------------------------------------------------------------------------------------------------------------------------------#



#-------------------------------------------------------- 3.1 --------------------------------------------------------------------------#


@app.callback(Output('tabela-dash', 'data'),
              Input('multimercado_button','n_clicks_timestamp'),
              Input('todos_button','n_clicks_timestamp')    
            )




def display(multimercado_button, todos_button ):

    if int(multimercado_button) > int(todos_button): #Multimercado button

        value = 'Macro Alta Vol'

        db_filtered = pd.DataFrame(dff[dff['tipo'] == value])
        db_filtered = db_filtered.loc[:,['Nome','tipo']]
        print(db_filtered)
        db_filtered = db_filtered.to_dict('Records')

        return db_filtered #<------------ Extracting data as dict, easy way to do


    
    elif int(todos_button) > int(multimercado_button): 
        db_filtered = pd.DataFrame(dff)
        db_filtered = db_filtered.loc[:,['Nome','tipo']]
        
        
        print(db_filtered)
        db_filtered = db_filtered.to_dict('Records')


        
        return db_filtered#<------------ Extracting data as dict, easy way to do


    else:
        
        db_filtered = pd.DataFrame(dff)
        db_filtered = db_filtered.loc[:,['Nome','tipo']]
        
        db_filtered = db_filtered.to_dict('Records')

        
        return db_filtered #<------------ Extracting data as dict, easy way to do


#-------------------------------------------------------- 3.2 --------------------------------------------------------------------------#

@app.callback(
    Output('tabela-dash', 'columns'),
    [Input('dropdown', 'value')],
    [State('tabela-dash', 'columns')]
)


def update_table(value, columns):

    if value is None:
        print('test 1: Value is None')
    else:
        print('test 1: Value is not None')
        raise PreventUpdate

    if columns is None:
        print('test 2: Columns is None')
    else:
        print('test 2: Columns in not None')


app.run_server(debug=True, use_reloader=False)

I dont know what happend that my columns just dont exist, my variable ‘columns’ only return “None”, but my variable ‘value’ are going ok.

I already tried some different ways, but neither of them came close.

Hello @theeconomist,

I cant really look at where you are doing, but is your db_filtered a list, if so, dont put it in the [] with it should be:

columns = [{"id": i, "name": i} for i in db_filtered]

I edited my original posting, now i’ve a reproduceble example, sorry for post out of standart.

How you can see, in my example the dash has a table with two columns and my dataframe has more. What i want with this callback is that new columns be created based on what the user select with the dropdown.

The value inside the dropdown will represent a column, but in my if’s test my columns always are returned as None.

Is much similar with the example by Marc Andre, but for some reason i coudn’t adapt for my purpose.

Try formatting your code this way:

@app.callback(
    Output('tabela-dash', 'columns'),
    Input('dropdown', 'value'),
    State('tabela-dash', 'columns')
)

And then make sure you return your columns.

Also, check out here:

Don’t worked, my function still dont returning columns parameter, only value.

This should probably be this:

table_creation(db_filtered),#calling the function with dff, but only will be displayed if the user use the button

And the function should return a table:

def table_creation(db_filtered):
                    
                    db_as_list = db_filtered.columns.to_list()
                    #print(db_as_list)
                    table = dash_table.DataTable(
                        data = [{


                        }],
                        columns = [{"name": i,
                                    "id": i 
                                    } for i in db_as_list], #<------------ setting columns of datatable
                        editable=False, #<------------ setting preferences if is or not editable
                        filter_action="native", #<------------ Filters in columns
                        sort_action="native", #<------------ 
                        sort_mode="multi", #<------------ 
                        column_selectable="single", #<------------ Selectable only one column
                        row_selectable=False, #<------------  dont let select just a row
                        selected_columns=[], #<------------ no column is selected previously
                        selected_rows=[],  #<------------ no row is selected previously
                        page_action="native", 
                        page_current= 0, #<------------ First page will be show
                        page_size= 25,
                        id = 'tabela-dash')
     return table

Give this a try.

It still dont working, i just dont know what different to do.

It’s really hard to say without seeing more of what you’ve got going on.

I got this to work… as maybe designed?

You needed to move the raise PreventUpdate to after all the if statements:

import pandas as pd
import dash_mantine_components as dmc
import dash_core_components as dcc
import dash_bootstrap_components as dbc
from dash import html
from dash import Dash, Input, Output, dash_table, State
from dash.exceptions import PreventUpdate
import plotly.express as px
import json
from dash_bootstrap_templates import load_figure_template
import datetime
import base64

dff = {'Nome': ['Random1', 'Random2', 'Random3', 'Random4'], 'tipo': ['Random11', 'Random22', 'Random33', 'Random44'],
       'a': ['1', '2', '3', '4', ], 'b': ['b1', 'b2', 'b3', 'b4'], 'c': ['c1', 'c2', 'c3', 'c4'],
       'd': ['d1', 'd2', 'd3', 'd3'], 'Indicator Name': ['a', 'b', 'c', 'd']}
dff = pd.DataFrame(dff)

db_filtered = pd.DataFrame(dff)

app = Dash(__name__, external_stylesheets=[dbc.themes.DARKLY])


# ---------------------------------------------------------------------------------------------------------------------------------------#

#  1. FUNCTIONS CONSTRUCTION

# 1.1 - table_creation


# ---------------------------------------------------------------------------------------------------------------------------------------#

# ------------------------------------------------------- 1.1 ---------------------------------------------------------------------------#

def table_creation(db_filtered):
    db_as_list = db_filtered.columns.to_list()
    # print(db_as_list)
    table = dash_table.DataTable(
        data=[{

        }],
        columns=[{"name": i,
                  "id": i
                  } for i in db_as_list],  # <------------ setting columns of datatable
        editable=False,  # <------------ setting preferences if is or not editable
        filter_action="native",  # <------------ Filters in columns
        sort_action="native",  # <------------
        sort_mode="multi",  # <------------
        column_selectable="single",  # <------------ Selectable only one column
        row_selectable=False,  # <------------  dont let select just a row
        selected_columns=[],  # <------------ no column is selected previously
        selected_rows=[],  # <------------ no row is selected previously
        page_action="native",
        page_current=0,  # <------------ First page will be show
        page_size=25, # <------------  n of funds to be showed
        id='tabela-dash'
    )
    return table


# ---------------------------------------------------------------------------------------------------------------------------------------#


# ---------------------------------------------------------------------------------------------------------------------------------------#


app.layout = html.Div([

    # -------------------------------------------------------  ---------------------------------------------------------------------------#

    dbc.Card(
        dbc.CardBody([

            #                ------------------------------------------------------------------------------------------------------------------#

            dbc.Row([
                dbc.Col([
                    html.Div([

                        dbc.Button("b1", color="warning", id='todos_button', n_clicks_timestamp='0'),
                        dbc.Button("b2", color="light", id='multimercado_button', n_clicks_timestamp='0'),

                        dcc.Dropdown(dff['Indicator Name'].unique(), id='dropdown'),

                    ])
                ]),
            ]),

            # ---------------------------------------------------------------------------------------------------------------------------------#

            dbc.Row([
                dbc.Col([
                    html.Div([
                        table_creation(db_filtered)], className="m-4 dbc")
                ])
            ])
        ])
    )
])


# ---------------------------------------------------------------------------------------------------------------------------------------#


# ---------------------------------------------------------------------------------------------------------------------------------------#


# -------------------------------------------------------- 3.1 --------------------------------------------------------------------------#


@app.callback(Output('tabela-dash', 'data'),
              Input('multimercado_button', 'n_clicks_timestamp'),
              Input('todos_button', 'n_clicks_timestamp')
              )
def display(multimercado_button, todos_button):
    if int(multimercado_button) > int(todos_button):  # Multimercado button

        value = 'Macro Alta Vol'

        db_filtered = pd.DataFrame(dff[dff['tipo'] == value])
        db_filtered = db_filtered.loc[:, ['Nome', 'tipo']]
        print(db_filtered)
        db_filtered = db_filtered.to_dict('Records')

        return db_filtered  # <------------ Extracting data as dict, easy way to do



    elif int(todos_button) > int(multimercado_button):
        db_filtered = pd.DataFrame(dff)
        db_filtered = db_filtered.loc[:, ['Nome', 'tipo']]

        print(db_filtered)
        db_filtered = db_filtered.to_dict('Records')

        return db_filtered  # <------------ Extracting data as dict, easy way to do


    else:

        db_filtered = pd.DataFrame(dff)
        db_filtered = db_filtered.loc[:, ['Nome', 'tipo']]

        db_filtered = db_filtered.to_dict('Records')

        return db_filtered  # <------------ Extracting data as dict, easy way to do


# -------------------------------------------------------- 3.2 --------------------------------------------------------------------------#

@app.callback(
    Output('tabela-dash', 'columns'),
    [Input('dropdown', 'value')],
    [State('tabela-dash', 'columns')]
)
def update_table(value, columns):
    if value is None:
        print('test 1: Value is None')
    else:
        print('test 1: Value is not None')


    if columns is None:
        print('test 2: Columns is None')
    else:
        print('test 2: Columns in not None')

    raise PreventUpdate



app.run_server(debug=True, use_reloader=False)