Embed Plotly Dash into Flask Application - python

I have successfully created my first Flask application and divided my code into a series of blueprints as my code base will grow substantially over time. I am now trying to embed a plotly dashboard (or maybe just a plotly visual display) into my app.
For now, I'm using a toy example I took from the web to learn plotly. The second code chunk launches the dash, but my goal is to integrate that second code into my main flask app. Provisionally, I'd like for it to be a route in the main app (I'll parse it out into a blueprint module later), but cannot find from the plotly documentation a didactic example showing how to integrate these together.
Am looking for some code support who might be able to show how the second can be seamlessly integrated into the main application as a route.
This link gave me some ideas to try, Running a Dash app within a Flask app, but I am not quite successful with some of the ideas proposed there.
from flask import Flask, render_template, request, session
from flask_session import Session
app = Flask(__name__)
app.secret_key = 'abcdefg'
### Import and Register Blueprints
from Help.routes import help
from Datatools.routes import data_tools
from Configtools.routes import config_tools
from wordAnalyzer.routes import word_analyzer
from ScoringTools.routes import test_scoring
app.register_blueprint(help)
app.register_blueprint(data_tools)
app.register_blueprint(config_tools)
app.register_blueprint(word_analyzer)
app.register_blueprint(test_scoring)
#app.route('/')
def homepage():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
The plotly app
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
df = pd.read_excel("https://github.com/chris1610/pbpython/blob/master/data/salesfunnel.xlsx?raw=True")
pv = pd.pivot_table(df, index=['Name'], columns=["Status"], values=['Quantity'], aggfunc=sum, fill_value=0)
trace1 = go.Bar(x=pv.index, y=pv[('Quantity', 'declined')], name='Declined')
trace2 = go.Bar(x=pv.index, y=pv[('Quantity', 'pending')], name='Pending')
trace3 = go.Bar(x=pv.index, y=pv[('Quantity', 'presented')], name='Presented')
trace4 = go.Bar(x=pv.index, y=pv[('Quantity', 'won')], name='Won')
app = dash.Dash()
app.layout = html.Div(children=[
html.H1(children='Sales Funnel Report'),
html.Div(children='''National Sales Funnel Report.'''),
dcc.Graph(
id='example-graph',
figure={
'data': [trace1, trace2, trace3, trace4],
'layout':
go.Layout(title='Order Status by Customer', barmode='stack')
})
])
if __name__ == '__main__':
app.run_server(debug=True)
UPDATE
I'm wondering if it's possible to do something along the lines of the following, such that the visual display is produced and outputted to an html file I create. My thinking here is that my app now is set up to allow a custom file input and then the user could read in a data file and it would be passed to the graphic.
#server.route('/fake')
def fake():
df = pd.read_excel("https://github.com/chris1610/pbpython/blob/master/data/salesfunnel.xlsx?raw=True")
pv = pd.pivot_table(df, index=['Name'], columns=["Status"], values=['Quantity'], aggfunc=sum, fill_value=0)
trace1 = go.Bar(x=pv.index, y=pv[('Quantity', 'declined')], name='Declined')
trace2 = go.Bar(x=pv.index, y=pv[('Quantity', 'pending')], name='Pending')
trace3 = go.Bar(x=pv.index, y=pv[('Quantity', 'presented')], name='Presented')
trace4 = go.Bar(x=pv.index, y=pv[('Quantity', 'won')], name='Won')
app = dash.Dash()
app.layout = html.Div(children=[
html.H1(children='Sales Funnel Report'),
html.Div(children='''National Sales Funnel Report.'''),
dcc.Graph(
id='example-graph',
figure={
'data': [trace1, trace2, trace3, trace4],
'layout':
go.Layout(title='Order Status by Customer', barmode='stack')
})
])
return render_template('fake.html', dashboard = dcc.Graph)

To avoid confusion of the Flask and Dash objects, let's rename the Flask object to server (they are both called app in your code), i.e.
...
server = Flask(__name__)
...
Now, to integrate the Dash application with the Flask server, you simply pass the server as a keyword,
...
app = dash.Dash(server=server, url_base_pathname="/app_base_path/")
...
The url_base_pathname argument is optional, it simply allows you to control at which path the Dash app is registered.

Related

Plotly Dash Dropdown Menu Invalid Argument Error

I am trying to create a basic Dash app in a Jupyter notebook with JupyterDash. The dropdown menu is displaying the below error message when I run the script.
Below is the code I am using. I am not sure what I am doing wrong here. Any help would be greatly appreciated.
# import the libraries
from pathlib import Path
import plotly.express as px
import dash
from dash import Dash, dcc, html
from dash.dependencies import Input, Output, State
import pandas as pd
import dash_bootstrap_components as dbc
from jupyter_dash import JupyterDash
# Load the Dataframe
df = pd.read_csv(Path("./ds_salaries.csv"))
# Preview the dataset
df.head()
# Create the dash app
app = JupyterDash(__name__)
# Bar chart employee residence
fig = px.histogram(df, x="employee_residence")
# Set up the app layout - dropdown for job title
app.layout = html.Div(children=[
html.H1('Data Science Job Analyzer', style={'textAlign':'center'}),
html.Br(),
dcc.Dropdown(
id='job-dropdown',
options=df["job_title"].unique(),
style={"width": "50%", "offset":1,},
clearable=False
),
dcc.Graph(id='hist', figure=fig)
])
# Run local server
if __name__ == '__main__':
app.run_server(debug=True)

Dash live-update with Postgresql, SQLAlchemy and Pandas not updating

I am new to Dash plotly and I am trying to use the Live-Update of Dash framework to get data from PostgreSQL every 5 seconds. The web application runs smoothly, but I need to refresh the web to update the graph. I am new to dash and really need help regarding this one.
from sqlalchemy.sql import select
from sqlalchemy import create_engine
import dash
import pandas as pd
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input
import plotly
import plotly.express as px
import plotly.graph_objs as go
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Graph(id='live-graph', animate=True),
dcc.Interval(
id='graph-update',
interval=200,
n_intervals=0
)
])
#app.callback(Output('live-graph', 'figure'),
Input('graph-update', 'n_intervals'))
def update_graph(n):
engine = create_engine('postgresql+psycopg2://username:password#127.0.0.1:5432/Cryptocurrency')
with engine.connect() as conn:
df = pd.read_sql("select * from \"cryptocurrency\"", conn)
fig = px.line(df, x="time", y="bitcoin_php")
return fig
if __name__ == '__main__':
app.run_server(debug=True)
I just updated the code above. I used context manager and reduced the interval to 200.

