Search code examples
pythondashboardplotly-dashplotly-python

plotly dash adding an image to dcc.Tabs that updates based on the user inputs


I am trying to create an interactive dashboard for survey responses where the user input the survey question and a the title of the topics and a generated wordcloud from the responses are updated in every tab (I already generated the topics an the wordcloud as an img). I tried

this is my layout code where I am having 7 tabs for my generated topics/wordcloud.

 dbc.Col([dcc.Tabs(id= "topic_tabs", value= "topic-1", children=[
                dcc.Tab(label= "Topic 1", value= "topic-1"),
                dcc.Tab(label= "Topic 2", value= "topic-2"),
                dcc.Tab(label= "Topic 3", value= "topic-3"),
                dcc.Tab(label= "Topic 4", value= "topic-4"),
                dcc.Tab(label= "Topic 5", value= "topic-5"),
                dcc.Tab(label= "Topic 6", value= "topic-6"),
                dcc.Tab(label= "Topic 7", value= "topic-7"),
                ]), html.Div(id= "topic_title"),
                     html.Div(id= "wordcloud")
                     ], width= {"size": 6, "order": 2}),
            ]),

Here is my code for the callback

@app.callback(
[Output(component_id= "topic_title", component_property= "children")],
[Input(component_id='survey', component_property='value'),
 Input(component_id= "question", component_property= "value"),
 Input(component_id="topic_titles_memory", component_property= "data"),
 Input(component_id="topic_tabs", component_property="value")])

def word_cloud_tabs(survey, question, topics, tab):
if survey =="COVID":
    path= *mypath* + str(question)
    
else:
    path= *mypath* + str(question)
if tab =="topic-1": 
    return html.Div([
        html.H3(topics[0], style= {"background-image": path+ "topic_1.png"})]) 
elif tab =="topic-2":
    return html.Div([
        html.H3(topics[1]), html.Img(path+ "topic_2.png")])
elif tab =="topic-3":
    return html.Div([
        html.H3(topics[2])]) , html.Div([html.Img(path+ "topic_3.png")])
elif tab =="topic-4":
    return html.Div([
        html.H3(topics[3])]), html.Img(path+ "topic_4.png")
elif tab =="topic-5":
    return html.Div([
        html.H3(topics[4])]), #html.Img(path+ "topic_5.png")
elif tab=="topic-6":
    return html.Div([
        html.H3(topics[5])]), #html.Img(path+ "topic_6.png")
elif (tab== "topic-7") & (len(topics)==7):
    return html.Div([
        html.H3(topics[6])]), #html.Img(path+ "topic_7.png") 
else:
    return {"display": None}

Above I am showing the different trials I have done, I have started for topi-1 as an example by returning 1 html.Div([html.H3(title, with the wordcloud as the background)]) and got an error

  The callback ..topic_title.children.. is a multi-output.
Expected the output type to be a list or tuple but got

The second trial for topic-2 as an example, where I attempted to return 1 html.Div([with the html.H3(title), html.Img(wordcloud)]) and still got the same error as above

The third attempt for topic-3 as an example, I created two seperate html.Div() one for the title, the other for the wordcloud and got the same error.

My latest attempt for topic-4 as an exmaple I returned the html.Div(html.H3) for the title and directly returned html.Img() and got an error about img. can't be used as a tag.

What I am aiming to be able to give the user to scroll through multiple wordclouds with their titles that are updated with the user inputs. I would really appreciate the support here.


Solution

  • You need to encase your return object in a list as the "children" property of the div expects a list.

    if tab == tabname:
        return [html.Div([
            html.H3(topics[number])]), html.Img(path+ "topic_number.png")]