Black Lives Matter. Please consider donating to Black Girls Code today.
Learn how to use COVID-19 data in open source Dash apps. Register for the Sept 23rd webinar with IQT!

First update of plotly Dash with live update

Dear all,

I am trying to use live update with plotly Dash (0.18.3) in Python (3.x), but I don’t need to update the plot so often (once or twice a day is what I need).

I did the following so far:

import dash
import pandas as pd
import plotly.graph_objs as go
import dash.dependencies as ddp
import dash_core_components as dcc
import dash_html_components as html

def plot_figure(data):
    layout = dict(
    title="Figure w/ plotly",
    )

    fig = dict(data=data, layout=layout)
    return fig

def serve_layout():
    return html.Div(children=[
        html.Div([
            html.H1("Plotly test with Live update",
                    style={"font-family": "Helvetica",
                           "border-bottom": "1px #000000 solid"}),
            ], className='banner'),
        html.Div([dcc.Graph(id='plot')],),
        dcc.Interval(id='live-update', interval=interval),
],)

second = 1000
minute = 60
hour   = 60
day    = 24
interval = 1/2*day*hour*minute*second

app = dash.Dash()

app.layout = serve_layout

@app.callback(
    ddp.Output('plot', 'figure'),
    [],
    [],
    [ddp.Event('live-update', 'interval')])
def gen_plot():
    ind = ['a', 'b', 'c', 'd']
    df = pd.DataFrame({'one' : pd.Series([4., 3., 2., 1.], index=ind),
                       'two' : pd.Series([1., 2., 3., 4.], index=ind)})

    trace = [go.Scatter(x=df.index, y=df['one'])]
    fig   = plot_figure(trace)
    return fig

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

The problem is at first nothing appears, it updates only after interval, so after half a day. I added the serve_layout function following Dash documentation to have an update when the page is loaded, but it seems to have no effect.

How could I have a first update when the page is first accessed and then updates at every interval?

Thank you for your answers!

Check out the solution in Trigger an event by changing tab. In short, you’ll need to call gen_plot() from inside serve_layout to get the most recent figure. In order to call gen_plot, you’ll need to remove the decorator from it.

Here is your example with those changes:

import dash
import pandas as pd
import plotly.graph_objs as go
import dash.dependencies as ddp
import dash_core_components as dcc
import dash_html_components as html

def plot_figure(data):
    layout = dict(
    title="Figure w/ plotly",
    )

    fig = dict(data=data, layout=layout)
    return fig

def serve_layout():
    return html.Div(children=[
        html.Div([
            html.H1("Plotly test with Live update",
                    style={"font-family": "Helvetica",
                           "border-bottom": "1px #000000 solid"}),
            ], className='banner'),
        html.Div([dcc.Graph(id='plot')],),
        dcc.Interval(id='live-update', interval=interval),
],)

second = 1000
minute = 60
hour   = 60
day    = 24
interval = 1/2*day*hour*minute*second

app = dash.Dash()

app.layout = serve_layout

def gen_plot():
    ind = ['a', 'b', 'c', 'd']
    df = pd.DataFrame({'one' : pd.Series([4., 3., 2., 1.], index=ind),
                       'two' : pd.Series([1., 2., 3., 4.], index=ind)})

    trace = [go.Scatter(x=df.index, y=df['one'])]
    fig   = plot_figure(trace)
    return fig

app.callback(
    ddp.Output('plot', 'figure'),
    [],
    [],
    [ddp.Event('live-update', 'interval')])(gen_plot)


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

I recommend reading through https://stackoverflow.com/questions/739654/how-to-make-a-chain-of-function-decorators/1594484#1594484 to get a better sense of how these decorators work and how you can refactor your code around them. :beers:

Also - I noticed that you posted this question earlier in stack overflow (https://stackoverflow.com/questions/46570953/first-update-of-plotly-dash-with-live-update) - would you mind linking this answer as a comment in your original SO question? Thanks :slight_smile:

Thank you for your answer, it helped! I had few little things to modify to make it work: move gen_plot before serve_layout, and add figure=gen_plot() to dcc.Graph in serve_layout.

import dash
import pandas as pd
import plotly.graph_objs as go 
import dash.dependencies as ddp
import dash_core_components as dcc
import dash_html_components as html

second = 1000
minute = 60
hour   = 60
day    = 24
interval = 1/2*day*hour*minute*second

def plot_figure(data):
    layout = dict(
        title="Figure w/ plotly",
    )
    
    fig = dict(data=data, layout=layout)
    return fig

def gen_plot():
    ind = ['a', 'b', 'c', 'd']
    df = pd.DataFrame({'one' : pd.Series([4., 3., 2., 1.], index=ind),
                       'two' : pd.Series([1., 2., 3., 4.], index=ind)})

    trace = [go.Scatter(x=df.index, y=df['one'])]
    fig   = plot_figure(trace)
    return fig

def serve_layout():
    return html.Div(children=[
        html.Div([
            html.H1("Plotly test with Live update",
                    style={"font-family": "Helvetica", 
                           "border-bottom": "1px #000000 solid"}),
            ], className='banner'),
        html.Div([dcc.Graph(id='plot', figure=gen_plot())],),
        dcc.Interval(id='live-update', interval=interval),
],)

app = dash.Dash()

app.layout = serve_layout

app.callback(
    ddp.Output('plot', 'figure'),
    [],
    [],
    [ddp.Event('live-update', 'interval')])(gen_plot)

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

Note that in my real application I also needed to do so with excerpt of text that I update with the figure. I had a gen_text function with the same decorator as my gen_plot function, I applied the same strategy and I added a children=gen_text() argument to the related html.Div; works like a charm!

Thank you for your help; I will mention this thread on StackOverflow.