情节条件 on_click

Plotly Conditional on_click

有没有办法为控制另一个的函数 `on_click 设置条件语句?我打算执行以下操作:

  1. 引入散点数据(目前有效)
  2. Select 我的散点数据中有 2 个点(目前有效 - 图片上的蓝点)
  3. 在 2 个散点之间创建新线(目前有效 - 图片上的黑线)
  4. Select 创建的新线上的一个点(目前有效 - 图片上的绿点)
  5. 将新行上的点限制为 1(我一直在尝试进行条件语句)
  6. Select 我的散点图中没有线的第 3 个点(我正在等待这样做,直到我可以修复上一步。我将有另一个数据集,我'我从那里拉出来,我将允许 select 从 - 图片上的红点)
  7. 根据我已经select编辑的点创建新线(图片上的橙色线)

我原以为使用条件 fake_click_check 语句会起作用,但它什么也没做。我想一旦我可以修复当前的条件语句(以及如何将它们与 on_click 一起使用),我就可以完成其余的步骤。

@out.capture()
def update_point(trace, points, selector):
    x = list(line.x) + points.xs
    y = list(line.y) + points.ys
    line.update(x=x, y=y)

    clicks=len(fig.to_dict()['data'][2]['x'])
    c = list(scatter.marker.color)
    s = list(scatter.marker.size)
    for i in points.point_inds:
        c[i] = '#bae2be'
        s[i] = 20
        with fig.batch_update():
            scatter.marker.color = c
            scatter.marker.size = s
    if (clicks==2):
        fict_x1=float(fig.to_dict()['data'][2]['x'][0])
        fict_x2=float(fig.to_dict()['data'][2]['x'][2])
        fict_x_start=np.minimum(fict_x1,fict_x2)
        fict_x_end=np.maximum(fict_x1,fict_x2)
        fict_x=np.arange(fict_x_start,fict_x_end,0.1)
        x_len=fict_x.size
        
        fict_y1=float(fig.to_dict()['data'][2]['y'][0])
        fict_y2=float(fig.to_dict()['data'][2]['y'][2])
        fict_y_start=np.minimum(fict_y1,fict_y2)
        fict_y_end=np.maximum(fict_y1,fict_y2)
        fict_y_tick=(fict_y_end-fict_y_start)/x_len
        fict_y=np.arange(fict_y_start,fict_y_end,fict_y_tick)
    
        new_point.update(x=fict_x,y=fict_y)
        fake_click_check=1
    if (clicks > 2):
        line.update(x=[],y=[])
        scatter.marker.color=['#a3a7e4']*100
        scatter.marker.size=[10]*100                
        out.clear_output
        
        
@out.capture()
def set_new_point(trace,points,selector):
    fake_click=len(fig.to_dict()['data'][2]['x'])
    if (fake_click_check < 1):
        if (fake_click>1):
            c = list(new_point.marker.color)
            s = list(new_point.marker.size)
            fake_click_check=fake_click_check+1
            for i in points.point_inds:
                c[i]='#bae2be'
                s[i]=20
                with fig.batch_update():
                    new_point.marker.color = c
                    new_point.marker.size = s


scatter.on_click(update_point)

if (fake_click_check==1):
    new_point.on_click(set_new_point)
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import ipywidgets as widgets

x = np.random.uniform(-10, 10, size=50)
y = np.sin(x)

# construct figure that has holders for points, interpolated line and final lines
fig = go.FigureWidget(
    [
        go.Scatter(x=x, y=y, mode="markers", name="base_points"),
        go.Scatter(name="points", mode="markers", marker={"size": 20}),
        go.Scatter(name="interp", showlegend=False),
        go.Scatter(name="lines", line={"color": "orange"}, mode="lines"),
    ]
)
fig.update_layout(template="simple_white")

out = widgets.Output(layout={"border": "1px solid black"})
out.append_stdout("Output appended with append_stdout\n")


# interpolated line between first two selected points
@out.capture()
def line_click(trace, points, selector):
    # print(trace.name, points.xs, points.ys)
    if len(points.xs) == 1 and len(fig.data[1].x) == 2:
        t = fig.data[1]
        t.update(x=list(t.x) + points.xs, y=list(t.y) + points.ys)


# create our callback function
@out.capture()
def base_click(trace, points, selector):
    # print(trace.name, points.xs, points.ys)
    if len(points.xs) == 0:
        return
    if fig.data[1].x is None: # first point
        t = fig.data[1]
        t.update(x=points.xs, y=points.ys)
    elif len(fig.data[1].x) in [1, 3]: # second and fourth point
        t = fig.data[1]
        t.update(x=list(t.x) + points.xs, y=list(t.y) + points.ys)
        if len(fig.data[1].x) == 2:
            # need a set of points so click events work on second points
            xx = np.linspace(*fig.data[1].x, 20)
            yy = np.interp(xx, fig.data[1].x, fig.data[1].y)
            t = fig.data[2]
            t.update(x=xx, y=yy, marker={"size": 2}, mode="markers")
        else: # fourth point create the lines
            # use order of points to construct wanted lines
            fig.data[3].update(
                x=np.array(fig.data[1].x)[[0, 3, 3, 2, 3, 1]],
                y=np.array(fig.data[1].y)[[0, 3, 3, 2, 3, 1]],
            )


fig.data[0].on_click(base_click)
fig.data[2].on_click(line_click)

reset = widgets.Button(description="Reset")


@out.capture()
def on_reset_clicked(b):
    # line.update(x=[], y=[])
    fig.data[1].update(x=None, y=None)
    fig.data[2].update(x=None, y=None)
    fig.data[3].update(x=None, y=None)

    out.clear_output()


reset.on_click(on_reset_clicked)

widgets.VBox([widgets.HBox([reset]), widgets.HBox([fig, out])])