Need help with Callback Statement for Plotly Table

Hey everyone. I’m new to using plotly dash and creating web apps and need help with my callback function. My team created a recommendation model that takes a job title and number as input and outputs a list of recommendations, the amount of recommendations are based on the number inputted to the function. This model is in a .py file titled recco.

For the app, I’m trying to create a plotly table that updates based on the job title and number inputted. There will only be one column which will consist of the course recommendations. The input boxes are showing and I can type numbers and text in them but a table isn’t showing and changing which is telling me my callback is incorrect. Here is my code:

‘’'python

from dash import Dash, dcc, html, Input, Output
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
import pandas as pd
import recco

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

server = app.server
def fig1(course_list):
    data = {'Course_Recommendations' : course_list}
    df = pd.DataFrame(data)

    fig2 = go.Figure(data = [go.Table(
        header = dict(
            values=["<b>Course Recommendations</b>"],
            align='center', font=dict(color='black', size=12),height=30
    ),
        cells=dict(
            values=[df['Course_Recommendations']],
            align='center', font=dict(color='white', size=11), height=30))])

    return fig2

input_types = ("text", "number",)

app.layout = html.Div(
    [
     html.H1("Course Recommender"),
     html.P('Please enter a job title and the number of recommendations you would like'),
     html.Div([
     dcc.Input(
     id = 'my_{}'.format(x),
     type = x,
     placeholder = "insert {}".format(x),
     debounce = True,
     size = 25
     
     ) for x in input_types]),
 
 html.Br(),
 
 dcc.Graph(id = 'mytable')
     
])

@app.callback(
    Output(component_id='mytable', component_property='figure'),
    [Input(component_id='my_{}'.format(x), component_property='value')
     for x in input_types
     ],)

def update_output(value):
    get1 = recco.recommender(value)
    return fig1(get1)

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

‘’’
All help is appreciated. Thank you.

Hi @asiam94,

your code should actually throw some errors, try correcting them one after another by setting debug=True

There are errors in code.

  1. update_output takes one value, actually Input(s) in callback are two.
  2. are we mixing up fig1?? def fig1…fig1=go.Figure(…and return fig1 ??

Do provide sample data (5 rows) to be able to help you more.

Cheers.

Hi. In the figure function, it should be fig2 return fig2. I’ve corrected it. Do I add another value to the update_output function since there are two inputs?

Here’s results from our recommender where the inputs are Project Manager and 5:
‘’’ python

Title
Project Management: Getting Started and Beyond                
Pass the Exam: CompTIA Project+ PK0-004                        
Successful Project Manager                                    
Beginning Project Management: Project Management Level One     
Project Management Fundamentals: Crash Course for Beginners

‘’'#

  1. update_output function which caters to callback, need to take as many values as are Inputs specified.
    You may take those values and not utilise is OK. But the question is why to add to Input, if you do not wish to utilse?.
  2. Based on your response, I understand , You need to process Text input and Number Input for recco function to give output. For the purpose, I have assumed that output is simply text output, hence, Textarea should do the job. Here is a modified code that does the job.
    Check for callback by inputting ‘Position1’ in Text Box and later by inputting Number 1 in Number Box.
    Here is complete Code:

from dash import Dash, dcc, html, Input, Output, dash_table
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
import pandas as pd
#import recco

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

server = app.server


input_types = ("text", "number",)

app.layout = html.Div(
    [
     html.H1("Course Recommender"),
     html.P('Please enter a job title and the number of recommendations you would like'),
     html.Div([
     dcc.Input(
     id = 'my_{}'.format(x),
     type = x,
     placeholder = "insert {}".format(x),
     debounce = True,
     size = 25
     
     ) for x in input_types]),
 
 html.Br(),
 
 dcc.Textarea(id = 'mytable', value='Initial Value', style={'height':300})
     
])

@app.callback(
    Output(component_id='mytable', component_property='value'),
    [Input(component_id='my_{}'.format(x), component_property='value')
     for x in input_types
     ],)

def update_output(value, val2):
    #recco.recommender(value)
    if value=='Position1':
        reco="Title Project Management: Getting Started and Beyond Pass the Exam: Project ABC Package : 001" 
    else:
        reco='To be specified....'


if val2==1 :
        reco = reco + '\n' + 'Experience :' + str(val2) + ' Years'
    else:
        reco = reco + '\n' + 'Experience: Not Specified'          
    return reco

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

You may notice that I have bypassed ‘recco’ as I have not installed the same in my machine.
Hope this helps. Have a nice day.
Cheers !
Mukesh Makwana

Good Day,
If you want to continue using Table, here is the code for that.

from dash import Dash, dcc, html, Input, Output, dash_table
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
import pandas as pd
#import recco

app = Dash(name, external_stylesheets=[dbc.themes.ZEPHYR])

server = app.server
course_list=[‘physics’, ‘chemistry’]
def fig1(course_list):
dfdata = {‘Course_Recommendations’ : course_list}
df = pd.DataFrame(dfdata)

fig= go.Figure([go.Table(
    header = dict(
        values=["<b>Course Recommendations</b>"],
        align='center', font=dict(color='black', size=12),height=30
),
    cells=dict(
        values=[df['Course_Recommendations']],
        align='center', font=dict(color='blue', size=11), height=30))])

return fig

fig = fig1(course_list)
input_types = (“text”, “number”,)

app.layout = html.Div(
[
html.H1(“Course Recommender”),
html.P(‘Please enter a job title and the number of recommendations you would like’),
html.Div([
dcc.Input(
id = ‘my_{}’.format(x),
type = x,
placeholder = “insert {}”.format(x),
debounce = True,
size = 25

 ) for x in input_types]),

html.Br(),
dcc.Graph(id = ‘mytable’, figure=fig, style={‘height’:300})
#dcc.Textarea(id = ‘mytable’, value=‘Initial Value’, style={‘height’:300})

])

@app.callback(
Output(component_id=‘mytable’, component_property=‘figure’),
[Input(component_id=‘my_{}’.format(x), component_property=‘value’)
for x in input_types
],)

def update_output(value, val2):
#recco.recommender(value)
if value==‘Position1’:
reco=“Title Project Management: Getting Started and Beyond Pass the Exam: Project ABC Package : 001”
else:
reco=‘To be specified…’

if val2==1 :
    reco = reco + '\n' + 'Experience :' + str(val2) + ' Years'
else:
    reco = reco + '\n' + 'Experience: Not Specified' 
fig.data[0]['cells']['values']=[[f'physics :{reco}', f'Chemistry:{reco}']]         
return fig

if name ==‘main’:
app.run_server(debug=False)

In absence of course_list list to populate dataframe, have defined simple list with two subjects.
Again you can use by input on Text: Position1 and Number : 1 to reflect the changes (or callback in action).
One bug was there…Need to define course_list outside the function def (as you have defined function to take course_list as input).
You may notice that we are not updating entire fig, but only values using fig.data[0][‘cells’][‘values’]. If you have upgraded to latest plotly, you have option of using patch() as well…To only send values…

Hope this helps.
Cheers
Mukesh Makwana

Hey everyone! I spent some time last night trying to figure it out and took earlier suggestions to make sure my update_output function included two values instead of one and I made sure that debug = True to see where the issue was coming from.

My issue was mainly stemming from my recco file. I had to create a if/else statement to set default values for the app to read before someone inputted anything to the app. The app trying to read the recco file without any inputs was causing it to find errors. Thank you everyone for helping me out!