4

Intro:


I already have a multi-page Dash app running with each page into a separate layout file and is callable from main index page.

What works well?


Running a standalone Dash app, ($python index.py), index page is shown with other entries and each link works well, with their graphs and callbacks.

'''
index.py : relevant sections
'''
from appc import app, server
import page1c, page2c, page3c
app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content')
])
...
...
..

index_page = html.Div([ ....
# Similar to calling in flask_app.py 
------------------------------------------------------------
'''
appc.py  : relevant sections
'''
app = dash.Dash('auth')
auth = dash_auth.BasicAuth(
    app,
    VALID_USERNAME_PASSWORD_PAIRS
)

server = app.server
app.config.suppress_callback_exceptions = True
...
..
'''

What doesn't work well?


A: Trying to use existing Dash App within a Flask app ($python flask_app.py) but having issue where only HTML content (from layout is shown) but callbacks aren't triggering if Dash layouts are defined in separate files.

Why?


A: Planning to use Flask for main web site and features and Dash for interactive graphs and HTML layout.

Attempted solution:


Below is the code from flask_app.py and i've commented to my best ability.

''' 
flask_app.py : Attempt to run dash and flask based routes in one instance.
'''

from flask import Flask, render_template
from dash import Dash
from dash.dependencies import Input, State, Output
import dash_core_components as dcc
import dash_html_components as html

import json
import plotly
import pandas as pd
import numpy as np

server = Flask(__name__)
########################################################################
@server.route('/graph') # Interactive Dash Graph in predefined HTML
def index():
    rng = pd.date_range('1/1/2011', periods=7500, freq='H')
    ts = pd.Series(np.random.randn(len(rng)), index=rng)

    graphs = [
        dict(
            data=[
                dict(
                    x=[1, 2, 3],
                    y=[10, 20, 30],
                    type='scatter'
                ),
            ],
            layout=dict(
                title='first graph'
            )
        ),

        dict(
            data=[
                dict(
                    x=[1, 3, 5],
                    y=[10, 50, 30],
                    type='bar'
                ),
            ],
            layout=dict(
                title='second graph'
            )
        ),

        dict(
            data=[
                dict(
                    x=ts.index,  # Can use the pandas data structures directly
                    y=ts
                )
            ]
        )
    ]

    # Add "ids" to each of the graphs to pass up to the client
    # for templating
    ids = ['Graph-{}'.format(i) for i, _ in enumerate(graphs)]

    # Convert the figures to JSON
    # PlotlyJSONEncoder appropriately converts pandas, datetime, etc
    # objects to their JSON equivalents
    graphJSON = json.dumps(graphs, cls=plotly.utils.PlotlyJSONEncoder)
    return render_template('layouts/graph.html',
                           ids=ids,
                           graphJSON=graphJSON)

########################################################################
@server.route('/hello') # Static predefined HTML
def hello_index():
    return render_template('hello.html',)

########################################################################
app = Dash(server=server, url_base_pathname='/dash') # Interactive Dash input box with callback.
app.layout = html.Div([
    html.Div(id='target'),
    dcc.Input(id='input', type='text', value=''),
    html.Button(id='submit', n_clicks=0, children='Save')
])

@app.callback(Output('target', 'children'), [Input('submit', 'n_clicks')],
              [State('input', 'value')])
def callback(n_clicks, state):
    return "callback received value: {}".format(state)

######################################################################        
app = Dash(__name__, server=server, url_base_pathname='/dashed') #Another Bash Graph inline, no callbacks.
app.layout = html.Div(children=[
    html.Div(children='''
    Dash: A web application framework for Python
    '''),

    dcc.Graph(
        id='example-graph',
        figure={
            'data': [
                {'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
                {'x': [1, 2, 3], 'y': [2, 4, 6], 'type': 'bar', 'name': 'Montreal'},
            ],
            'layout': {
                'title': 'Dash Data Visualization'
            }
        }
    )
])
########################################################################
'''
Content from 'index.py' : Check above.

page1c, page2c, page3c are dash separate layout files for a multipage website with dash, which is working perfect.
These are called in 'index.py' (main page) respectively as below.
Running 'python index.py' (standalone dash instance), all the interactive pages are responsive and plot the data (with callbacks) they're intended to.
But running with flask, pages only show HTML content, sliders and dropdown boxes, but the backend processes aren't triggering so no graphs are generated.
'''
# Note: 'index_page' is the layout with 3 links to above items.
# All 3 files have multiple layout (with graphs and callbacks), different files for everyone to keep it simple and less cluttered.

import page1c, page2c, page3c
from index import index_page

d_app = Dash(server=server, url_base_pathname='/', )

d_app.layout = html.Div([
    html.Div(id='page-content'),
    dcc.Location(id='url', refresh=True),
])

@d_app.callback(Output('page-content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/page1':
         return page1c.layout
    elif pathname == '/page2':
         return page2c.layout
    elif pathname == '/page3':
         return page3c.layout
    else:
        return index_page

######################################################################        
if __name__ == '__main__':
    app.run_server(port=9999, debug=True)
Moni
  • 73
  • 2
  • 8
  • Hi, Moni Any luck ? – Mangesh Oct 18 '18 at 13:42
  • Didn't try it afterwards. Kept the basic site and dashboards as is with Dash. – Moni Oct 30 '18 at 03:16
  • If you toggle page inputs on the d_app, and the target url changes, does the flask app callback trigger for that URL? – bmc May 31 '20 at 14:35
  • Similar issue unsolver here https://stackoverflow.com/questions/61893445/dash-cytoscape-callbacks-not-working-after-refresh-in-a-flask-app – Rafael Valero Sep 27 '20 at 10:55
  • An interesting alternative could be run the apps in different ports and them 1) create a proxy 2) embedding the apps: as in here: https://community.plotly.com/t/proxy-multiple-dash-apps-running-on-different-ports/33385 . I am working with the second. – Rafael Valero Sep 27 '20 at 15:19
  • Another possibility could be "midleware" as in here: https://peterspython.com/en/blog/two-flask-apps-frontend-and-admin-on-one-domain-using-dispatchermiddleware but I have not tried this one fully. – Rafael Valero Sep 27 '20 at 15:36

0 Answers0