I'm trying to build a multi page Dash App. When I run the following code, everything works except it won't route to my /dash_1 or /dash_2 urls. Was wondering if someone could help me out.
My structure looks like this:
dash-project/
app1/
app.py
app2/
app.py
server.py
run.py
My run.py code is
from app import server as application
from app import app
import app_1.dash_1
import app_2.dash_2
My app.py code is:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from werkzeug.wsgi import DispatcherMiddleware
import os
import pandas as pd
import dash
import flask
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from analysis import *
server=flask.Flask(name)
app = dash.Dash(name)
app.config.suppress_callback_exceptions = True
app.css.append_css({
‘external_url’: ‘https://codepen.io/chriddyp/pen/bWLwgP.css’
})
My dash_1.py code is:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
import plotly.graph_objs as go
from analysis import *
from app import app, server
app = dash.Dash(name='dash_1', sharing=True,
url_base_pathname='/dash_1', csrf_protect=False)
app.config['suppress_callback_exceptions']=True
df = pd.read_csv('/Users/ds/app_1/main.csv')
layout = html.Div([
dcc.Graph(
id='Senators ',
figure={
'data': [
go.Scatter(
x=df[df['candidate'] == i]
['contributor_individual'],
y=df[df['candidate_name'] == i]['contributor'],
#z=df[df['candidate_name'] == i]['contributor'],
text=df[df['candidate_name'] == i]['contributorl'],
mode='markers',
opacity=0.7,
marker={
'size': 15,
'line': {'width': 0.5, 'color': 'white'}
},
name=i
) for i in df.candidate_name.unique()
],
'layout': go.Layout(
xaxis={'title': 'Contributor '},
yaxis={'title': 'Contributor '},
#margin={'l': 40, 'b': 40, 't': 10, 'r': 10},
#legend={'x': 0, 'y': 1},
hovermode='closest'
)
}
)
])
layout = html.Div(children=[
html.H1(children='Senators '),
html.Div(children='''
God Bless.
'''),
dcc.Graph(
id='main.csv',
figure={
'data': [
{'x':df['candidate'], 'y': df['sectorl'], 'type': 'bar'},
{'x':df['candidate'], 'y': df['industry'], 'type': 'bar'},
{'x':df['candidate'], 'y': df['contributor'], 'type': 'bar'},
],
'layout': {
'title': 'Let Them Eat...'
}
}
)
])
My dash_2.py code is
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
from app import app, server
app = dash.Dash(name='dash_2', sharing=True,
url_base_pathname='/dash_2', csrf_protect=False)
app.config['suppress_callback_exceptions']=True
df = pd.read_csv('/Users/ds/app_2/slice.csv')
layout = html.Div(children=[
html.H1(children='Bars'),
html.Div(children='''
One Bite....
'''),
dcc.Graph(
id='slice.csv',
figure={
'data': [
{'x':df['Slice'], 'y': df['Score'], 'type': 'bar'},
],
'layout': {
'title': 'Bars'
}
}
)
])
Any help would be greatly appreciated - I can't seem to wrap my head around this - Thanks!
You need to pass your flask app to your Dash instance.
Like this.
app = dash.Dash(__name__, server=server)
So try importing server and include it as a parameter in your Dash instances in app1 and app2.
Like so:
from app import server
app = dash.Dash(name='dash_1', sharing=True,
url_base_pathname='/dash_1', csrf_protect=False, server=server)
app = dash.Dash(name='dash_2', sharing=True,
url_base_pathname='/dash_2', csrf_protect=False, server=server)
Hope it helps.
#Franrey Saycon is completely right. You were importing too many things. In case this is helpful to anyone, I created a tutorial that shows how to build a multipage Dash application, with explanations on folder/file structure and library imports.
Related
I am trying to build a dropdown page selector in a multi page dash app. The dropdown selection should generate an updated html depending on the user selection. The issue that I'm running in to is that I do not know how to use href within the value selection of dcc.Dropdown.
The code below is my current example that is not working.
import dash
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash(__name__, suppress_callback_exceptions=True)
server = app.server
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div([
html.H2('Equipment Maintenance & Repair Dashboard'),
html.Div([
dcc.Dropdown(id='page_dd',
options=[{'label': x, 'value': x} for x, y in page_info.items()])
])
])
])
if __name__ == '__main__':
app.run_server()
If I use dcc.Link instead of dcc.Dropdown, then the output is successful. See the example below, which properly changes the html following the user selection.
import dash
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash(__name__, suppress_callback_exceptions=True)
server = app.server
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div([
html.H2('Equipment Maintenance & Repair Dashboard'),
html.Div([
dcc.Link('Trend ', href='/apps/dispatch_trend'),
dcc.Link('Equipment ', href='/apps/equipment_overview')
])
])
])
if __name__ == '__main__':
app.run_server()
If you want the url to change based on the dropdown selection you need to create callback
#app.callback(Output("url", "pathname"), Input("page_dd", "value"))
def update_url_on_dropdown_change(dropdown_value):
return dropdown_value
Complete example
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input
app = dash.Dash(__name__, suppress_callback_exceptions=True)
server = app.server
app.layout = html.Div(
[
dcc.Location(id="url", refresh=False),
html.Div(
[
html.H2("Equipment Maintenance & Repair Dashboard"),
html.Div(
[
dcc.Dropdown(
id="page_dd",
options=[
{"label": "Trend", "value": "/apps/dispatch_trend"},
{
"label": "Equipment",
"value": "/apps/equipment_overview",
},
],
)
]
),
]
),
]
)
#app.callback(Output("url", "pathname"), Input("page_dd", "value"))
def update_url_on_dropdown_change(dropdown_value):
return dropdown_value
if __name__ == "__main__":
app.run_server()
I am implementing a flask application on which I want cytoscape graphs on it. I also want to dynamically update the data by sending a rest API call on the flask application and based on the data the cytoscape graph updates the graphs.
This is the code I have written to do so, but the update process is slow i.e. it receives the data but that data isn't updated on the dash code.
import dash # pip install dash
import dash_cytoscape as cyto # pip install dash-cytoscape==0.2.0 or higher
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Output, Input
import pandas as pd # pip install pandas
import plotly.express as px
import requests
from flask import Flask, request
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
server = Flask(__name__)
app1 = dash.Dash(__name__, server=server, external_stylesheets=external_stylesheets)
#server.route('/data', methods=['POST'])
def query_example():
global data_out
data = request.get_data()
data = (literal_eval(data.decode('utf8')))["data"]
print("Data Received")
with open('topology_data.pkl', 'wb') as f:
pickle.dump(data, f)
return {"Data":True}
with open('topology_data.pkl', 'rb') as f:
data_out = pickle.load(f)
app1.layout = html.Div([
html.Div([
cyto.Cytoscape(
id='org-chart',
layout={'name': 'breadthfirst'},
style={'width': '100%', 'height': '500px'},
elements=data_out,
stylesheet=[
# Group selectors
{
'selector': 'node',
'style': {
'content': 'data(label)',
'background-color': 'green',
'line-color': 'green'
}
},
{
'selector': 'edge',
'style': {
'background-color': 'green',
'line-color': 'green',
'label': 'data(label)'
}
},
{
'selector': '[weight = 1]',
'style': {
'line-color': 'red'
}
}
]
)
], className='six columns'),
], className='row')
if __name__ == '__main__':
app1.run_server(debug=True)
Please tell me a solution to integrate the data receiving process using the REST API and updating the data on the graphs.
You need to use callbacks to update the data.
#app.callback(Output('org-chart', 'elements'),
[Input("button", "n_clicks")],
def update_data(nclicks):
"""Retrieves data from api call
Parameters
----------
nclicks : int | None
The number of times the button was pressed.
Used to prevent initial update with empty state.
"""
if nclicks in [0, None]:
raise PreventUpdate
else:
data = api_call()
return data
You can find a lot more details and an example on https://dash.plotly.com/cytoscape/callbacks under "Adding and removing elements"
You need to add a button in your app layout of course
html.Button('Make api call', id='button', n_clicks=0)
I'm fairly new to dash and I'm trying to follow along some of the more advanced guides (link: here) that look at multi page dashboards but seem to be falling over at every hurdle along the way.
I've managed to create my virtual environment install the required packages and I've just created the 'app.py' file but when I create and run the 'index.py' file I'm seeing the following error:
ImportError: cannot import name 'app' from 'app'
The app.py file I'm running was created with the following code:
import dash
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
#app.config.suppress_callback_exceptions = True ####<-- tutorial said to run this line but as suppress was giving me errors I removed it
The 'index.py' file I'm running looks like:
from app import app
from app import server
import dash_html_components as html
import dash_core_components as dcc
app.layout = html.Div([html.H1('Dash Demo Graph',
style={
'textAlign': 'center',
"background": "yellow"}),
dcc.Graph(
id='graph-1',
figure={
'data': [
{'x': [1, 2, 3, 4, 5, 6, 7], 'y': [10, 20, 30, 40, 50, 60, 70], 'type': 'line', 'name': 'value1'},
{'x': [1, 2, 3, 4, 5, 6, 7], 'y': [12, 22, 36, 44, 49, 58, 73], 'type': 'line', 'name': 'value2'}
],
'layout': {
'title': 'Simple Line Graph',
}
}
),
], style={
"background": "#000080"}
)
if __name__ == '__main__':
app.run_server(debug=True)
I'm on a Windows machine using Jupyter Lab and python 3.8, the directory I'm running the code out of has the following folders and files in:
.ipynb_checkpoints
__pycache__
env
app.py
index.py
Any help on how I resolve this error would be much appreciated.
I was looking for a solution to this issue I encountered. There is a question almost similar to mine in plotly community (https://community.plot.ly/t/problem-with-densitymapbox-chart-type/28517), but still haven’t found a resolution. My dropdown menu consists of scattermapbox and densitymapbox as i wanted to juggle between these. However, when changing from scattermapbox to densitymapbox, it results to the image below:
densitymapbox after scattermapbox format
import dash
import copy
import pathlib
import dash
import numpy as np
import math
import datetime as dt
import pandas as pd
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_core_components as dcc
import dash_html_components as html
import dash_table
import plotly.graph_objs as go
# get relative data folder
PATH = pathlib.Path(__file__).parent
DATA_PATH = PATH.joinpath("data").resolve()
external_scripts = [
‘https://cdn.plot.ly/plotly-1.39.1.min.js’
]
external_stylesheets = [
‘https://codepen.io/etpinard/pen/wxwPXJ’
]
app = dash.Dash(
__name__,
external_scripts=external_scripts,
external_stylesheets=external_stylesheets
)
server = app.server
# Load data
df = pd.read_excel("Clean_TR(6.8.19).xlsx")
group_name = df['gname'].unique()
mapbox_access_token = <your token>
app.layout = html.Div(
[
dcc.Store(id = 'aggregate_data'),
dcc.Dropdown(
id = 'map_plot',
options = [{'label':i, "value":i} for i in ['Scatter', 'Density']],
value = ['Scatter']
),
dcc.Graph(id = 'mindanao-map')
]
)
#app.callback(
Output('mindanao-map', 'figure'),
[Input('map_plot', 'value')]
)
def update_map(map_plot):
if map_plot == "Density":
maptype = 'densitymapbox'
else:
maptype = 'scattermapbox'
return {
'data' : [{
'lat':df['latitude'],
'lon':df['longitude'],
'marker':{
'color': df['freq'],
'size': 8,
'opacity': 0.6
},
'customdata': df['idno'],
'type': maptype
}],
'layout': {
'mapbox': {
'accesstoken': mapbox_access_token,
'style':"light",
'center': dict(lon=123.30, lat= 7.50),
'zoom':'6',
},
'hovermode': 'closest',
'margin': {'l': 0, 'r': 0, 'b': 0, 't': 0}
}
}
if __name__ == "__main__":
app.run_server(debug=True)
But whenever I swap out the if-else ordering, i.e,
if map_plot == "Scatter":
maptype = 'scattermapbox'
else:
maptype = 'densitymapbox'
it results to density map showing, but scatter will not.
Do I need to separate these two instead of if-else? Any inputs will do. Thank you for your time!
This is a Plotly.js bug, and I've filed a report here: https://github.com/plotly/plotly.js/issues/4285
Edit: this bug is fixed in recent versions of Plotly.js and Plotly.py and Dash.
I want to export the site I've made in dash into a static PDF. Here is the code for my site (it's just a chart with 3 columns):
import dash
import dash_core_components as dcc
import dash_html_components as html
import pdfkit
from flask import Flask, render_template, make_response
app = dash.Dash()
app.layout = html.Div(
className="three columns",
children=html.Div([
dcc.Graph(
id='right-top-graph',
figure={
'data': [{
'x': [1, 2, 3],
'y': [3, 1, 2],
'type': 'bar'
}],
'layout': {
'height': 400,
'margin': {'l': 10, 'b': 20, 't': 0, 'r': 0}
}
}
),
])
)
app.css.append_css({
'external_url': 'https://codepen.io/chriddyp/pen/bWLwgP.css'
})
if __name__ == '__main__':
app.run_server(debug=True)
I tried using pdfkit by adding this code to my script, but it didn't work (received an error telling me that render_template() takes 1 positional argument but 2 were given):
rendered = render_template('pdf_template.html',app)
pdf = pdfkit.from_string(rendered, False)
response = make_response(pdf)
response.headers['Content-Type'] = 'application/pdf'
response.headers['Content-Disposition'] = 'attachment; filename=output.pdf'
Does anyone have any idea as to how I can convert my dash site into a PDF?
Thanks in advance.
You can use the print function of whatever browser you are using (usually control + p) and save it as PDF if all you are looking for is the static PDF file.
If you want more enhanced functionality you can add a print to PDF button like the one in one of the dash examples. It uses a js file to invoke the browser print functionality, see more detail. This way you can also use CSS to define the way the PDF output looks
The problem with using the python file to generate pdf directly is that dash only creates a JSON representation of the layout tree which is then assembled in the browser itself, see more.
You can use pdfkit in the following way:
import pdfkit
pdfkit.from_url('http://local.dash.site', 'out.pdf')
The big difference from what you posted is that you could use the local web server to render the page.
As an alternative, you could also use https://wkhtmltopdf.org/
This is the lib underneath pdfkit.
You can use the directions from the following link to create pdf:
http://flask.pocoo.org/snippets/68/
render_template accepts only one positional arguments, the rest must be keyword arguments.
render_template takes only one positional argument.
Can you try below?
options = {
'margin-top': '0.15in',
'margin-right': '0.15in',
'margin-bottom': '0.2in',
'margin-left': '0.15in',
'encoding': "UTF-8",
}
css = 'path to your .css file'
html = render_template('a_html.html')
pdf = pdfkit.from_string(html, False, options=options, css=css)
Have you tried running your script in the following way (I've just pasted the pdf creation part of your script into where the dash site is rendered):
import dash
import dash_core_components as dcc
import dash_html_components as html
import pdfkit
from flask import Flask, render_template, make_response
app = dash.Dash()
app.layout = html.Div(
className="three columns",
children=html.Div([
dcc.Graph(
id='right-top-graph',
figure={
'data': [{
'x': [1, 2, 3],
'y': [3, 1, 2],
'type': 'bar'
}],
'layout': {
'height': 400,
'margin': {'l': 10, 'b': 20, 't': 0, 'r': 0}
}
}
),
])
)
app.css.append_css({
'external_url': 'https://codepen.io/chriddyp/pen/bWLwgP.css'
})
rendered = render_template('pdf_template.html',app)
pdf = pdfkit.from_string(rendered, False)
response = make_response(pdf)
response.headers['Content-Type'] = 'application/pdf'
response.headers['Content-Disposition'] = 'attachment; filename=output.pdf'
if __name__ == '__main__':
app.run_server(debug=True)