情节:如何用新数据更新/重绘情节表达图?

Posted

技术标签:

【中文标题】情节:如何用新数据更新/重绘情节表达图?【英文标题】:Plotly: How to update / redraw a plotly express figure with new data? 【发布时间】:2020-12-22 06:32:57 【问题描述】:

在调试或计算量大的循环期间,我想看看我的数据处理如何演变(例如在线图或图像中)。

在 matplotlib 中,代码可以使用plt.cla()plt.draw()plt.pause(0.001) 重新绘制/更新图形,这样我就可以实时或在调试时跟踪我的计算进度。我如何在情节表达(或情节)中做到这一点?

【问题讨论】:

我会调查plotly animations 该页面上的所有示例都使用预先计算的数据,只需将其显示为动画即可。通过调用生成器或迭代器来检索下一个数据点,可以将图形字典的 frames=[..] 部分内的计算外包。不确定。 【参考方案1】:

我不确定是否存在用于 plotly 的相同功能。但是您至少可以构建一个图形,扩展您的数据源,然后只需替换图形的数据,而无需触及任何其他图形元素,如下所示:

for i, col in enumerate(fig.data):
    fig.data[i]['y'] = df[df.columns[i]]
    fig.data[i]['x'] = df.index

您的图形是使用plotly.express 还是go.Figure 的结果无关紧要,因为这两种方法都会生成可以通过上面的代码sn-p 编辑的图形结构。您可以通过在 JupyterLab 的两个不同单元格中设置以下两个 sn-ps 来自行测试。

单元格 1 的代码

import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

# code and plot setup
# settings
pd.options.plotting.backend = "plotly"

# sample dataframe of a wide format
np.random.seed(5); cols = list('abc')
X = np.random.randn(50,len(cols))  
df=pd.DataFrame(X, columns=cols)
df.iloc[0]=0;df=df.cumsum()

# plotly figure
fig = df.plot(template = 'plotly_dark')
fig.show()

单元格 2 的代码

# create or retrieve new data
Y = np.random.randn(1,len(cols))

# organize new data in a df
df2 = pd.DataFrame(Y, columns = cols)

# add last row to df to new values
# this step can be skipped if your real world
# data is not a cumulative process like
# in this example
df2.iloc[-1] = df2.iloc[-1] + df.iloc[-1]

# append new data to existing df
df = df.append(df2, ignore_index=True)#.reset_index()

# replace old data in fig with new data
for i, col in enumerate(fig.data):
    fig.data[i]['y'] = df[df.columns[i]]
    fig.data[i]['x'] = df.index

fig.show()

运行第一个单元格将汇总一些数据并构建一个如下图:

运行第二个单元格将生成一个只有一行的新数据框,将其附加到原始数据框,替换现有图中的数据,然后再次显示该图。您可以根据需要多次运行第二个单元格,以使用扩展数据集重新绘制图形。运行 50 次后,您的图形将如下所示:

【讨论】:

嗨@vestland。在我的测试中,这段代码不断产生新的数字。无论我将后端设置为“笔记本”还是“浏览器”。它实际上并没有更新现有的数字。当我使用“浏览器”时,我会得到无穷无尽的标签。当我使用“笔记本”时,我会在笔记本内绘制出无穷无尽的数字。 @Jim 新人物?我不太清楚你的意思。每次运行之间是否清除输出? 是的,完全正确。应该更新的不仅仅是图形对象,而是显示的图形本身。我不希望每次更新和显示图形对象时都创建一个新图形。 @Jim 我明白了。您想在哪里显示此动画?在 JupyterLab 中?还是只是为了开发? 仅用于开发。无论是在独立的 .py 程序中还是在其他情况下,我都使用 Jupyter 笔记本,但如果它弹出并在浏览器中显示也没关系。事实上,我什至更喜欢那样。【参考方案2】:

所以我想我基本上想通了。诀窍是不要使用go.Figure() 创建图形,而是使用go.FigureWidget() 在光学上相同,但在幕后却不是。

documentation

youtube video demonstration

这些 FigureWidgets 会随着新数据的到来而更新。它们保持动态,以后的调用可以修改它们。

一个 FigureWidget 可以由一个 Figure 组成:

figure = go.Figure(data=data, layout=layout)

f2 = go.FigureWidget(figure)
f2                                          #display the figure

这很实用,因为它可以使用简化的 plotly express 界面创建一个 Figure,然后用它来构造一个 FigureWidget。不幸的是,plotly express 似乎没有它自己的简化 FigureWidget 模块。所以需要使用更复杂的go.FigureWidget

【讨论】:

以上是关于情节:如何用新数据更新/重绘情节表达图?的主要内容,如果未能解决你的问题,请参考以下文章

UITableViewCell 在出队时重绘

QWT zoomer plus panner 连续重绘

python: dash 实况情节图例

UIView 不重绘,但元素错位

更改某些属性后如何强制重绘小部件?

.data() 处的 D3 新数据使 svg 重绘而不是更新节点位置