python - 如何在 Dash Plotly 中将 Long_callback 与多页应用程序一起使用?

标签 python plotly plotly-dash

我正在尝试构建一个具有长回调的多页面 Dash 应用程序。当我使用单页应用程序运行应用程序时,它工作正常。下面给出工作代码

单页.py

import json
import dash
from dash import html, dcc
from dash.long_callback import DiskcacheLongCallbackManager
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import datetime
import pandas as pd
import plotly.express as px

## Diskcache
import diskcache

from query_4_entity_explr import get_ORG_info, get_daterange_entity_dataframe

cache = diskcache.Cache("./cache")
long_callback_manager = DiskcacheLongCallbackManager(cache)

app = dash.Dash("topx_org",
                long_callback_manager=long_callback_manager,
                external_stylesheets=[dbc.themes.BOOTSTRAP],
                meta_tags=[{'name': 'viewport', 'content': 'initial-scale=1'}])

today = datetime.datetime.today().date()
date_30_day_back = (datetime.datetime.today() - datetime.timedelta(days=1)).date()

app.layout = dbc.Container([
    dbc.Row([
        dbc.Col(html.H3("Explore Organizations mentioned in media", className='text-center text-primary py-5'), width=12)
    ]),
    dbc.Row([
        dbc.Col(dbc.Label(['Select daterange']), width={'size': 2, 'offset': 0}),
        dbc.Col(dcc.DatePickerRange(id='input_date_picker_range', display_format='YYYY-MM-DD', start_date=date_30_day_back, end_date=today), width={'size':10, 'offset':0}),
    ], justify='around', className='mb-1'),
    dbc.Row([
        dbc.Col(dbc.Label(['Choose Companies with mention count']), width=2),
        dbc.Col(dcc.Dropdown(id = "input_item_dropdown", options =  [], value=[], multi=True), width=10),

    ], justify='around', className='mb-1'),
    # dbc.Row(dbc.Button(id="cancel_button_id", children="Cancel Running Job!")),
    dbc.Row([
        dbc.Col(html.Div(id="output_text", children=[]), width={'size':10, 'offset':2}),

    ], justify='around', className='py-3'),

    dbc.Row([
                html.Progress(id="progress_bar"),
            ]),

    dbc.Row([

        dbc.Col(dcc.Graph(id='output_graph', figure={}), width=12),

    ], justify='around', className='py-5'),

    dcc.Store(id='stored-dataframe')
])


@app.long_callback(
    [Output(component_id='output_text', component_property='children'),
     Output(component_id="input_item_dropdown", component_property="options"),
     Output(component_id='stored-dataframe', component_property='data'),
     ],
    [Input(component_id="input_date_picker_range", component_property="start_date"),
     Input(component_id="input_date_picker_range", component_property="end_date"),
     ],
    manager=long_callback_manager,
    running=[
        (Output("output_text", "disabled"), False, True),
        (
            Output("output_graph", "style"),
            {"visibility": "hidden"},
            {"visibility": "visible"},
        ),
        (
            Output("progress_bar", "style"),
            {"visibility": "visible"},
            {"visibility": "hidden"},
        ),
    ],
)


def update_figure(start_date, end_date):

    print(start_date)
    print(end_date)

    # Data Acquisition
    TOP_N = 20
    unique_org_list, top_companys, org_gp_pdf = get_ORG_info(get_daterange_entity_dataframe(start_date,end_date), TOP_N)

    # For the div
    # _text = str(f"Between {start_date} to {end_date} for all the organizations : { ', '.join (item_list_value) }")
    _text = str(f"Between {start_date} to {end_date} there are {len(unique_org_list)} organizations mentioned in media.")

    # Store the data in browser storage.
    datasets = {
        'so_1': org_gp_pdf.to_json(orient='split', date_format='iso'),
        'so_2': top_companys,
    }

    return [_text], [{'label': str(c[0]) + f"  ({c[1]})", 'value': str(c[0])} for c in unique_org_list[0:]], json.dumps(datasets)


@app.callback(
    [Output(component_id='output_graph', component_property='figure')],
    [Input(component_id="input_item_dropdown", component_property="value"),
     Input(component_id='stored-dataframe', component_property='data')
    ],
    progress=[Output("progress_bar", "value"), Output("progress_bar", "max")],
)

