How to solve Callback error when updating figure graph

I’m working on making an entity name recognition application using BERT Transformer where the input and visualization process is done using Plotly Dash. I am very confused what is wrong with my code. There are two problems that i experienced. At first, i thought the code that i made had worked because it could display the results on the bar chart when i input a text and click submit, but there is an error message “Callback error updating.figure” and secondly i can’t show result in pie chart. I think it’s just a minor error, but I still can’t find a way to solve this.
I would find it helpful and if someone could help me with this problem.


And my code for Layout is here:


    # Define app
    app = JupyterDash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
    server = app.server
    app.config['suppress_callback_exceptions']= True
    colors = {"background": "#2D2D2D", "background_div": "white", 'text': 'white'}
    app.layout = html.Div(style={'backgroundColor': colors['background']}, 
    children=[
              html.Div([
                  html.H2('Analyzing NER Indonesian Language (BERT Transformer)', 
                  style={
                  'paddingTop': '30px',
                  'marginBottom': '30px',
                  'textAlign': 'center',
                  'color': colors['text']
                  }),
              ]),
              html.Div(
                  dcc.Textarea(
                      id='text-input',
                      placeholder='Enter your text to be analyzed',
                      className='textarea',
                      style={
                          'width': '80%', 'height': 250, 'verticalAlign': 'top',
                          'fontFamily': 'Arial', 'fontColor': '#515151',
                      }
                  ),
                  style={'display': 'flex', 'justifyContent': 'center'}
              ),
              html.Div(
                  [html.Button(id='submit', n_clicks=0, children='Submit')],
                  style={'display': 'flex', 'justifyContent': 'center', 'marginTop': '20px'}),
              html.Br(),
              html.Div(
                  className="row",
                  children=[
                      html.Div(
                          className="six columns",
                          style={"width":600, "margin": 10, "marginLeft": '30px', 'display': 'inline-block'},
                          children=[
                              html.Div(
                                  children=
                                  dcc.Graph(id='piegraph')
                              )
                          ]
                      ),
                      html.Div(
                          className="six columns",
                          style={"width":700, "margin": 10, 'display': 'inline-block'},
                          children=html.Div(
                              children=
                              dcc.Graph(id='bargraph'),
                          )
                      )
                  ]
              ),
          ]
    )

My Code for Function is here:

    def predictBar(text_input): 
    tokenized_sentence = tokenizer.encode(text_input)
    input_ids = torch.tensor([tokenized_sentence]).cuda() 
    with torch.no_grad():
        output = model(input_ids)
    label_indices = np.argmax(output[0].to('cpu').numpy(),
                              axis=2)
    # join split tokens
    tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
    new_tokens, new_labels = [], []
    
    for token, label_idx in zip(tokens, label_indices[0]):
        if token.startswith("##"):
            new_tokens[-1] = new_tokens[-1] + token[2:]
        else:
            new_labels.append(tags_vals[label_idx])
            new_tokens.append(token)
    
    ner_data = {'Words':new_tokens,'Labels':new_labels}
    fig_BAR = px.bar(ner_data, x="Words", y="Labels", orientation='h')
    return fig_BAR
    

    def predictPie(text_input):  
    tokenized_sentence = tokenizer.encode(text_input)
    input_ids = torch.tensor([tokenized_sentence]).cuda()
    with torch.no_grad():
        output = model(input_ids)
    label_indices = np.argmax(output[0].to('cpu').numpy(),
                              axis=2)
    # join split tokens
    tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
    new_tokens, new_labels = [], []

    for token, label_idx in zip(tokens, label_indices[0]):
        if token.startswith("##"):
            new_tokens[-1] = new_tokens[-1] + token[2:]
        else:
            new_labels.append(tags_vals[label_idx])
            new_tokens.append(token)

    ner_data = {'Words':new_tokens,'Labels':new_labels}
    fig_PIE = px.pie(ner_data, values='Words', names='Labels')
    return fig_PIE

