在 Dash 应用程序中“就地”更新 Plotly FIgureWidget

问题描述 投票:0回答:1

考虑以下玩具 Python 类,它偶尔可以从某些源获取附加数据,并更新其显示:

# minimum_working_example.py
import plotly.graph_objects as go
import random

class MyData:
    def __init__(self):
        self.mydata = []
        self.figure = go.FigureWidget()
        self.figure.add_trace(go.Scatter(
            name = 'mydata',
        ))
        self.get_more_data()

    def get_more_data(self):
        self.mydata += [ random.random() for _ in range(10) ]
        self.figure.update_traces(
            selector=dict(name='mydata'),
            y = self.mydata,
            x = list(range(len(self.mydata))),
        )

如果我进入 Jupyter 笔记本并说出类似的话

# interactive jupyter prompt
from minimum_working_example import MyData
mydata = MyData()
display(mydata.figure)

然后我得到一个可以摆弄的图形:缩放轴、切换哪些迹线可见等。(我的非最小示例有多个迹线。)因为该图形是

FigureWidget
,所以调用
mydata.get_more_data()
会发生变化图表上的轨迹,但它不会改变任何其他特征。

[The thing in action1

我想将此显示从交互式笔记本移动到带有“获取更多数据”按钮的 Dash 应用程序,但到目前为止,我尝试过的所有操作都会导致该图形重置所有修改,而不是就地更新。这是一个以教育方式失败的示例,基于部分属性更新的文档页面:

# mwe_dash.py
from dash import Dash, html, dcc, Input, Output, Patch, callback
import plotly.graph_objects as go

import datetime
import random

import minimum_working_example

app = Dash(__name__)
mydata = minimum_working_example.MyData()

app.layout = html.Div(
    [
        html.Button("Append", id="append-new-val"),
        dcc.Graph(figure=mydata.figure, id="append-example-graph"),
    ]
)

@callback(
    Output("append-example-graph", "figure"),
    Input("append-new-val", "n_clicks"),
    prevent_initial_call=True,
)
def put_more_data_on_figure(n_clicks):
    mydata.get_more_data()
    return mydata.figure

if __name__ == "__main__":
    app.run(port=8056)

如果我用

python mwe_dash.py
单独运行它,那么每次我按下“获取更多数据”按钮时,该数字都会完全重置 - 就像上面文档页面上的示例一样。但如果我在 Jupyter 中运行它,使用

# in jupyter again
from mwe_dash import app, mydata
display(mydata.figure)
app.run(jupyter_server_url='localhost:8888',port=8057)

然后,当图形更新时,与 Jupyter 笔记本中图形的外观改变交互将应用到 Dash 应用程序中。但是,每次按下“获取更多数据”按钮时,Dash 应用程序中的数字都会重置为笔记本中的版本。

如何获取 Dash 应用程序中的图形以重现 Jupyter 笔记本中的更新而不重置行为?我假设我需要从图形到 Dash 应用程序进行一些额外的回调。即使我去掉了这个分析工具的笔记本部分,是否有必要在后台运行 Jupyter 服务器?

python jupyter-notebook plotly ipython plotly-dash
1个回答
0
投票
  1. 如果您想“将此显示从交互式笔记本移动到 Dash 应用程序”,请使用

    go.Figure()
    而不是
    go.FigureWidget()

  2. 您没有进行部分更新:

    fig.update_traces()
    更新后端的图形,回调只是返回它(整个图形),因此在客户端您会丢失先前加载的图形的状态。您应该使用
    Patch
    类来扩展 x 和 y 中的值列表。

  3. 不要在 MyData 类中创建/更新图形,只需创建/更新数据并在需要时使用它们(单一责任原则)。

class MyData:

    def __init__(self):
        self.data = []
        self.get_more_data()

    def get_more_data(self):
        newdata = [ random.random() for _ in range(10) ]
        self.data += newdata
        return newdata
app = Dash(__name__)

mydata = MyData()

y = mydata.data
x = list(range(len(y)))

fig = go.Figure(go.Scatter(x=x, y=y, name='mydata'))

app.layout = html.Div(
    [
        html.Button("Append", id="append-new-val"),
        dcc.Graph(figure=fig, id="append-example-graph"),
    ]
)

@callback(
    Output("append-example-graph", "figure"),
    Input("append-new-val", "n_clicks"),
    prevent_initial_call=True,
)
def put_more_data_on_figure(n_clicks):
    i = len(mydata.data)

    new_y = mydata.get_more_data()
    new_x = list(range(i, i+len(new_y)))

    patched_figure = Patch()
    patched_figure['data'][0]['x'].extend(new_x)
    patched_figure['data'][0]['y'].extend(new_y)

    return patched_figure

if __name__ == "__main__":
    app.run(debug=True)
© www.soinside.com 2019 - 2024. All rights reserved.