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!

Many Updates On One Page Load. Dash App

Im trying implement “Updates on Page Load” as you document says at https://plot.ly/dash/live-updates
Trying this python code :

import dash
import dash_html_components as html
import datetime

def serve_layout():
    d = str(datetime.datetime.now())
    print ""
    print "SELECT * FROM ... #This SQL Query should run once! "
    print "This should run ONCE every GET of browser!! ",d, " ..."
    print ""
    return html.H1('The time is: ' + d)

app = dash.Dash(__name__)
app.layout = serve_layout

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

I got this on line command console:

$ python b01.py

SELECT * FROM … #This SQL Query should run once!
This should run ONCE every GET of browser!! 2017-07-01 22:07:58.632625 …

SELECT * FROM … #This SQL Query should run once!
This should run ONCE every GET of browser!! 2017-07-01 22:07:58.634538 …

SELECT * FROM … #This SQL Query should run once!
This should run ONCE every GET of browser!! 2017-07-01 22:08:07.365613 …

SELECT * FROM … #This SQL Query should run once!
This should run ONCE every GET of browser!! 2017-07-01 22:08:07.367369 …

  • Debugger is active!
  • Debugger PIN: 289-950-892

SELECT * FROM … #This SQL Query should run once!
This should run ONCE every GET of browser!! 2017-07-01 22:08:48.421873 …

SELECT * FROM … #This SQL Query should run once!
This should run ONCE every GET of browser!! 2017-07-01 22:08:48.422106 …

SELECT * FROM … #This SQL Query should run once!
This should run ONCE every GET of browser!! 2017-07-01 22:08:48.422447 …

SELECT * FROM … #This SQL Query should run once!
This should run ONCE every GET of browser!! 2017-07-01 22:08:48.422617 …

127.0.0.1 - - [01/Jul/2017 22:08:48] “GET / HTTP/1.1” 200 -
127.0.0.1 - - [01/Jul/2017 22:08:48] “GET /_dash-dependencies HTTP/1.1” 200 -

SELECT * FROM … #This SQL Query should run once!
This should run ONCE every GET of browser!! 2017-07-01 22:08:48.790658 …

127.0.0.1 - - [01/Jul/2017 22:08:48] “GET /_dash-layout HTTP/1.1” 200 -
127.0.0.1 - - [01/Jul/2017 22:08:48] “GET /_dash-routes HTTP/1.1” 200 -

How to solve this? Thanks!

Nice catch @expresiondigitalnet! Indeed, it looks like it is run twice on start and 7 times on serving the page.

This should probably be considered a bug. Until this is fixed, you could add caching so that a new value is only computed every 5 minutes or every hour or every day. There is a tutorial on caching here: https://plot.ly/dash/performance

I’m having the same issue, like @expresiondigitalnet I need to run a DB query on page load.

The current behavior is that when starting the app, my query executes 4 times, and then 7 more when the page is loaded, and 5 more each time the page is refreshed. This seems pretty egregious (and in fact undermines my application), is there a work-around for this?

1 Like

I’m having a similar issue when a callback has ‘N’ inputs. It seems that the callback function is called ‘N’ times on page load.
This is a bit cumbersome when the callback is slow. The following example reproduces this issue:

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
from dash.dependencies import Input, Output
import numpy as np
import time

app = dash.Dash()


def make_plot(value1, value2, value3, value4):
    x = np.random.randn(value1) + value3
    y = np.random.randn(value2) + value4
    trace = go.Scatter(x=x, y=y, mode='markers')
    return {'data': [trace]}

app.layout = html.Div([
    dcc.Graph(id='1'),
    dcc.Slider(id='2', min=0, max=100, value=50, step=1),
    dcc.Slider(id='3', min=0, max=100, value=50, step=1),
    dcc.Slider(id='4', min=0, max=100, value=50, step=1),
    dcc.Slider(id='5', min=0, max=100, value=50, step=1)
])


@app.callback(
    Output('1', 'figure'),
    [Input('2', 'value'),
     Input('3', 'value'),
     Input('4', 'value'),
     Input('5', 'value')])
def test(value1, value2, value3, value4):
    time.sleep(2)
    return make_plot(value1, value2, value3, value4)

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