and the callback code is here:

 @app.callback(Output('piegraph', 'figure'),
                  [Input('submit', 'n_clicks')],
                  [State('text-input', 'value')])
    
    def plot_pie(submit, text_input):
        if submit is None:
          # PreventUpdate prevents ALL outputs updating
          raise dash.exceptions.PreventUpdate
        fig_PIE = predictPIE(text_input)
        return fig_PIE
    
    @app.callback(Output('bargraph', 'figure'),
                  [Input('submit', 'n_clicks')],
                  [State('text-input', 'value')])
    
    def plot_bar(submit, text_input):
        if submit is None:
          # PreventUpdate prevents ALL outputs updating
          raise dash.exceptions.PreventUpdate
        fig_BAR = predictBar(text_input)
        return fig_BAR

I ran this using google colab with JupyterDash external mode.

Hi @liandanisa

You can click on the error message to see more details of it.:grinning:

The problem is that the error info detail message doesn’t come out, only the message Callback error update bargraph.figure appears.
I’ve tried various ways but the result is always like that

Another tip:

print the fig variables before returning, to see in the console if the information that is returned is as expected:

        print(fig_BAR)
        return fig_BAR

I will try your advice, if I still have a problem can I ask you again?

Yes, Sure :smiley:

One way to find this kind of problem is first build a variable for the figure property of the dcc.Graph that you want to have as a result of the callback’s output, but instead of using a callback just try directly in the dcc.Graph and see if the graph shows the fig as expected.

Then printing the figure that the callback builds, you can compare both and find out where the difference is. :grinning:

You suggested that I try to create a graph without going through a callback, but what I’m confused about is whether I can input value without using a callback?

Hey @liandanisa

I tryed to reproduce your code but unfortunatly I have problem with the tokenizer.encode() I don’t have the approriate package.

But try adding your functions into the callback like this:

@app.callback(Output('piegraph', 'figure'),
                 [Input('submit', 'n_clicks')],
                 [State('text-input', 'value')])   
def plot_pie(submit, text_input):
    if submit is None:
        # PreventUpdate prevents ALL outputs updating
        raise dash.exceptions.PreventUpdate
    
    tokenized_sentence = Tokenizer.encode(text_input)
    input_ids = torch.tensor([tokenized_sentence]).cuda()
    with torch.no_grad():
        output = model(input_ids)
    label_indices = np.argmax(output[0].to('cpu').numpy(),
                              axis=2)
    # join split tokens
    tokens = Tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
    new_tokens, new_labels = [], []

    for token, label_idx in zip(tokens, label_indices[0]):
        if token.startswith("##"):
            new_tokens[-1] = new_tokens[-1] + token[2:]
        else:
            new_labels.append(tags_vals[label_idx])
            new_tokens.append(token)

    ner_data = {'Words':new_tokens,'Labels':new_labels}
    fig_PIE = px.pie(ner_data, values='Words', names='Labels')
    
    print(fig_PIE)
    
    return fig_PIE

@app.callback(Output('bargraph', 'figure'),
              [Input('submit', 'n_clicks')],
              [State('text-input', 'value')])

def plot_bar(submit, text_input):
    if submit is None:
        # PreventUpdate prevents ALL outputs updating
        raise dash.exceptions.PreventUpdate
        
    tokenized_sentence = Tokenizer.encode(text_input)
    input_ids = torch.tensor([tokenized_sentence]).cuda() 
    with torch.no_grad():
        output = model(input_ids)
    label_indices = np.argmax(output[0].to('cpu').numpy(),
                              axis=2)
    # join split tokens
    tokens = Tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
    new_tokens, new_labels = [], []
    
    for token, label_idx in zip(tokens, label_indices[0]):
        if token.startswith("##"):
            new_tokens[-1] = new_tokens[-1] + token[2:]
        else:
            new_labels.append(tags_vals[label_idx])
            new_tokens.append(token)
    
    ner_data = {'Words':new_tokens,'Labels':new_labels}
    fig_BAR = px.bar(ner_data, x="Words", y="Labels", orientation='h')    
    print(fig_BAR)
    
    return fig_BAR

If you want share the libraries you are using to let me try in my PC.

I have managed to solve it, and it turns out that besides in the figure my error lies in the tokenizer encode. But it has all worked. Thank you for your help.

1 Like