Dash Table (Passing variables to another callback, download data, and additional rows)

Hi!

I have this table that is an output, so the callback function calculates the values in the cells.

I need to do 3 additional things, but struggling to do them:
1)- I want to add another row. The data list of the table looks like the following, so how to add a second row so that I can control what values should go to each row ell. Currently, I am putting value 1 in cell 1 and value 2 in cells 2 as shown in the example. But if I have two rows, how the syntax should be?

data=[
        {
    
            "SP":  "Square Footage",
             "Exam": Value1,
             "Waiting": Value2,
   

        }
  
    ] 

2- My second question: the values (Value 1 and Value 2…) shown in question 1 are calculated in the callback function that updates the table. I want to use them in other callbacks as well, how to pass them to other callbacks?

3- My final question, is how to allow the user to download the table results? No filters needed, just need a button that says ‘download’ and then export the results to an excel or text file.

Thank you very much for this awesome app python tool!

Hi @fhalawa

Here are some suggestions:

  1. The most common way to add rows or do any other data prep in the callback is to use a pandas dataframe. When the data in the df is how you want it to look in the table, then data = df.to_dict(“records”) will put it in a format needed to update the data property of the table. Output('table', 'data)

  2. To use the output of this table in another callback, you can use it as an input in that callback:
    Input(‘table’, ‘data’)

  3. There is a good example of how to export data from a table in the last topic here: https://dash.plotly.com/datatable/editable

If you still have questions, it’s easier to help if you can provide a minimal example with some sample data. For more information see: How to Get your Questions Answered on the Plotly Forum

1 Like

Thank you for your reply @AnnMarieW, I still have an issue. Here is a detailed illustration of the problem.

I have a table to be filled in by the call back. The table code is the following:

html.Div(‘Program’,style={‘padding’: 35}),
dash_table.DataTable(
id=‘tableo’,
columns=[
{“name”: “Spaces”, “id”: “SP”},
{“name”: “Exam Rooms”, “id”: “Exam”},
{“name”: “Waiting”, “id”: “Waiting”},
{“name”: “Playroom”, “id”: “Playroom”},
{“name”: “Offices”, “id”: “Offices”},
{“name”: “Reception”, “id”: “Reception”},
{“name”: “Kiosk”, “id”: “Kiosk”},
{“name”: “Screening rooms”, “id”: “Screening”},
{“name”: “Isolation rooms”, “id”: “Isolation”},
{“name”: “Clean utility”, “id”: “Clean”},
{“name”: “Soild utility”, “id”: “Soild”},
{“name”: “Consult rooms”, “id”: “Consult”},
{“name”: “Medication room”, “id”: “Medication”},
{“name”: “Utility room”, “id”: “Utility”},
{“name”: “Storage”, “id”: “Storage”},
{“name”: “Lockers”, “id”: “Lockers”},
{“name”: “Nurse station”, “id”: “Nurse”},
{“name”: “Additional Spaces”, “id”: “AS”}

    ,

],
  style_table={
    'maxHeight': '50ex',
    'overflowY': 'scroll',
    'width': '100%',
    'minWidth': '100%'},

),

In the call back, I am calculating the values of the cells and return “data”.

@app.callback(
Output(‘tableo’, ‘data’),
[Input(‘Duration’, ‘value’),
Input(‘Visits’, ‘value’),
Input(‘Uti’, ‘value’),
Input(‘Hours’, ‘value’),
Input(‘Virtual’, ‘value’),
Input(‘Operations’,‘value’),
Input(‘additional’,‘value’),

  ])

def update_table(Duration,Visits,Uti,Hours,Virtual,Operations, additional):

#Number of exam rooms and booths
if Visits <= 2048:
   NumberExams = 2
   SFExam = 120*NumberExams
   
if Visits> 2048:
    if 'Telehealth Booths' in Operations:
            NumberExams= 2 +  round((Visits/240*(1-(Virtual/100))*Duration)/(Hours*60*Uti/100))
            SFExam= 120*(2+NumberExams)
            NumberBooths= round((Visits/240*(Virtual/100)*Duration)/(Hours*60*Uti/100))
            SFBooths=NumberBooths*40
    if 'Telehealth Booths' not in  Operations:
        
             NumberExams= round((Visits/240*Duration)/(Hours*60*Uti/100))
             SFExam= 120*(2+NumberExams)
             NumberBooths= 0
    
#Waiting area
if NumberExams<4:
    WaitSF= 120 
else: 
    WaitSF=120 +((NumberExams-4)/4)*600


data=[
        {
    
            "SP":  "Square Footage",
            "Waiting": WaitSF,
            "Exam": SFExam,
            
   

        }
  
    ] 

return data

What I am trying to do is
1- add another row to that table so that in the call back I can return the value for row 1 and the value for row 2. I was not successful in doing that…
2- After the data is returned by the callback, I want to use it in another call back to visualize the data. I am not being able to read the data since it is something that is returned by a previous call back, so can I return in and then use it as an input?

I am sorry, I forgot one point @AnnMarieW .

So I have this code after the table to add a download button

html.Div(’’,style={‘padding’: 35}),
html.A(
‘Download Data’,
id=‘download-link’,
download=“rawdata.csv”,
href="",
target="_blank"
),

How can I have a call back to save the table as a csv so that the user can download the final results?

Would you mind writing the syntax for that for me? The examples I saw in this forum as based on a filter and did not work in my case. Thank you again

Hi @fhalawa

You can add [State(‘tableo’, ‘data’)] to the callback, then append the new data.

You can combine the callback for the visualization, or have a separate callback where the table data is an input.

1 Like
dash_table.DataTable(
id=‘tableo’,
columns=[......
export_format='csv',
export_headers='display'

No need to do a callback. It’s a feature that can be added to the the dash datatable

This is great @AnnMarieW ! Much appreciated.

The export feature works pretty well, all I am missing now is a the following.

In the first callback, I am generating a list called Listo =[Value1,Value2,…]. I want to pass Listo to another call back, so the first callback calculates Listo and also calculates data for the table, and returns two values:

return data
return Listo

Now, I want Listo be read by the next callback to visualize some values in it, how to do that? Should I read it as an input?
input(‘Listo’,‘value’) or there is another syntax to pass a list in callback?

I am new to dash, so appreciate this help!

Try using dcc.Store https://dash.plotly.com/dash-core-components/store

Thank you AnnMarieW
I have an output as table and as figure. Can I have the call back with 2 outputs and returning two values as shown in this example? it is giving me an error. Not sure how should I do that correctly? @AnnMarieW

IncorrectTypeException: The input argument NumRooms.figure must be a list or tuple of

dash.dependencies.Inputs.

@app.callback(
Output(‘tableo’, ‘data’),
Output(‘NumRooms’, ‘figure’),
[Input(‘Duration’, ‘value’),
Input(‘Visits’, ‘value’),
Input(‘Uti’, ‘value’),
Input(‘Hours’, ‘value’),
Input(‘Virtual’, ‘value’),
Input(‘Operations’,‘value’),
Input(‘additional’,‘value’),

  ])

def update_table(Duration,Visits,Uti,Hours,Virtual,Operations, additional):

#Bariatric Configurations
if 'BariatricC' in Operations:
       ExamRoomsArea=150
if 'BariatricC' not in Operations:
       ExamRoomsArea=120    
       
#ExamRooms       
if Visits <= 2048:
   NumberExams = 2
   SFExam = ExamRoomsArea*NumberExams
if Visits> 2048:
    if 'Telehealth Booths' in Operations:
            NumberExams= 2 +  round((Visits/240*(1-(Virtual/100))*Duration)/(Hours*60*Uti/100))
            SFExam= ExamRoomsArea*(2+NumberExams)
            NumberBooths= round((Visits/240*(Virtual/100)*Duration)/(Hours*60*Uti/100))
            SFBooths=NumberBooths*40
    if 'Telehealth Booths' not in  Operations:            
             NumberExams= round((Visits/240*Duration)/(Hours*60*Uti/100))
             SFExam= ExamRoomsArea*(2+NumberExams)
             NumberBooths= 0

#Waiting area
if NumberExams<4:
    WaitSF= 120 
else: 
    WaitSF=120 +((NumberExams-4)/4)*60
#Playroom
if 'Playroom' in Operations:
     NumberPlayRooms=1
     SFPlayRooms=120
if 'Playroom' not in Operations:
     NumberPlayRooms=0
     SFPlayRooms=0   

#Kiosk Check in
if NumberExams >= 16:
     NumberKiosks=1
     SFKiosks=30
     
#PatientEducation
Numbereducation =1
SFeducation=120




     

data=[
        {
    
            "SP":  "Square Footage",
            "Waiting": WaitSF,
            "Exam": SFExam,
            
   

        }
  
    ] 

XAxis1= round((Visits*(1-(Virtual/100))*Duration)/(Hours*60*Uti/100))
XAxis2= round((Visits*(Virtual/100)*Duration)/(Hours*60*Uti/100))

XAxis1= round((Visits*Duration)/(Hours*60*Uti/100))
XAxis2= 0


figure={
        'data': [
            {'x': ['KeyRooms', 'Virtual Rooms'], 'y': [XAxis1, XAxis2], 'type': 'bar', 'name': 'Key Rooms'},
        ],
        'layout': {
            'paper_bgcolor': colors['background'],
            'font': {
                'color': colors['text2']
            }
        }
    }

return data
return figure

Yes, you can have multiple outputs. You just need add [ ]

@app.callback(
    [Output(‘tableo’, ‘data’),  Output(‘NumRooms’, ‘figure’)],

And then the return should be like this:

return data, figure
1 Like

Thank you! That solves the problem!

1 Like

@AnnMarieW, just one little thing please-so if I want to return 3 outputs (table, figure, and another figure). Here is the problem, the second figure over-writes the first one in the call back function since both have the same name as “figure”. How to let the code understand that I have two separate figures?
Here is the code:

XAxis1= round((Visits*(1-(Virtual/100))*Duration)/(Hours*60*Uti/100))
XAxis2= round((Visits*(Virtual/100)*Duration)/(Hours*60*Uti/100))

XAxis1= round((Visits*Duration)/(Hours*60*Uti/100))
XAxis2= 0


figure={
        'data': [
            {'x': ['KeyRooms', 'Virtual Rooms'], 'y': [XAxis1, XAxis2], 'type': 'bar', 'name': 'Key Rooms'},
        ],
        'layout': {
            'paper_bgcolor': colors['background'],
            'font': {
                'color': colors['text2']
            }
        }
    }

X1= (round((Visits*(1-(Virtual/100))*Duration)/(Hours*60*Uti/100)))*400
X2= (round((Visits*(Virtual/100)*Duration)/(Hours*60*Uti/100)))*40
SF1= X1+X2
    
z1= (round((Visits*(1-(Virtual/100))*Duration)/(Hours*60*Uti/100)))*650
z2= (round((Visits*(Virtual/100)*Duration)/(Hours*60*Uti/100)))*40
SF2= z1+z2
            

X1= (round((Visits*Duration)/(Hours*60*Uti/100)))*400
X2= 0
SF1=X1 
SF2=(round((Visits*Duration)/(Hours*60*Uti/100)))*650

figure={
        'data': [
            {'x': ['DGSF Min', 'DGSF Max'], 'y': [SF1, SF2], 'type': 'bar', 'name': 'DGSF'},
        ],
        'layout': {
            'paper_bgcolor': colors['background'],
            'font': {
                'color': colors['text2']
            }
        }
    }
return data,figure,figure

Just give the figures different names, like figure1 and figure2 (or something more descriptive) :slight_smile:

It can be a little confusing because in the Output, it looks like they both return ‘figure’. But that is the type of parameter you are updating. You can use any variable name for ‘figure’ you like in the callback.

The order of the variable names in the return statement just needs to match the order of the Outputs listed in the @app.callback(…

Tried that. I think DASH only reads it if it is called figure. It is not reading the one that I am naming as figure 2.

@app.callback(
[Output(‘tableo’, ‘data’),
Output(‘NumRooms’, ‘figure’),
Output(‘SF’, ‘figure2’),
],
[Input(‘Duration’, ‘value’),
Input(‘Visits’, ‘value’),
Input(‘Uti’, ‘value’),
Input(‘Hours’, ‘value’),
Input(‘Virtual’, ‘value’),
Input(‘Operations’,‘value’),
Input(‘additional’,‘value’),

  ])

Then in the call back function, the following:

XAxis1= round((Visits*(1-(Virtual/100))*Duration)/(Hours*60*Uti/100))
XAxis2= round((Visits*(Virtual/100)*Duration)/(Hours*60*Uti/100))

XAxis1= round((Visits*Duration)/(Hours*60*Uti/100))
XAxis2= 0


figure={
        'data': [
            {'x': ['KeyRooms', 'Virtual Rooms'], 'y': [XAxis1, XAxis2], 'type': 'bar', 'name': 'Key Rooms'},
        ],
        'layout': {
            'paper_bgcolor': colors['background'],
            'font': {
                'color': colors['text2']
            }
        }
    }

X1= (round((Visits*(1-(Virtual/100))*Duration)/(Hours*60*Uti/100)))*400
X2= (round((Visits*(Virtual/100)*Duration)/(Hours*60*Uti/100)))*40
SF1= X1+X2
    
z1= (round((Visits*(1-(Virtual/100))*Duration)/(Hours*60*Uti/100)))*650
z2= (round((Visits*(Virtual/100)*Duration)/(Hours*60*Uti/100)))*40
SF2= z1+z2
            

X1= (round((Visits*Duration)/(Hours*60*Uti/100)))*400
X2= 0
SF1=X1 
SF2=(round((Visits*Duration)/(Hours*60*Uti/100)))*650

figure2={
        'data': [
            {'x': ['DGSF Min', 'DGSF Max'], 'y': [SF1, SF2], 'type': 'bar', 'name': 'DGSF'},
        ],
        'layout': {
            'paper_bgcolor': colors['background'],
            'font': {
                'color': colors['text2']
            }
        }
    }
return data,figure,figure2

I was clarifying my answer when you did your last post, so please see that updated post for the explanation…

Try this: Output(‘SF’, ‘figure’),

1 Like

Many thanks! @AnnMarieW

Glad it’s working for you - Looks like you are making good progress!

Thanks @AnnMarieW for your great help!
It is really fun working on dash but I am really new… learning bit by bit.

My final question here to finalize this app: I want my table and 2 figures to be shown on the right side of the layout. Whereas, the input variables on the left side of the screen… I am REALLY struggling with that. Here is an example of my code, and I would appreciate it if you are able to split them for me into a right and left sides (this will help me learn it better)…

First the title:Interactive Planning Dashboard should stay in the middle

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

app = dash.Dash(name, external_stylesheets=external_stylesheets)

colors = {
‘background’: ‘#ffffff’,
‘text’: ‘#7FDBFF’,
‘text2’:’#646464
}

app.layout = html.Div(style={‘backgroundColor’: colors[‘background’]}, children=[
html.H1(
children=‘Interactive Planning Dashboard’,
style={
‘textAlign’: ‘center’,
‘color’: colors[‘text2’] }),

Code part where I have the input variables and should be the left side:

html.Div('Expected Number of Patients',style={'padding': 35}),
daq.Slider(
id='Visits',
min=0,
max=50000,
value=2000,
handleLabel={"showCurrentValue": True,"label": "VALUE"},
step=1),       


html.Div('Virtual Visits %',style={'padding': 35}),
daq.Slider(
id='Virtual',
min=0,
max=100,
value=20,
handleLabel={"showCurrentValue": True,"label": "VALUE"},
step=1),  

… I have many inputs, but I am just showing an example

Part where I have the outputs (which should go to the right side):

html.Div(‘Program’,style={‘padding’: 35}),
dash_table.DataTable(
id=‘tableo’,
columns=[
{“name”: “Spaces”, “id”: “SP”},
{“name”: “Exam Rooms”, “id”: “Exam”},
{“name”: “Waiting”, “id”: “Waiting”},
{“name”: “Playroom”, “id”: “Playroom”},
{“name”: “Offices”, “id”: “Offices”},
{“name”: “Reception”, “id”: “Reception”},
{“name”: “Kiosk”, “id”: “Kiosk”},
{“name”: “Screening rooms”, “id”: “Screening”},
{“name”: “Isolation rooms”, “id”: “Isolation”},
{“name”: “Clean utility”, “id”: “Clean”},
{“name”: “Soild utility”, “id”: “Soild”},
{“name”: “Consult rooms”, “id”: “Consult”},
{“name”: “Medication room”, “id”: “Medication”},
{“name”: “Utility room”, “id”: “Utility”},
{“name”: “Storage”, “id”: “Storage”},
{“name”: “Lockers”, “id”: “Lockers”},
{“name”: “Nurse station”, “id”: “Nurse”},
{“name”: “Bariatric rooms”, “id”: “BR”},
{“name”: “Additional Spaces”, “id”: “AS”}

    ,

],
      export_format='csv',
  export_headers='display',
  style_table={
    'maxHeight': '50ex',
    'overflowY': 'scroll',
    'width': '100%',
    'minWidth': '100%'},

),

dcc.Store(id=‘memory-output’),

html.Div(’’,style={‘padding’: 35}),

html.Div(children=’’’
Number of Clinics’’’, style={
‘textAlign’: ‘center’,
‘color’: colors[‘text2’]
}),
# start of graph
dcc.Graph(id=‘NumRooms’, figure=“figure1”),
#end graph
html.Div(children=’’’
Total Space Needed
‘’’, style={
‘textAlign’: ‘center’,
‘color’: colors[‘text2’]
}),
# start of graph
dcc.Graph(id=‘SF’, figure=“figure2”)
#end graph

])

Thank you so much!!

I’m certainly no expert on web design and css etc. I struggle with this in my apps too.

However, I’ve recently started using Bootstrap, and it does make things a little easier.

Here are some resources I’ve found helpful:

Dash bootstrap components:
https://dash-bootstrap-components.opensource.faculty.ai/

Video on using bootstrap in Dash:

Bootstrap cheatsheet:

I hope this helps.

1 Like