簡體   English   中英

Python Dash 刷新頁面未更新源數據

[英]Python Dash refresh page not updating source data

我編寫了一個基本的 plotly dash 應用程序,它從 csv 中提取數據並將其顯示在圖表上。 然后,您可以在應用程序上切換值並更新圖表。

但是,當我向 csv 添加新數據(每天完成一次)時,應用程序不會在刷新頁面時更新數據。

解決方法通常是將app.layout定義為 function,如此所述(向下滾動以在頁面加載時更新)。 您會在下面的代碼中看到我已經做到了。

這是我的代碼:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import numpy as np

import pandas as pd

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

path = 'https://raw.githubusercontent.com/tbuckworth/Public/master/CSVTest.csv'

df = pd.read_csv(path)
df2 = df[(df.Map==df.Map)]


def layout_function():

    df = pd.read_csv(path)
    df2 = df[(df.Map==df.Map)]
    
    available_strats = np.append('ALL',pd.unique(df2.Map.sort_values()))
    classes1 = pd.unique(df2["class"].sort_values())
    metrics1 = pd.unique(df2.metric.sort_values())
    
    return html.Div([
            html.Div([
                dcc.Dropdown(
                    id="Strategy",
                    options=[{"label":i,"value":i} for i in available_strats],
                    value=list(available_strats[0:1]),
                    multi=True
                ),
                dcc.Dropdown(
                    id="Class1",
                    options=[{"label":i,"value":i} for i in classes1],
                    value=classes1[0]
                ),
                dcc.Dropdown(
                    id="Metric",
                    options=[{"label":i,"value":i} for i in metrics1],
                    value=metrics1[0]
                )],
            style={"width":"20%","display":"block"}),
                
        html.Hr(),
    
        dcc.Graph(id='Risk-Report')          
    ])
            
app.layout = layout_function


@app.callback(
        Output("Risk-Report","figure"),
        [Input("Strategy","value"),
         Input("Class1","value"),
         Input("Metric","value"),
         ])

def update_graph(selected_strat,selected_class,selected_metric):
    if 'ALL' in selected_strat:
        df3 = df2[(df2["class"]==selected_class)&(df2.metric==selected_metric)]
    else:
        df3 = df2[(df2.Map.isin(selected_strat))&(df2["class"]==selected_class)&(df2.metric==selected_metric)]
    df4 = df3.pivot_table(index=["Fund","Date","metric","class"],values="value",aggfunc="sum").reset_index()
    traces = []
    for i in df4.Fund.unique():
        df_by_fund = df4[df4["Fund"] == i]
        traces.append(dict(
                x=df_by_fund["Date"],
                y=df_by_fund["value"],
                mode="lines",
                name=i
                ))
    
    if selected_class=='USD':
        tick_format=None
    else:
        tick_format='.2%'
    
    return {
            'data': traces,
            'layout': dict(
                xaxis={'type': 'date', 'title': 'Date'},
                yaxis={'title': 'Values','tickformat':tick_format},
                margin={'l': 40, 'b': 40, 't': 10, 'r': 10},
                legend={'x': 0, 'y': 1},
                hovermode='closest'
            )
        }
    

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

我試過的事情

  1. def layout_function():之前刪除初始df = pd.read_csv(path) 這會導致錯誤。
  2. 使用此代碼創建回調按鈕以刷新數據:
@app.callback(
        Output('Output-1','children'),
        [Input('reload_button','n_clicks')]        
        )

def update_data(nclicks):
    if nclicks == 0:
        raise PreventUpdate
    else:
        df = pd.read_csv(path)
        df2 = df[(df.Map==df.Map)]
        return('Data refreshed. Click to refresh again')

這不會產生錯誤,但按鈕也不會刷新數據。

  1. update_graph回調中定義df 這會在您每次切換某些內容時更新數據,這是不切實際的(我的真實數據是 > 10^6 行,所以我不想每次用戶更改切換值時都讀取它)

簡而言之,我認為定義app.layout = layout_function應該可以完成這項工作,但事實並非如此。 我錯過/沒有看到什么?

感謝任何幫助。

TLDR; 我建議您只需從回調中加載數據。 如果加載時間太長,您可以更改格式(例如更改為feather )和/或通過預處理減小數據大小。 如果這仍然不夠快,下一步是將數據存儲在服務器端內存緩存中,例如Redis


由於您在 layout_function 中重新分配dfdf2 ,這些變量在layout_function中被視為局部變量,因此您不會修改全局 scope 中的dfdf2變量。雖然您可以使用global 關鍵字實現此行為,但使用 global在 Dash 中不鼓勵使用變量

Dash 中的標准方法是在回調中(或在layout_function中)加載數據並將其存儲在Store object(或等效地,隱藏的Div中)。 結構類似於

import pandas as pd
import dash_core_components as dcc
from dash.dependencies import Output, Input

app.layout = html.Div([
    ...
    dcc.Store(id="store"), html.Div(id="trigger")
])

@app.callback(Output('store','data'), [Input('trigger','children')], prevent_initial_call=False)
def update_data(children):
    df = pd.read_csv(path)
    return df.to_json()

@app.callback(Output("Risk-Report","figure"), [Input(...)], [State('store', 'data')])
def update_graph(..., data):
    if data is None:
        raise PreventUpdate
    df = pd.read_json(data)
    ...

但是,這種方法通常比僅在回調中從磁盤讀取數據(這似乎是您試圖避免的)得多,因為它會導致數據在服務器和客戶端之間傳輸。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM