Updating graph with the generator function

I have a generator function that runs some expensive calculations and every once in a while returns intermediate results. I would like to have a graph that updates when these results get back. In my mind it should look somewhat like this:

app.layout = html.Div([
html.Button(id='start_analysis', n_clicks=0, children='Start analysis'),
dcc.Graph(id='plot_result')]

@app.callback([Input('start_analysis', 'n_clicks')])
def perform_analysis(n_clicks):
    result=my_generator_function()
    for data in result:
        plot_intermediate_result(data)

@app.callback(Output('plot_result', 'figure'))
def plot_intermediate_result(data):
    figure=go.Figure(...)
    return figure    

I see that there are lots of problems here. First function doesn’t actually need an output, and second function doesn’t need an input (cause this callback is only supposed to be fired by the first callback), and I think that in Dash callbacks have to have both input and output.
Secondly, I’ve found out that callbacks cannot be fired fron another callback, so I have no idea how to do what needs to be done.
What is the proper way to update graph by generator function result?

app.layout = html.Div([
html.Button(id='start_analysis', n_clicks=0, children='Start analysis'),
dcc.Graph(id='plot_result')]

@app.callback(
     Output('plot_result', 'figure'),
     [Input('start_analysis', 'n_clicks')])
def perform_analysis(n_clicks):
    result=my_generator_function()
    for data in result:
        plot_intermediate_result(data)

    ....
    return your_final_figure


def plot_intermediate_result(data):
    figure=go.Figure(...)
    return figure    

Hi, see the code

This didn’t work and, frankly, I don’t see why it would, since the figure, generated in function plot_intermediate_result, doesn’t go anywhere…

You can return it, and how many graph you want to plot when user click button?

The thing is, I want to plot intermediate results before the analysis is finished, that’s why I use generators. There should be only one plot, but it should update several times while my_generator_function runs.
Therefore, the figure from plot_intemediate_result should not be returned to perform_analysis function (which is still running and cannot plot anything until it finishes).
Another “logical” way to do it would be by changing perform_analysis function to

def perform_analysis(n_clicks):
    result=my_generator_function()
    for data in result:
        figure=go.Figure(...)
        yield(figure)

But callback function cannot be a generator, so it wouldn’t work too

you need two events for input : n_clicks from html.Button and n_intervals from dcc.Interval,
and then output to your figure of graph. :slightly_smiling_face:
the code may be like as follows,

app.layout = html.Div([
    html.Button(id='start_analysis', children='Start analysis'),
    dcc.Interval(id='Interval', interval=5*1000),
    dcc.Graph(id='plot_result')
])

@app.callback(
     Output('plot_result', 'figure'),
     [Input('start_analysis', 'n_clicks'),
      Input('Interval', 'n_intervals ')])
def perform_analysis(n_clicks, n_intervals):
    ctx = dash.callback_context
    if not ctx.triggered or ctx.triggered[0]['value'] is None:  
          raise dash.exceptions.PreventUpdate
    input_id = ctx.triggered[0]['prop_id'].split('.')[0]

    if input_id == 'Interval' and your analysis function is runing :     
          run your plot_intermediate_result
          ...
          return your intermediate result
    elif input_id == 'start_analysis':
          run your perform_analysis function
          ...
          return your analysis result