Would it possible to fix this behaviour? Cheers!

Have had the same experiences. Wish I’d mentioned it; been debugging for two weeks! @chriddyp - want me to file an issue on Git?

1 Like

That would be great. It sounds like a lot of users are seeing this issue, so it’s something I should prioritize. I’ll see if I can fit it in next week.

1 Like

Tracked here https://github.com/plotly/dash/issues/116

2 Likes

Anyone made any progress with this, or have a workaround that may be viable?

1 Like

Same issue even in simple user guide’s example :
import dash
import dash_html_components as html
import datetime

app=dash.Dash()

def serve_layout():
print(“Started”)
return html.H1('The time is: ’ + str(datetime.datetime.now()))

app.layout = serve_layout

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

image

Update: number of times this code prints “Started” depends of web browser. 5 times for google chrome 3 times for ie and firefox =|

I’ve read some time ago that multiple roundtrips were caused by a python websocket implementation. I don’t remember the source nor did I nail it down to this problem for Dash. Pardon my ignorance. That’d be just a place to start looking at.

I haven’t worked on this yet but I"ll look into it this morning.

Dash doesn’t actually use websockets, just straight HTTP requests with flask.

1 Like

Fixed in https://github.com/plotly/dash/pull/128, the fix will be available in the v0.18.1 release.

2 Likes

Holy crap that was quick @chriddyp. On your first coffee?

Can’t wait to try!

2 Likes

v0.18.1 has been published. Upgrade with pip install dash==0.18.1. Here’s the example app that I’m testing with:

import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc

app = dash.Dash()

print('App start')


def serve_layout():
    print('Calling layout')
    return html.Div([
        html.Div(id='output-1'),
        html.Div(id='output-2'),
        dcc.Dropdown(
            id='input',
            options=[{'label': i, 'value': i} for i in ['a', 'b']]
        )
    ])


app.layout = serve_layout


@app.callback(Output('output-1', 'children'), [Input('input', 'value')])
def update_outout(value):
    return 'You have selected {}'.format(value)


@app.callback(Output('output-2', 'children'), [Input('input', 'value')])
def update_outout(value):
    return 'You have selected {}'.format(value)


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

Just barely :wink:

3 Likes

Still seeing multiple calls in a special case? input 1 effects output 1, then input 1 and output 1 are used as inputs to another function. See below:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import json
#Define Dash App
app=dash.Dash()

def app_layout():
return(
        html.Div([
            html.Div([
                    dcc.Dropdown(id='options',
                                 options=[{'label':'1', 'value':1},
                                          {'label':'2', 'value':2},
                                          {'label':'3', 'value':3}],
                                 value=1),
                    dcc.Dropdown(id='options2',
                                 options=[{'label':'1', 'value':1},
                                          {'label':'2', 'value':2},
                                          {'label':'3', 'value':3}],
                                 value=2),
                    dcc.Dropdown(id='options3',
                                 options=[{'label':'1', 'value':1},
                                          {'label':'2', 'value':2},
                                          {'label':'3', 'value':3}],
                                 value=3)
                    ]),
            html.Div([
                    dcc.Markdown("""
                                 **Dropdowns**
                                 """.replace('   ', '')),
                    html.Pre(id='click-data', style={'border': 'thin lightgrey solid'})
                        ])
                ])
    )
                #style={'backgroundColor': '#F9F9F9', 'width':'49%', 'margin':50}),

app.layout=app_layout

@app.callback(
    Output('options2', 'value'),
    [Input('options','value')])                 
def update_options2(one):
    print 'UPDATING OPTIONS2'                  
    return one

@app.callback(
    Output('options3', 'value'),
    [Input('options','value')])                 
def update_options3(one):
    print 'UPDATING OPTIONS3'                  
    return one
        
@app.callback(
    Output('click-data', 'children'),
    [Input('options','value'),
     Input('options2','value'),
     Input('options3','value')])                 
def display_click_data(one, two, three):  
    print 'OUTPUT OPTIONS'                
    return json.dumps(str(one)+str(two)+str(three))


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

new version:

@emunson - I believe that is a separate issue (Specifying dependency tree traversal). Coincidently, I’m working on that issue today as well.