Plotly: How to rewrite a standard dash app to launch it in JupyterLab?

You can find a bunch of Dash examples in the plotly docs, and most examples end with a note on how to build figures using Dash:
What About Dash? Dash is an open-source framework for building
analytical applications, with no Javascript required, and it is
tightly integrated with the Plotly graphing library.
Learn about how to install Dash at https://dash.plot.ly/installation.
But I'd like to fire them up in JupyterLab instead. So what changes would I have to make in the following 'normal' Dash app to make it run in JupyterLab?
Code sample:
import plotly.graph_objects as go
import plotly.express as px
import dash
import dash_core_components as dcc
import dash_html_components as html
# data and plotly figure
df = px.data.gapminder().query("country=='Canada'")
fig = px.line(df, x="year", y="lifeExp", title='Life expectancy in Canada')
# Set up Dash app
app = dash.Dash()
app.layout = html.Div([
dcc.Graph(figure=fig)
])
# Launch Dash app
app.run_server(debug=True,
use_reloader=False # Turn off reloader if inside Jupyter
)
Any working Dash app can be launched from JupyterLab with the setup described in the question by specifying use_reloader=False in:
app.run_server(debug=True,
use_reloader=False # Turn off reloader if inside Jupyter
)
But if you'd like to use JupyterLab and select between launching the app in your default browser, inline in a cell or directly in Jupyter in its own tab, just follow these simple steps:
Change the following lines
# 1
import dash
# 2
app = dash.Dash()
# 3
app.run_server(debug=True,
use_reloader=False # Turn off reloader if inside Jupyter
)
To this:
# 1
from jupyter_dash import JupyterDash
# 2
app = JupyterDash(__name__)
# 3
app.run_server(mode='inline', port = 8070, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)
This will launch Dash inline directly in JupyterLab:
But you can also go for mode='external' to launch Dash it its own tab:
And you can set mode='external' to launch it in your default browser.
Complete code with changes:'
import plotly.graph_objects as go
import plotly.express as px
# import dash
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
# data and plotly figure
df = px.data.gapminder().query("country=='Canada'")
fig = px.line(df, x="year", y="lifeExp", title='Life expectancy in Canada')
# Set up Dash app
# app = dash.Dash()
app = JupyterDash(__name__)
app.layout = html.Div([
dcc.Graph(figure=fig)
])
# Launch Dash app
# app.run_server(debug=True,
# use_reloader=False # Turn off reloader if inside Jupyter
# )
app.run_server(mode='inline', port = 8070, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)

