在Dash中创建用于悬停跟踪的客户端回调

Create client side callback for hover tracking in Dash(在Dash中创建用于悬停跟踪的客户端回调)
本文介绍了在Dash中创建用于悬停跟踪的客户端回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经创建了一个Dash应用程序来跟踪和存储图像的悬停数据(参见下面的代码)。我想把悬停跟踪部分变成客户端回调,让APP更具伸缩性,提高悬停跟踪的性能。下面是我使用普通回调的代码。如何将此函数转换为客户端回调?

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
])


# Change to client side callback (in JavaScript)
@app.callback(
    [Output('ss-idx', 'data'),
     Output('ss-img', 'figure'),
     Output('hoverdata', 'data')],
    [Input('ss-img', 'hoverData'),
     Input('next-button', 'n_clicks')],
    [State('hoverdata', 'data'),
     State('ss-idx', 'data')]
)
def add_to_hoverdata(hover_point, next_clicks, hoverdata, ss_idx):
    ctx = dash.callback_context
    if not ctx.triggered:
        raise PreventUpdate

    button_id = ctx.triggered[0]['prop_id'].split('.')[0]
    if 'ss-img' in button_id:
        if hover_point is not None:
            x = hover_point["points"][0]["x"]
            y = hover_point["points"][0]["y"]
            hoverdata.append((x, y))
            return dash.no_update, dash.no_update, hoverdata

    elif 'next-button' in button_id:
        # Add hoverdata and screenshot index to mysql database (code not shown)
        print(next_clicks)
        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)

推荐答案

尝试将其转换为客户端回调...但首先要注意到的两点是:

  1. 因为url是在服务器端定义的数组,所以必须通过dcc.Store组件添加到客户端。

  2. 您将无法在客户端回调中向数据库发送数据。这是在最下面of the Dash docs的第三点中提到的。如果您能够连接到数据库并以JS格式发送数据,我想您可以这样做,但这可能是一个非常糟糕的主意...

回调:

app.clientside_callback(
    # from dash.dependencies import ClientsideFunction
    ClientsideFunction(
        namespace="clientside",
        function="addToHoverData"
    ),
    [Output('ss-idx', 'data'),
     Output('ss-img', 'figure'),
     Output('hoverdata', 'data')],
    [Input('ss-img', 'hoverData'),
     Input('next-button', 'n_clicks')],
    [State('hoverdata', 'data'),
     State('ss-idx', 'data'),
     # you must create a Store with the url list
     State('url-list', 'data') 
    ]
)

assets/clientside.js

window.dash_clientside = Object.assign({}, window.dash_clientside, {
    clientside: {
        add_to_hoverdata: function(hoverData, nClicks, storeHoverData, storeIdx, storeURLs) {
            // storeURLs is an array that holds the image URLs
            const ctx = dash_clientside.callback_context;

            if (!("triggered" in ctx)){
                return dash_clientside.no_update
            }

            const triggered_id = ctx.triggered[0].prop_id.split(".")[0];

            if (triggered_id === "ss-img"){
                if (hoverData !== undefined){
                    // assumes storeHoverData is an array
                    storeHoverData.push(hoverData.points[0]);
                    return [
                        dash_clientside.no_update,
                        dash_clientside.no_update,
                        storeHoverData
                    ]
                }
            } else if (triggered_id === "next-button"){
                console.log(nClicks);

                if (nClicks < storeURLs.length){
                    return [
                        storeIdx +1,
                        storeURLs[storeIdx +1],
                        []
                    ]
                }
                else {
                    return dash_clientside.no_update
                }
            }
        }
    }
});

我尽量使js代码靠近您的python回调。

这篇关于在Dash中创建用于悬停跟踪的客户端回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Update another component when Formik form changes(当Formik表单更改时更新另一个组件)
Formik validation isSubmitting / isValidating not getting set to true(Formik验证正在提交/isValiating未设置为True)
React Validation Max Range Using Formik(使用Formik的Reaction验证最大范围)
Validation using Yup to check string or number length(使用YUP检查字符串或数字长度的验证)
Updating initialValues prop on Formik Form does not update input value(更新Formik表单上的初始值属性不会更新输入值)
password validation with yup and formik(使用YUP和Formick进行密码验证)