I'm trying to test the refresh page logic.
I read the manual:
https://dash.plotly.com/live-updates
And wrote this simple code:
import datetime
import dash
import dash_html_components as html
def get_time():
print("get time...")
return datetime.datetime.now()
def serve_layout():
return html.H1('The time is: ' + str(get_time()))
if __name__ == '__main__':
app = dash.Dash()
app.layout = serve_layout()
app.run_server(debug=True)
I expected to see that every page refresh (F5) I will see the log "get time...",
But I see this log only on startup and not on every refresh.
What am I missing ?
I want to wrote a logic that every page refresh (F5) the function serve_layout (and get_time) will be called.
How can I do it ?
It looks like you are assigning the rendered layout instead of a function, which is needed to update on page refresh. Hence if you replace the line
app.layout = serve_layout()
with
app.layout = serve_layout
it should work as expected.
Related
I have tried all possibilities, but I can't get it to read the URL in a Python Dash application. Below is an attempt, which unfortunately does not work: the first part of the URL comes, but the back part is always filled with "_dash-update-component".
Calling in the browser with "http://127.0.0.1:8050/langage=EN" always brings only:
http://127.0.0.1:8050/_dash-update-component
anyone maybe have an idea?
import dash
from dash import html
from dash.dependencies import Input, Output
from flask import request
app = dash.Dash()
app.layout = html.Div([
html.Button("Get URL", id="get_url"),
html.Div(id='output-url')
])
#app.callback(
Output(component_id='output-url', component_property='children'),
[Input(component_id='get_url', component_property='n_clicks')]
)
def update_output(n_clicks):
if n_clicks is None:
raise dash.exceptions.PreventUpdate
else:
return request.url
if __name__ == '__main__':
app.run_server(debug=True)
My app works fine when I use the regular Dash callback, but I am currently forced to use long_callback. In this case, my spinner (dcc.Loading) disappears almost instantly - although, ironically, this seems to be a really useful place for a spinner. I have tried to create a minimal example below.
Am I misusing the spinners or is this a bug?
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
from dash.long_callback import DiskcacheLongCallbackManager
import diskcache
import time
cache = diskcache.Cache('./cache')
long_callback_manager = DiskcacheLongCallbackManager(cache)
app = dash.Dash(
__name__,
long_callback_manager=long_callback_manager,
)
app.layout = html.Div(children=[
dcc.Slider(id='my_slider', min=1, max=10, step=1, value=5),
dcc.Loading(
html.Div(id='my_div', children=['Start']),
),
])
#app.long_callback(
Output('my_div', 'children'),
Input('my_slider', 'value'),
interval=2000,
)
def update_div(slider_value):
time.sleep(5)
return f'Done loading: {slider_value}'
if __name__ == '__main__':
app.run_server(debug=True)
I have tried to set the loading_state/is_loading property in the running argument of the long_callback, but I haven't succeeded. Maybe it's not a "setable" property?
Not sure if this is the solution you are looking for, but I have discovered a method that works with dash bootstrap components using the dbc.Spinner in conjunction with the running keyword argument of the long_callback.
First, create a div where you want the spinner to appear, give it a unique id name and set its children equal to None. For me, I used a dbc.Row(dbc.Col()) instead of a div, but it should work the same. Then you will need to set the running keyword argument of the long_callback to output a dbc.Spinner. The following code is currently working for me. I have removed a lot of code, so ignore the inputs, ouputs and lack of layout components. Pay attention to the running kwarg.
app.layout = dbc.Container(dbc.Row(dbc.Col(id='fs_spinner', children=None)))
#app.long_callback(
output=(
Output("full_search_predictions", "data"),
Output("full_results_query", "data"),
),
inputs=[
Input("submit_button", "n_clicks"),
Input("search_query", "value"),
],
running=[
(Output('fs_spinner', 'children'), dbc.Spinner(size='md'), None)
],
interval=20000,
prevent_initial_call=True,
)
Here is what is happening. When the the long_callback begins, it returns a dbc.Spinner() to the children component of the fs_spinner. Once the callback is complete, it then returns None to the children component of the fs_spinner, which removes the spinner from the screen.
Hope this helps!
I'm writing a plotly Dash application where I don't initially have database access, so I need to wait for the database connection before I can set the initial application state.
Thus, I want to run a function that will set the application state later on, but the only way to set state seems to be with #app.callback() decorators, but the problem is they require a property or state variable to watch before firing, but in my case I'm not watching part of the Dash app, I'm watching something external.
How can I do this in Dash?
For example:
app = Dash(routes_pathname_prefix='/dash/trend/')
app.layout = html.Div(children=[
dcc.Dropdown(
options=get_field_options(),
id='field_select',
multi=True,
)
])
#app.callback(
dash.dependencies.Output('field_select', 'options'),
[
# What do I put here as an input??
]
)
def update_fields(href):
return get_field_options()
You can use plotly dash store component to keep some data needed for event.
dcc.Store(id='local', storage_type='local'),
Dash Store component
Use a hidden html.Div() to store your information. This can be empty:
html.Div(id='application-state', style={'display': 'none'})
So your code should look like this:
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
app = Dash(routes_pathname_prefix='/dash/trend/')
app.layout = html.Div(children=[
dcc.Dropdown(
options=get_field_options(),
id='field_select',
multi=True,
),
html.Div(id='application-state', style={'display': 'none'})
])
#app.callback(
[Output('field_select', 'options')],
[Input('application-state', 'children')])
def update_fields(href):
if href =! None:
return get_field_options()
else:
return []
Your external part should update the respective hidden div. You can change this to any other component that is able to store the information you want to transfer to the dash visualization. You find the best sources and tricks for this problem domain here.
The if else part for returning a valid object is a bit tricky. Please let me know if there is a callback output error like Expected 1 output but received None or something similar.
I have a Flask/Dash app that uses the Flask-Babel module. The translation works like a charm after logging in and browsing through pages. However, I cannot make it work for the login page which will always be displayed in English. The messages.po and messages.mo both contain the translation strings I prepared for the login page, so the compilation part seems to work fine.
Here's a snippet from my app.py (with a hard-coded choice of Spanish):
import dash
from dash.dependencies import Input, Output
from flask import Flask, request
from flask_babel import Babel
# some more imports...
# (...)
def main():
update_dataframes()
app = dash.Dash(
"MyApp",
url_base_pathname='/summary',
static_folder="static",
sharing=True,
csrf_protect=False
)
# Hook Flask-Babel to the app
babel = Babel(app.server)
#babel.localeselector
def get_locale():
# return request.accept_languages.best_match(context.config['LANGUAGES'].keys())
return 'es'
# App layout
app.layout = build_app_layout(context)
# Setup callbacks
setup_callbacks(app)
setup_login(app, app.server, context.config)
# Start Dash/Flask app
app.server.run(
port=context.config['DEPLOY']['SERVER_PORT'],
debug=context.config['DEPLOY']['SERVER_DEBUG'],
threaded=context.config['DEPLOY']['SERVER_THREADED']
)
# Interval tread to update all dataframes
ThreadPoolExecutor(max_workers=1).submit(update_dataframes_thread)
if __name__ == '__main__':
main()
Below, a part of the setup_login(...) method called above. I'd like to notice that app.server is passed to it from the code above, after Flask-Babel has been hooked to the app (don't really know if that matters much):
from dash_flask_login import FlaskLoginAuth
from flask_login import LoginManager, UserMixin, login_user, logout_user
# (...)
login_app = Dash(
name='login-app',
url_base_pathname='/login',
server=app.server
)
What I tried: hooking the Flask-Babel again for the login_app Dash() instance, but that didn't work (anyways it's still the same app.server).
I've come across this SO question with a similar problem, but it seems to be specific to Flask-Security module (not my case).
What am I missing to make the login page translated?
Although I haven't found a direct reason why a combination of Dash and Flask-Login don't work with Flask-Babel on the login page, I solved the problem with a workaround - I'm dynamically updating generated HTML component through Dash's callback decorator just after loading the page. The function simply substitutes the original English some_string with gettext(some_string) tag which is detected properly in the callbacks. This way the page loads in English and immediately gets translated, as the callbacks come to action. Minimal example:
app.layout = html.Div(
[
html.H1('Hello World!', id='h1'),
html.Div(html.A('login', href='/login')
]
)
# Display the message translated to another language
#app.callback(
Output('h1', 'children'),
[Input('url', 'search')]
)
def translate_message(children):
return gettext('Hello World!')
I want to be able to run my dash app from my flask app when I go to a specific url '/dash'. However I get the following error. 'TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.'
flaskapp.py
app = Flask(__name__)
#app.route('/')
def index():
return 'Welcome!'
#app.route('/dash')
def dash_chart():
dashapp.start() # Run the dash app
if __name__ == "__main__":
app.run(debug=True)
dashapp.py
def start():
app = dash.Dash()
app.layout = html.Div('Hello World')
if __name__=='__main__':
app.run_server(debug=True)
If I make the following change to my flaskapp.py,
server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server, url_base_pathname='/dashapp') #Results in an error
#server.route('/')
def index():
return 'Welcome!'
#server.route('/dash')
def dash_chart():
return flask.redirect('/dashapp')
if __name__ == "__main__":
server.run(debug=True)
I get the following error, AttributeError: 'NoneType' object has no attribute 'traverse'
I think your issue is that you never actually built out the Dash application. I get the same errors you get with your code, but actually building out the Dash app (that is, setting the Layout) seems to fix the issue. Note that the error traceback specifically shows Dash failing to traverse your layout, because there isn't one. Try creating a dash.Layout() for it to parse, so that it has something to serve. An answer to issue #220 on Dash's GitHub mentions this same error and solution.
For a MCVE:
import dash
import dash_html_components as html
import flask
server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server, url_base_pathname='/dashapp')
app.layout = html.Div(children=[
html.H1(children='Dash App')])
#server.route('/')
def index():
return '''
<html>
<div>
<h1>Flask App</h1>
</div>
</html>
'''
if __name__ == '__main__':
server.run(debug=True)
Each page should look the same, except that host:port/ should show the heading "Flask App", while host:port/dashapp should show the heading "Dash App".