Python plotly dash - button to link to webpage

I am using python dash and I'd like to have a button below my table that when clicked, will take the user to a specific webpage. I am very - VERY - new to using dash so I'm not even sure if this functionality exists. I did search this topic specifically to python dash and came up empty handed. Any and all help is appreciated, thank you!
You can use dash_bootstrap_components or dbc to do that. Check this page for more detailed information about dbc: https://dash-bootstrap-components.opensource.faculty.ai/docs/components/button/
To summarize, what you need to do:
If you haven't done yet, pip install dbc:
pip install dash-bootstrap-components
Import it to your code:
import dash_bootstrap_components as dbc
Configure your app with one of the dbc themes. When you creat the app, just include an external_stylesheet:
app = Dash(external_stylesheets=[dbc.themes.CYBORG])
Include the dbc.Button componen in your app (see examples in documentation or below).
Here is an example:
from dash import Dash, html
import dash_bootstrap_components as dbc
app = Dash(external_stylesheets=[dbc.themes.CYBORG])
app.layout = html.Div([
html.Div("Default format"),
dbc.Button(
children='Open Page',
id='button_plain',
href = "https://stackoverflow.com/"),
html.Br(),
html.Br(),
html.Br(),
html.Div("Modify format"),
dbc.Button(
children='Open Page',
id='button_format',
color = "primary",
outline = True, #more lightweight format
size = "lg", #sm, lg
href = "https://stackoverflow.com/"),
])
if __name__ == '__main__':
app.run_server(debug=True)
More about dbc Themes: https://bootswatch.com/
use this for button example and to learn more please use this
link:https://dash.plotly.com/dash-core-components.
import dash
import dash_html_components as html
import dash_core_components as dcc
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
html.Div(dcc.Input(id='input-box', type='text')),
html.Button('Submit', id='button'),
html.Div(id='output-container-button',
children='Enter a value and press submit')
])
#app.callback(
dash.dependencies.Output('output-container-button', 'children'),
[dash.dependencies.Input('button', 'n_clicks')],
[dash.dependencies.State('input-box', 'value')])
def update_output(n_clicks, value):
return 'The input value was "{}" and the button has been clicked {} times'.format(
value,
n_clicks
)
if __name__ == '__main__':
app.run_server(debug=True)

Plotly Dash URL pathname callback not firing when loading page

I am trying to build a multi-page Dash app using the url callback. My app called dash_apps.py looks like this:
from flask import Flask
from flask import request
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
server = Flask(__name__)
app = dash.Dash(
__name__,
server = server,
serve_locally = False,
requests_pathname_prefix = "/plotary/dash/",
)
app.layout = html.Div([
html.Div([
html.A([
html.Div(id="logo")
],href='https://man-es.com'),
html.Div([
html.H1('Keine Auswertung ausgewählt. ')
],id="description"),
],
id="navbar")]
)
#app.callback(Output('description', 'children'),
[Input('url', 'pathname')])
def display_page(pathname):
return html.Div([
html.H1('Auswertung Nr {}'.format(pathname))
])
#server.route('/plotary/dash/<int:report_id>')
def create_report(report_id):
return app
if __name__ == '__main__':
app.run_server(debug=True)
and is called through a wsgi.py that looks like this:
from dash_apps import server
if __name__ == "__main__":
server.run()
The server I am using runs nginx and I use a web socket that starts wsgi.py with gunicorn as is explained in this post.
Now if I open for example http://<ip.to.server>/plotary/dash/18 it will just state Keine Auswertung ausgewählt. although I would expect it to show Auswertung Nr. 18.
What am I missing here?
Alternatively I could also get the report_id from Flask's route, however I do not know how to then pass this variable to app.layout.
You need to add a dcc.Location object to your layout, and its id should match the one you are using on the callback ("url" in the case of Input('url', 'pathname')).
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div([
html.A([
html.Div(id="logo")
],href='https://man-es.com'),
html.Div([
html.H1('Keine Auswertung ausgewählt. ')
],id="description"),
],
id="navbar")]
)

Categories