def update_graph_2(item_list_value, jsonified_cleaned_data):
    # Load the stored DF and List from Browser storage
    datasets = json.loads(jsonified_cleaned_data)
    df_2 = pd.read_json(datasets['so_1'], orient='split')
    top_companys = datasets['so_2']

    if len(item_list_value) == 0:
        fig = px.bar( df_2[df_2.ORG.isin(top_companys)].sort_values(['NEWS_DATE'], ascending=True), title=f"Showing top {len(top_companys)} organizations", x="NEWS_DATE", y="COUNT", color="ORG", barmode="group")  # .query("ORG=='Mentice' | ORG=='Isofol Medical AB'")
    else:
        queryString = " | ".join([f"ORG=='{item}'" for item in item_list_value])
        fig = px.bar(df_2.query(queryString).sort_values(['NEWS_DATE'], ascending=True) ,title=f"Showing some selected organizations", x="NEWS_DATE", y="COUNT", color="ORG", barmode="group")  # .query("ORG=='Mentice' | ORG=='Isofol Medical AB'")
        # align title
    fig.update_layout(title_x=0.5, xaxis=dict(title_text='NEWS PUBLISH DATE'), yaxis=dict(title_text='DAILY ORG MENTION COUNT '))
    return [fig]


if _name_ == "__main__":
    app.run_server(port=8050, debug=False)

但是当我尝试在多页面结构中运行相同的应用程序时,它显示@long_callback不可调用。 在多页结构中,我的主应用程序文件如下所示 应用程序.py


from pages import topx_org, topx_per

import dash
from dash import html, dcc
from dash.long_callback import DiskcacheLongCallbackManager
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc


## Diskcache
import diskcache


cache = diskcache.Cache("./cache")
long_callback_manager = DiskcacheLongCallbackManager(cache)

app = dash.Dash(__name__,
           suppress_callback_exceptions=True,
           long_callback_manager=long_callback_manager,
           external_stylesheets=[dbc.themes.BOOTSTRAP],
           meta_tags=[{'name': 'viewport', 'content': 'initial-scale=1'}])

server = app.server

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


@app.callback(Output('page-content', 'children'),
              Input('url', 'pathname'))
def display_page(pathname):
    if pathname == '/topx_org':
        return topx_org.layout
    elif pathname == '/topx_per':
        return topx_per.layout
    else:
        return '404'


if _name_ == '__main__':
    app.run_server(debug=True)

下面给出了 topx_org.py

from dash import callback, long_callback
import json
from dash import html, dcc
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import datetime
import pandas as pd
import plotly.express as px
from query_4_entity_explr import get_ORG_info, get_daterange_entity_dataframe

today = datetime.datetime.today().date()
date_30_day_back = (datetime.datetime.today() - datetime.timedelta(days=1)).date()

layout = dbc.Container([
    dbc.Row([
        dbc.Col(html.H3("Explore Organizations mentioned in media", className='text-center text-primary py-5'), width=12)
    ]),
    dbc.Row([
        dbc.Col(dbc.Label(['Select daterange' ]), width={'size':2, 'offset':0}),
        dbc.Col(dcc.DatePickerRange(id='input_date_picker_range', display_format='YYYY-MM-DD',start_date=date_30_day_back, end_date=today), width={'size':10, 'offset':0}),

    ], justify='around', className='mb-1'),
    dbc.Row([
        dbc.Col(dbc.Label(['Choose Companies with mention count']), width=2),
        dbc.Col(dcc.Dropdown(id = "input_item_dropdown", options =  [], value=[], multi=True), width=10),

    ], justify='around', className='mb-1'),
    dbc.Row([
        dbc.Col(html.Div(id="output_text", children=[]), width={'size':10, 'offset':2}),

    ], justify='around', className='py-3'),

    dbc.Row([

        dbc.Col(dcc.Graph(id='output_graph', figure={}), width=12),

    ], justify='around', className='py-5'),

    dcc.Store(id='stored-dataframe')
])


