【问题标题】:Python dash return several values inside for loopPython dash 在 for 循环中返回几个值
【发布时间】:2023-02-20 16:43:09
【问题描述】:

对于我的 dash 应用程序,为了动态更新一些图形,我必须在 for 循环中使用一个名为 update_graphs 的函数。一些图表包含多条轨迹,而另一些图表只有一条。 update_graphs 函数在回调中被调用并返回一个dict 和一个int 以更新graph 对象的extendData 属性。但是,由于我在 for 循环中使用 return 语句,所以我只得到第一条轨迹。

我不熟悉生成器和 yield 关键字,也许这是一个选项。但我没能让它发挥作用。

我还尝试将 update_graphs 的结果存储在列表中,但它不起作用。

任何帮助表示赞赏!

这是应用程序的代码:

import dash
from dash.dependencies import Output, Input, State, MATCH, ALL
from dash import dcc, html, ctx
import plotly
import plotly.express as px
import random
import plotly.graph_objs as go
import pandas as pd
  
# Initializing the data with the correct format
init_store = {}
n=3

init_df = pd.DataFrame({'a':pd.Series(dtype='int'), 'b':pd.Series(dtype='int'), 'c':pd.Series(dtype='int'), 'd':pd.Series(dtype='int')}, index=range(50))
init_df['a'] = init_df.index
init_store['0'] = init_df

for i in range(n):
    init_df = pd.DataFrame({'a':pd.Series(dtype='int'), 'b':pd.Series(dtype='int')}, index=range(50))
    init_df['a'] = init_df.index
    init_store[f'{i+1}'] = init_df

# Function to update the dataframes with the new observations
def get_data(json_data):
    df = pd.read_json(json_data)
    compteur = df['a'][len(df['a'])-1]
    if len(df.columns) > 2:
        new_row = {'a':compteur + 1, 'b':random.randint(13,26), 'c':random.randint(13,26), 'd':random.randint(13,26)}
    else:
        new_row = {'a':compteur + 1, 'b':random.randint(13,26)}
    df = df.shift(periods=-1)
    df.iloc[len(df)-1] = new_row

    return(df.to_json())

# Function to update the graphs based on the dataframes
def update_graphs(json_data, column, index=0):
    
    df = pd.read_json(json_data)
    nb_obs = df.shape[0]
    x_new = df['a'][len(df)-1]        
    y_new = df[column][nb_obs-1]

    return dict(x=[[x_new]], y=[[y_new]]), index

colors = px.colors.qualitative.G10

def generate_graph_containers(index, json_data):

    dataframe = pd.read_json(json_data)
    X = dataframe['a']
    Y = dataframe.loc[:, dataframe.columns != 'a']
    graph_id = {'type': 'graph-', 'index': index}

    
    return( 
        html.Div(
            html.Div(
            dcc.Graph(
                id=graph_id,
                style={"height": "8rem"},
                config={
                    "staticPlot": False,
                    "editable": False,
                    "displayModeBar": False,
                },
                figure=go.Figure(
                            {
                                "data": [
                                    {
                                        "x": list(X),
                                        "y": list(Y[Y.columns[i]]),
                                        "mode": "lines",
                                        "name": Y.columns[i],
                                        "line": {"color": colors[i+2]},
                                    }
                                    for i in range(len(Y.columns))
                                ],
                                "layout": {
                                    "uirevision": True,
                                    "margin": dict(l=0, r=0, t=4, b=4, pad=0),
                                    "xaxis": dict(
                                        showline=False,
                                        showgrid=False,
                                        zeroline=False,
                                        showticklabels=False,
                                    ),
                                    "yaxis": dict(
                                        showline=False,
                                        showgrid=False,
                                        zeroline=False,
                                        showticklabels=False,
                                    ),
                                    "paper_bgcolor": "rgba(0,0,0,0)",
                                    "plot_bgcolor": "rgba(0,0,0,0)",
                                }
                            }
                        )
            )
        )
        )
    )

app = dash.Dash(__name__)

store = [dcc.Store(id={'type':'store-', 'index':i}, data=init_store[str(i)].to_json()) for i in range(n)]

def make_layout(): 
    return(
            html.Div(
        [   
            html.Div(
                store
            ),

            dcc.Interval(
                id = 'interval',
                interval = 1000,
                n_intervals = 0
            ),

            html.Div(
                [
                    generate_graph_containers(str(i), store[i].data) for i in range(n)
                ] 
            )
            
        ]
    )
)

app.layout = make_layout

@app.callback(
    Output(component_id={'type':'store-', 'index':MATCH}, component_property='data'),
    [ 
        Input('interval', 'n_intervals'),
        State(component_id={'type':'store-', 'index':MATCH}, component_property='data') 
    ]
)
def update_data(time, data):
    return(get_data(data))


@app.callback(
    Output(component_id={'type':'graph-', 'index':MATCH}, component_property='extendData'),
    Input(component_id={'type':'store-', 'index':MATCH}, component_property="data")
)
def update_graphs_callback(data):
    triggered_id = ctx.triggered_id
    print(triggered_id['index'])
    columns = ['b', 'c', 'd']

    if triggered_id['index'] == 0:
        for i in range(len(columns)):
            return(update_graphs(data, columns[i], i))
    else:
        return(update_graphs(data, 'b'))
  
if __name__ == '__main__':
    app.run_server(debug=True)

【问题讨论】:

    标签: python for-loop callback return plotly-dash


    【解决方案1】:

    我想到了。诀窍在于预期更新图形的 extendData 属性的格式。当尝试更新多个跟踪时,格式应该是一个字典,其中一个键用于 x 值,一个键用于 y 值。关联的值应该是每个键的数组,每个跟踪包含一个数组。不要忘记在字典后添加跟踪索引。因此,例如,在 3 条不同的轨迹的情况下,该函数应返回如下内容:

    dict(x=[[x_0], [x_1], [x_2]], y=[[y_0], [y_1], [y_2]]), [0, 1, 2]
    

    因此 update_graphs 函数应该是:

    def update_graphs(json_data):
        
        df = pd.read_json(json_data)
        nb_obs = df.shape[0]
    
        x_new =  []  
        y_new = []
        trace_index = []
        for i in range(len(df.columns)-1):
            x_new.append([df['a'][len(df)-1]])
            y_new.append([df[df.columns[i+1]][nb_obs-1]])
            trace_index.append(i)
            
        return(dict(x=x_new, y=y_new), trace_index)
    

    并且更新图表的回调应更改为:

    @app.callback(
        Output(component_id={'type':'graph-', 'index':MATCH}, component_property='extendData'),
        Input(component_id={'type':'store-', 'index':MATCH}, component_property="data")
    )
    def update_graphs_callback(data):
        return(update_graphs(data))
    

    【讨论】:

      猜你喜欢
      • 2023-02-14
      • 2011-07-05
      • 2015-12-30
      • 2021-05-06
      • 2021-08-14
      • 1970-01-01
      • 2015-02-24
      • 2016-08-23
      • 2018-09-25
      相关资源
      最近更新 更多