python - Plotly-Dash:如何提高绘图对 slider 更改的响应能力

标签 python plotly plotly-dash

我正在开发一种工具,通过 Dash slider 修改这些参数来可视化一组参数对数学函数的影响。我正在使用一些 Dash 教程示例中的方法,这些示例使用回调来替换图形。

这可行,但绘图对 slider 更改的响应不如内置操作(例如通过拖动旋转绘图)。当图中有很多元素时尤其如此。

是否有其他方法可以提高响应能力?例如,是否有一种方法可以仅定位已更改的绘图元素,而不是替换整个图形?

这是一个最小的工作示例,由一个静态圆(带有许多样本)和一个我们通过 slider 旋转的线段组成。线段的旋转非常不稳定。

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go
from dash.dependencies import Input, Output, State
import numpy as np

app = dash.Dash(__name__)

# plot a circle
t = np.linspace(0, 2*np.pi, 10000)  # intentionally use many points to exaggerate the issue
x = np.cos(t)
y = np.sin(t)
z = np.zeros_like(t)
marker_size = 4
fig = go.Figure()
fig.add_trace(go.Scatter3d(x=x, y=y, z=z, mode='lines'))
fig.add_trace(go.Scatter3d(
    x=[0.0, 0.0], y=[0.0, 0.0], z=[0.0, 0.0],
    marker=go.scatter3d.Marker(size=marker_size),
    line=dict(width=3.0),
    showlegend=False,
))

fig.update_layout(
    uirevision='constant',
    autosize=False,
    width=900,
    height=900,
    scene=dict(
        xaxis=dict(range=[-1, 1]),
        yaxis=dict(range=[-1, 1]),
        zaxis=dict(range=[-1, 1.0]),
        aspectratio=dict(x=2, y=2, z=2),
    ),
)

app.layout = html.Div(children=[
    dcc.Graph(
        id='example-graph',
        figure=fig
    ),
    html.Div(
        [
            dcc.Slider(
                id='slider-phi',
                min=0.0,
                max=360.0,
                step=1.0,
                value=0.0,
                marks={0: '0', 180: '180', 360: '360'},
                updatemode='drag',
            ),
        ],
        style=dict(width='50%'),
    ),
    html.Div(children='', id='output-box'),
])

@app.callback(
    Output('example-graph', 'figure'),
    [Input('slider-phi', 'value')],
    [State('example-graph', 'figure')]
)
def display_structure(phi, myfig):
    myfig['data'][1]['x'][1] = np.cos(np.radians(phi))
    myfig['data'][1]['y'][1] = np.sin(np.radians(phi))
    myfig['data'][1]['z'][1] = 0

    return myfig

if __name__ == '__main__':
    app.run_server(debug=True)

最佳答案

缺乏响应能力可归因于两个关键因素。首先,正如您所注意到的,整个图形每次都会更新,而不仅仅是所需的轨迹。您可以通过定位 extendData 属性而不是 figure 属性来避免这种情况,

@app.callback(Output('example-graph', 'extendData'), [Input('slider-phi', 'value')])
def update_data(phi):
    # tuple is (dict of new data, target trace index, number of points to keep)
    return dict(x=[[0, np.cos(np.radians(phi))]], y=[[0, np.sin(np.radians(phi))]]), [1], 2

第二个因素是回调是在服务器端而不是客户端执行的,即每次移动 slider 时,请求都会在客户端和服务器之间交换。为了避免这种情况,您可以通过将回调转换为 clientside callback 将更新移动到客户端。 ,

app.clientside_callback(
    """
    function(phi) {
        // tuple is (dict of new data, target trace index, number of points to keep)
        return [{x: [[0, Math.cos(phi/180*Math.PI)]], y:[[0, Math.sin(phi/180*Math.PI)]]}, [1], 2]
    }
    """, Output('example-graph', 'extendData'), [Input('slider-phi', 'value')]
)

这应该产生合理的响应能力。这是它在我的笔记本电脑上的外观,

Responsiveness

为了完整起见,这里是完整的代码,

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go
from dash.dependencies import Input, Output, State
import numpy as np

app = dash.Dash(__name__)

# plot a circle
t = np.linspace(0, 2*np.pi, 10000)  # intentionally use many points to exaggerate the issue
x = np.cos(t)
y = np.sin(t)
z = np.zeros_like(t)
marker_size = 4
fig = go.Figure()
fig.add_trace(go.Scatter3d(x=x, y=y, z=z, mode='lines'))
fig.add_trace(go.Scatter3d(
    x=[0.0, 0.0], y=[0.0, 0.0], z=[0.0, 0.0],
    marker=go.scatter3d.Marker(size=marker_size),
    line=dict(width=3.0),
    showlegend=False,
))

fig.update_layout(
    uirevision='constant',
    autosize=False,
    width=900,
    height=900,
    scene=dict(
        xaxis=dict(range=[-1, 1]),
        yaxis=dict(range=[-1, 1]),
        zaxis=dict(range=[-1, 1.0]),
        aspectratio=dict(x=2, y=2, z=2),
    ),
)

app.layout = html.Div(children=[
    dcc.Graph(
        id='example-graph',
        figure=fig
    ),
    html.Div(
        [
            dcc.Slider(
                id='slider-phi',
                min=0.0,
                max=360.0,
                step=1.0,
                value=0.0,
                marks={0: '0', 180: '180', 360: '360'},
                updatemode='drag',
            ),
        ],
        style=dict(width='50%'),
    ),
    html.Div(children='', id='output-box'),
])

app.clientside_callback(
    """
    function(phi) {
        // tuple is (dict of new data, target trace index, number of points to keep)
        return [{x: [[0, Math.cos(phi/180*Math.PI)]], y:[[0, Math.sin(phi/180*Math.PI)]]}, [1], 2]
    }
    """, Output('example-graph', 'extendData'), [Input('slider-phi', 'value')]
)

if __name__ == '__main__':
    app.run_server(debug=True)

关于python - Plotly-Dash:如何提高绘图对 slider 更改的响应能力,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65854771/

相关文章:

python - 从 C 扩展访问 PIL 图像数据

python - kwargs 和函数签名

python - pyenv virtualenv : The SDK seems invalid 的 pycharm 错误

python - 如何将 html 列表添加到 dash 布局

python - 破折号/阴谋在间隔= 500时歇斯底里

python - 强制一个线程阻止所有其他线程执行

r - Plotly:如何更改默认模式栏按钮?

python - plotly 分散 : Change Interval length

python - 通过绘制县等值区域图添加更多关于悬停的数据

python - 将 Dash 应用程序集成到 Flask : minimal example