Запуск многостраничного приложения Plotly-Dash с обратными вызовами и графиками в Flask

Вступление:


У меня уже есть многостраничное приложение Dash, работающее с каждой страницей в отдельном файле макета и вызываемое с главной страницы индекса.

Что хорошо работает?


При запуске автономного приложения Dash ($python index.py) индексная страница отображается с другими записями, и каждая ссылка работает хорошо с их графиками и обратными вызовами.

'''
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
...
..
'''

Что не работает?


A: Попытка использовать существующее приложение Dash в приложении Flask ($python flask_app.py), но возникает проблема, когда отображается только HTML-контент (из макета), но обратные вызовы не запускаются, если макеты Dash определены в отдельных файлах.

Почему?


О: Планируется использовать Flask для основного веб-сайта и функций, а Dash - для интерактивных графиков и HTML-макетов.

Попытка решения:


Ниже приведен код из flask_app.py, и я прокомментировал его как можно лучше.

''' 
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)

Привет, Мони. Удачи?

Mangesh 18.10.2018 15:42

Потом не пробовал. Базовый сайт и информационные панели остались такими же, как и в Dash.

Moni 30.10.2018 04:16

Если вы переключаете ввод страницы в d_app, и целевой URL-адрес изменяется, запускается ли обратный вызов приложения flask для этого URL-адреса?

bmc 31.05.2020 16:35

Аналогичная проблема решается здесь stackoverflow.com/questions/61893445/…

Rafael Valero 27.09.2020 12:55

Интересной альтернативой может быть запуск приложений в разных портах и ​​их 1) создание прокси 2) встраивание приложений: как здесь: community.plotly.com/t/…. Работаю со вторым.

Rafael Valero 27.09.2020 17:19

Другой возможностью может быть "промежуточное ПО", как здесь: peterspython.com/en/blog/…, но я еще не пробовал это полностью.

Rafael Valero 27.09.2020 17:36
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
4
6
3 775
0

Другие вопросы по теме