Halaman refresh Python Dash tidak mengupdate data sumber
Saya telah menulis aplikasi garis petak dasar yang menarik data dari csv dan menampilkannya pada grafik. Anda kemudian dapat mengubah nilai pada aplikasi dan pembaruan grafik.
Namun, ketika saya menambahkan data baru ke csv (dilakukan sekali setiap hari) aplikasi tidak memperbarui data saat memuat ulang halaman.
Perbaikannya biasanya adalah Anda mendefinisikan Anda app.layout
sebagai fungsi, seperti yang diuraikan di sini (gulir ke bawah untuk pembaruan pada pemuatan halaman). Anda akan melihat dalam kode saya di bawah ini bahwa saya telah melakukannya.
Ini kode saya:
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)
Hal-hal yang telah saya coba
- Menghapus inisial
df = pd.read_csv(path)
sebelumdef layout_function():
. Ini menghasilkan kesalahan. - Membuat tombol callback untuk menyegarkan data menggunakan kode ini:
@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')
Ini tidak menghasilkan kesalahan, tetapi tombolnya juga tidak menyegarkan data.
- Mendefinisikan
df
dalamupdate_graph
panggilan balik. Ini memperbarui data setiap kali Anda beralih sesuatu, yang tidak praktis (data asli saya adalah> 10 ^ 6 baris, jadi saya tidak ingin membacanya setiap kali pengguna mengubah nilai toggle)
Singkatnya, saya pikir mendefinisikan app.layout = layout_function
harus membuat ini berhasil, tetapi ternyata tidak. Apa yang saya lewatkan / tidak lihat?
Hargai bantuan apapun.
Jawaban
TLDR; Saya menyarankan agar Anda cukup memuat data dari dalam callback. Jika waktu buka terlalu lama, Anda dapat mengubah format (mis. Menjadi bulu ) dan / atau mengurangi ukuran data melalui pemrosesan awal. Jika ini masih belum cukup cepat, langkah selanjutnya adalah menyimpan data di cache dalam memori sisi server seperti Redis .
Karena Anda menugaskan ulang df
dan df2
dalam layout_function
, variabel ini dianggap lokal dalam Python , dan dengan demikian Anda tidak memodifikasi variabel df
dan df2
dari ruang lingkup global. Meskipun Anda dapat mencapai perilaku ini menggunakan kata kunci global , penggunaan variabel global tidak disarankan di Dash .
Pendekatan standar di Dash akan memuat data dalam callback (atau di layout_function
) dan menyimpannya dalam Store
objek (atau yang sama, tersembunyi Div
). Strukturnya akan seperti ini
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)
...
Namun, pendekatan ini biasanya akan jauh lebih lambat daripada hanya membaca data dari disk di dalam callback (yang tampaknya menjadi apa yang Anda coba hindari) karena menghasilkan data yang ditransfer antara server dan klien.