如何正确为Plotly中的单个轨迹添加回调?

1 投票
0 回答
52 浏览
提问于 2025-04-12 04:59

下面的代码尝试用三种不同的方法在Plotly的图形上注册一个回调函数。

  1. 方法'a'是在将图形添加到图表之前,直接在图形对象上注册回调函数。
  2. 方法'b'是在将图形添加到图表后,通过从图表的数据列表中获取对象来注册回调函数。
  3. 方法'c'是方法'a'的一种变体,其中回调函数是局部的(也就是说,它不是一个成员函数)。

以下是我尝试添加回调函数的三种方法的代码。如果你在Jupyter Notebook中运行这段代码,你应该能看到三个图表,点击任意一个图表上的点应该会打印一条消息,但似乎只有使用方法'b'的图表能够正常工作。

import ipywidgets as widgets
import plotly.graph_objects as go

line = {'name': 'line','data': ((1,1), (2,2), (3,3)), 'color':'red', 'dash':'solid'}
squared = {'name': 'squared','data': ((1,1), (2,2**2), (3,3**2)), 'color':'blue', 'dash':'4,4'}
cubed = {'name': 'cubed','data': ((1,1), (2,2**3), (3,3**3)), 'color':'green', 'dash':'solid'}
n4 = {'name': 'n4','data': ((1,1), (2,2**4), (3,3**4)), 'color':'purple', 'dash':'solid'}
traces = (line, squared, cubed, n4)

class MyPlot:
    def __init__(self, traces, use_callback):
        self.traces = traces
        self.use_callback = use_callback
    
    def get_values(self, func, index):
        return [e[index] for e in func['data']]
    
    def callback_a(self, trace, points, state):
        print(f"in callback_a with trace = {trace}, points = {points}, state = {state}")
        
    def callback_b(self, trace, points, state):
        if len(points.point_inds) < 1:
            return
        print(f"in callback_b with trace = {trace}, points = {points}, state = {state}")
       
            
    def display(self):
        
        def callback_c(trace, points, state):
            print(f"in callback_c with trace = {trace}, points = {points}, state = {state}")
        
        fig = go.FigureWidget() 
               
        for t in traces:
            s = go.Scatter(mode="lines", name=t['name'], x=self.get_values(t, 0), y=self.get_values(t, 1), line=dict(width=2, color=t['color'], dash=t['dash']))
            if self.use_callback == 'a': s.on_click(self.callback_a)
            if self.use_callback == 'c': s.on_click(callback_c)
            fig.add_trace(s) 
            if self.use_callback == 'b': fig.data[-1].on_click(self.callback_b)
            fig.layout.title = f"Plot using callback {self.use_callback}"
            
        display(fig)
        
my_plot_a = MyPlot(traces, 'a')
my_plot_b = MyPlot(traces, 'b')
my_plot_c = MyPlot(traces, 'c')
my_plot_a.display()
my_plot_b.display()
my_plot_c.display()

正如我之前所说,似乎只有方法'b'能够正常工作。然而,这种方法有一个不太好的“特性”。当我点击任意一个图形上的点时,每个图形的回调函数都会被调用,即使我并没有点击那个图形。为了解决这个问题,我通过检查points.point_inds属性的长度来进行处理,只有在我想要的回调中这个长度才会大于0。虽然这样可以解决问题,但感觉有点多余,而我想要的方法'a'似乎是文档中推荐的做法,但我却无法让它正常工作。

这是来自Plotly的一个文档的例子。我觉得我在方法'a'和'c'中都遵循了这个例子。我是不是做错了什么?

在此输入图片描述

0 个回答

暂无回答

撰写回答