# Output(component_id='output_graph', component_property='figure'),
@callback(
    [Output(component_id='output_text', component_property='children'),
     Output(component_id="input_item_dropdown", component_property="options"),
     Output(component_id='stored-dataframe', component_property='data'),
     ],
    [Input(component_id="input_date_picker_range", component_property="start_date"),
     Input(component_id="input_date_picker_range", component_property="end_date"),
     ],
    progress=[Output("progress_bar", "value"), Output("progress_bar", "max")],
)

def update_figure(start_date, end_date):
    print(start_date)
    print(end_date)
    # print(item_list_value)

    # Data Acquisition
    TOP_N = 20
    unique_org_list, top_companys, org_gp_pdf = get_ORG_info(get_daterange_entity_dataframe(start_date,end_date), TOP_N)

    # For the div
    # _text = str(f"Between {start_date} to {end_date} for all the organizations : { ', '.join (item_list_value) }")
    _text = str(f"Between {start_date} to {end_date} there are {len(unique_org_list)} organizations mentioned in media.")

    # Store the data in browser storage.
    datasets = {
        'so_1': org_gp_pdf.to_json(orient='split', date_format='iso'),
        'so_2': top_companys,
    }

    return [_text], [{'label': str(c[0]) + f"  ({c[1]})", 'value': str(c[0])} for c in unique_org_list[0:]], json.dumps(datasets)


@long_callback(
    [Output(component_id='output_graph', component_property='figure')],
    [Input(component_id="input_item_dropdown", component_property="value"),
     Input(component_id='stored-dataframe', component_property='data')
    ],
    running=[
        (Output("output_text", "disabled"), False, True),
        (
            Output("output_graph", "style"),
            {"visibility": "hidden"},
            {"visibility": "visible"},
        ),
        (
            Output("progress_bar", "style"),
            {"visibility": "visible"},
            {"visibility": "hidden"},
        ),
    ],
)
def update_graph_2(item_list_value, jsonified_cleaned_data):
    # Load the stored DF and List from Browser storage
    datasets = json.loads(jsonified_cleaned_data)
    df_2 = pd.read_json(datasets['so_1'], orient='split')
    top_companys = datasets['so_2']

    if len(item_list_value) == 0:
        fig = px.bar( df_2[df_2.ORG.isin(top_companys)].sort_values(['NEWS_DATE'], ascending=True), title=f"Showing top {len(top_companys)} organizations", x="NEWS_DATE", y="COUNT", color="ORG", barmode="group")  # .query("ORG=='Mentice' | ORG=='Isofol Medical AB'")
    else:
        queryString = " | ".join([f"ORG=='{item}'" for item in item_list_value])
        fig = px.bar(df_2.query(queryString).sort_values(['NEWS_DATE'], ascending=True) ,title=f"Showing some selected organizations", x="NEWS_DATE", y="COUNT", color="ORG", barmode="group")  # .query("ORG=='Mentice' | ORG=='Isofol Medical AB'")
        # align title
    fig.update_layout(title_x=0.5, xaxis=dict(title_text='NEWS PUBLISH DATE'), yaxis=dict(title_text='DAILY ORG MENTION COUNT '))
    return [fig]

我遇到以下错误

 @long_callback(
TypeError: 'module' object is not callable

最佳答案

(更新)根据this post ,这还不可能,因为 long_callback 需要应用程序对象(@app.long_callback)。如果您尝试在页面文件中导入应用程序对象,则会创建循环导入,从而导致错误。

帖子中提到的唯一可能性是将所有长回调放在 app.py 文件中。 “正常”回调和布局可以保留在页面文件中。

关于python - 如何在 Dash Plotly 中将 Long_callback 与多页应用程序一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71885905/

相关文章:

python - Selenium python : get all the <li> text of all the <ul> from a <div>

python-3.x - Python Dash 数据表应仅显示选定的列

python - 如何使用 VSCode 调试 JupyterDash 应用程序?

python - 我在哪里可以找到 QGIS 的所有 python 函数的概述

Python网络编程项目?

python - 尝试使用 Python 从联网设备上的 TCP 套接字连接获取数据

python - Plotly-Dash:为每个选定的 df 列添加新的 y 轴

Python:如何为 Pandas DataFrame 创建带有离线绘图的阶梯图?

python - 如何在 python 中创建交互式绘图,根据我单击的位置生成新绘图?

python - 水平对齐破折号核心组件