dash的回調(diào)機(jī)制是基于組件的輸入(input)和輸出(output)。當(dāng)一個(gè)組件的屬性被指定為input時(shí),其值的改變會(huì)觸發(fā)回調(diào)函數(shù)的執(zhí)行。而state則允許回調(diào)函數(shù)訪問某個(gè)組件的當(dāng)前值,但該組件值的改變并不會(huì)觸發(fā)回調(diào)。
在實(shí)際應(yīng)用中,我們常常遇到以下場景:
直接將輸入框的值作為第二個(gè)回調(diào)的Input是不可行的,因?yàn)槎〞r(shí)器回調(diào)會(huì)被輸入框的每次輸入而非提交按鈕的點(diǎn)擊觸發(fā),或者如果作為State,則無法在輸入改變時(shí)獲取到最新值。此時(shí),dcc.Store便成為了理想的解決方案。
dcc.Store是Dash提供的一個(gè)用于在客戶端瀏覽器中存儲(chǔ)數(shù)據(jù)的組件。它可以存儲(chǔ)字符串、數(shù)字、列表或字典等JSON可序列化的數(shù)據(jù)。dcc.Store的優(yōu)勢在于:
我們將通過一個(gè)具體的例子來演示如何實(shí)現(xiàn)這一過程。假設(shè)我們有一個(gè)應(yīng)用,用戶輸入一個(gè)股票代碼并提交后,該代碼被存儲(chǔ),然后一個(gè)實(shí)時(shí)更新的圖表需要讀取這個(gè)股票代碼來顯示數(shù)據(jù)。
首先,在應(yīng)用布局中添加必要的組件:一個(gè)文本輸入框、一個(gè)提交按鈕、一個(gè)用于顯示輸入結(jié)果的div、一個(gè)dcc.Store組件以及一個(gè)用于顯示圖表的dcc.Graph和一個(gè)dcc.Interval定時(shí)器。
from dash import Dash, dcc, html, Input, Output, callback, State app = Dash(__name__) # 示例數(shù)據(jù),實(shí)際應(yīng)用中可能從數(shù)據(jù)庫或API獲取 symbols = ['AAPL', 'GOOG', 'MSFT', 'AMZN'] inter = 1000 # 定時(shí)器間隔,單位毫秒 app.layout = html.Div([ dcc.Graph(id='graph'), dcc.Interval( id='interval', interval=inter, n_intervals=0, ), html.Div([ dcc.Input(id='input-on-submit', type='text', placeholder='輸入股票代碼'), html.Button('提交', id='submit-val', n_clicks=0), ]), html.Div(id='container-button-basic', children='請輸入一個(gè)股票代碼并點(diǎn)擊提交'), dcc.Store(id='stkName-value', data=None) # 初始化dcc.Store ])
這個(gè)回調(diào)負(fù)責(zé)接收用戶在dcc.Input中輸入的值,并在用戶點(diǎn)擊html.Button后,將其處理(例如轉(zhuǎn)換為大寫并驗(yàn)證)后存儲(chǔ)到dcc.Store中。
@callback( Output('stkName-value', 'data'), Output('container-button-basic', 'children'), Input('submit-val', 'n_clicks'), State('input-on-submit', 'value'), prevent_initial_call=True # 避免應(yīng)用啟動(dòng)時(shí)立即觸發(fā) ) def update_output(n_clicks, value): """ 處理用戶輸入,驗(yàn)證后存儲(chǔ)到 dcc.Store。 """ if n_clicks is None or value is None: # 初始加載或沒有輸入時(shí),不執(zhí)行邏輯 return None, '請輸入一個(gè)股票代碼并點(diǎn)擊提交' processed_value = str(value).upper() if processed_value in symbols: print(f'輸入的股票代碼是: "{processed_value}"') # 將處理后的值存儲(chǔ)到 'stkName-value' 的 'data' 屬性中 return processed_value, f'已接受股票代碼: {processed_value}' else: # 如果輸入不合法,可以存儲(chǔ)一個(gè)默認(rèn)值或None,并給出提示 return None, f'股票代碼 "{processed_value}" 不被接受,請嘗試其他代碼。'
關(guān)鍵點(diǎn):
這個(gè)回調(diào)由dcc.Interval定時(shí)器觸發(fā),它需要讀取dcc.Store中存儲(chǔ)的股票代碼,然后用它來更新圖表。
基于AI數(shù)字人能力,實(shí)現(xiàn)7*24小時(shí)AI數(shù)字人直播帶貨,低成本實(shí)現(xiàn)直播業(yè)務(wù)快速增增,全天智能在線直播
import plotly.graph_objects as go @callback( Output('graph', 'figure'), Input('interval', 'n_intervals'), State('stkName-value', 'data') # 使用State獲取dcc.Store中的數(shù)據(jù) ) def update_graph_live(n_intervals, stored_stock_name): """ 根據(jù)存儲(chǔ)的股票代碼實(shí)時(shí)更新圖表。 """ if stored_stock_name is None: # 如果dcc.Store中沒有有效數(shù)據(jù),返回一個(gè)空圖表或提示信息 return go.Figure().update_layout( title="請先輸入并提交有效的股票代碼", xaxis_title="", yaxis_title="" ) print(f"定時(shí)器觸發(fā),正在為 {stored_stock_name} 更新圖表 (n_intervals: {n_intervals})") # 模擬獲取實(shí)時(shí)數(shù)據(jù) # 實(shí)際應(yīng)用中,這里會(huì)根據(jù) stored_stock_name 從API或數(shù)據(jù)庫獲取數(shù)據(jù) x_data = list(range(n_intervals, n_intervals + 10)) y_data = [i * 0.5 + (n_intervals % 5) for i in x_data] figure = go.Figure( data=[go.Scatter(x=x_data, y=y_data, mode='lines+markers', name=stored_stock_name)], layout=go.Layout( title=f'{stored_stock_name} 實(shí)時(shí)數(shù)據(jù)', xaxis_title='時(shí)間', yaxis_title='值', uirevision=stored_stock_name # 保持圖表狀態(tài),防止每次更新時(shí)重置縮放等 ) ) return figure
關(guān)鍵點(diǎn):
原問題中提到的IndexError: list index out of range通常發(fā)生在Dash回調(diào)函數(shù)的參數(shù)與聲明的Input和State組件數(shù)量或順序不匹配時(shí)。Dash內(nèi)部會(huì)根據(jù)Input和State的聲明順序,將對應(yīng)的值作為參數(shù)傳遞給回調(diào)函數(shù)。如果函數(shù)定義的參數(shù)數(shù)量少于或多于聲明的組件數(shù)量,或者順序不一致,就會(huì)導(dǎo)致這種索引錯(cuò)誤。
在上述的第二個(gè)回調(diào)update_graph_live中,如果最初只聲明了Input('interval', 'n_intervals'),而函數(shù)卻定義了兩個(gè)參數(shù)update_graph_live(n_intervals, data),那么data參數(shù)將無法找到對應(yīng)的輸入/狀態(tài)組件,從而引發(fā)IndexError。
通過正確地添加State('stkName-value', 'data')到update_graph_live回調(diào)的裝飾器中,并確保回調(diào)函數(shù)簽名def update_graph_live(n_intervals, stored_stock_name):與Input和State的順序和數(shù)量完全匹配,即可有效解決此問題。
將上述所有代碼片段組合起來,形成一個(gè)完整的Dash應(yīng)用:
from dash import Dash, dcc, html, Input, Output, callback, State import plotly.graph_objects as go app = Dash(__name__) # 示例數(shù)據(jù),實(shí)際應(yīng)用中可能從數(shù)據(jù)庫或API獲取 symbols = ['AAPL', 'GOOG', 'MSFT', 'AMZN'] inter = 1000 # 定時(shí)器間隔,單位毫秒 app.layout = html.Div([ dcc.Graph(id='graph'), dcc.Interval( id='interval', interval=inter, n_intervals=0, ), html.Div([ dcc.Input(id='input-on-submit', type='text', placeholder='輸入股票代碼'), html.Button('提交', id='submit-val', n_clicks=0), ]), html.Div(id='container-button-basic', children='請輸入一個(gè)股票代碼并點(diǎn)擊提交'), dcc.Store(id='stkName-value', data=None) # 初始化dcc.Store ]) @callback( Output('stkName-value', 'data'), Output('container-button-basic', 'children'), Input('submit-val', 'n_clicks'), State('input-on-submit', 'value'), prevent_initial_call=True ) def update_output(n_clicks, value): """ 處理用戶輸入,驗(yàn)證后存儲(chǔ)到 dcc.Store。 """ if n_clicks is None or value is None: return None, '請輸入一個(gè)股票代碼并點(diǎn)擊提交' processed_value = str(value).upper() if processed_value in symbols: print(f'輸入的股票代碼是: "{processed_value}"') return processed_value, f'已接受股票代碼: {processed_value}' else: return None, f'股票代碼 "{processed_value}" 不被接受,請嘗試其他代碼。' @callback( Output('graph', 'figure'), Input('interval', 'n_intervals'), State('stkName-value', 'data') # 使用State獲取dcc.Store中的數(shù)據(jù) ) def update_graph_live(n_intervals, stored_stock_name): """ 根據(jù)存儲(chǔ)的股票代碼實(shí)時(shí)更新圖表。 """ if stored_stock_name is None: return go.Figure().update_layout( title="請先輸入并提交有效的股票代碼", xaxis_title="", yaxis_title="" ) print(f"定時(shí)器觸發(fā),正在為 {stored_stock_name} 更新圖表 (n_intervals: {n_intervals})") # 模擬獲取實(shí)時(shí)數(shù)據(jù) x_data = list(range(n_intervals, n_intervals + 10)) y_data = [i * 0.5 + (n_intervals % 5) for i in x_data] figure = go.Figure( data=[go.Scatter(x=x_data, y=y_data, mode='lines+markers', name=stored_stock_name)], layout=go.Layout( title=f'{stored_stock_name} 實(shí)時(shí)數(shù)據(jù)', xaxis_title='時(shí)間', yaxis_title='值', uirevision=stored_stock_name # 保持圖表狀態(tài),防止每次更新時(shí)重置縮放等 ) ) return figure if __name__ == '__main__': app.run_server(debug=True)
通過熟練運(yùn)用dcc.Store結(jié)合Input和State,開發(fā)者可以構(gòu)建出更復(fù)雜、更靈活的Dash應(yīng)用,實(shí)現(xiàn)高效的跨回調(diào)數(shù)據(jù)共享和用戶體驗(yàn)。
以上就是在Plotly Dash應(yīng)用中通過dcc.Store實(shí)現(xiàn)跨回調(diào)數(shù)據(jù)傳遞的詳細(xì)內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!
每個(gè)人都需要一臺速度更快、更穩(wěn)定的 PC。隨著時(shí)間的推移,垃圾文件、舊注冊表數(shù)據(jù)和不必要的后臺進(jìn)程會(huì)占用資源并降低性能。幸運(yùn)的是,許多工具可以讓 Windows 保持平穩(wěn)運(yùn)行。
微信掃碼
關(guān)注PHP中文網(wǎng)服務(wù)號
QQ掃碼
加入技術(shù)交流群
Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號