You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Dash图像悬停追踪的普通回调改为客户端回调以提升性能

Dash悬停回调客户端改造方案

改造要点

  • 把高频率触发的悬停数据追加逻辑完全迁移到前端执行,避免每次悬停都发起服务端请求,大幅降低服务端压力、提升响应速度
  • 低频率的Next按钮点击逻辑仍保留在服务端,不需要修改原有数据库写入、图片生成的业务逻辑

完整修改后代码

import dash
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
import plotly.express as px
import requests
from dash.dependencies import ClientsideFunction, Input, Output, State
from dash.exceptions import PreventUpdate
from PIL import Image


app = dash.Dash(__name__)
server =  app.server

# In reality, there are 50 screenshot images with non-sequential indexes
urls = ["https://pbs.twimg.com/media/EW8GhG_XkAEOyAh.jpg",
        "https://pbs.twimg.com/media/CqzwpPnWEAAiGjW.jpg"]

def url_to_fig(url):
    rgb_arr = np.array(Image.open(requests.get(url, stream=True).raw))
    fig = px.imshow(rgb_arr)
    fig.update_xaxes(visible=False)
    fig.update_yaxes(visible=False)
    fig.update_layout(
        dragmode=False, width=800, height=800)
    fig.update_traces(hoverinfo='none', hovertemplate=None)
    return fig

app.layout = html.Div([
    dcc.Store(id='ss-idx', data=0),
    dcc.Graph(id='ss-img', figure=url_to_fig(urls[0]), config = {"displayModeBar": False}),
    html.Button("Next", id='next-button', n_clicks=0),
    dcc.Store(id='hoverdata', data=[]), # Place to append new hoverdata
])

# 新增:客户端回调,仅处理悬停数据追加,完全在前端执行
app.clientside_callback(
    Output('hoverdata', 'data'),
    Input('ss-img', 'hoverData'),
    State('hoverdata', 'data'),
    prevent_initial_call=True,
    """
    function(hover_point, hoverdata) {
        const ctx = dash_clientside.callback_context;
        if (!ctx.triggered.length || !hover_point) return dash_clientside.no_update;
        const x = hover_point.points[0].x;
        const y = hover_point.points[0].y;
        hoverdata.push([x, y]);
        return hoverdata;
    }
    """
)

# 修改后的服务端回调,仅处理Next按钮点击逻辑
@app.callback(
    [Output('ss-idx', 'data'),
     Output('ss-img', 'figure'),
     Output('hoverdata', 'data')],
    Input('next-button', 'n_clicks'),
    [State('hoverdata', 'data'),
     State('ss-idx', 'data')],
    prevent_initial_call=True
)
def handle_next_click(next_clicks, hoverdata, ss_idx):
    # Add hoverdata and screenshot index to mysql database (code not shown)
    print(next_clicks, hoverdata)
    if next_clicks < len(urls):
        new_idx = ss_idx + 1
        return new_idx, url_to_fig(urls[new_idx]), [] # Reset hoverdata
    else:
        raise PreventUpdate


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

关键修改说明

  • 新增的客户端回调直接通过内联JS实现逻辑,不需要额外引入JS文件,prevent_initial_call参数避免页面初始化时无意义触发
  • JS逻辑和原Python逻辑完全对齐:判断触发源、提取悬停坐标、追加到存储数组后返回
  • 服务端回调去掉了hoverData的触发输入,只有点击Next按钮时才会触发服务端请求,服务端可以直接拿到当前页面完整的悬停数据做数据库写入,原有业务逻辑不需要调整

内容的提问来源于stack exchange,提问作者acciolurker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 06:15:02