简体   繁体   中英

Plotly Conditional on_click

Is there a way to set a conditional statement for function `on_click that controls another? I'm intending to do the following:

  1. Bring in scatter data (currently works)
  2. Select 2 points in my scatter data (currently works - blue dots on picture)
  3. Create new line between the 2 scatter points (currently works - black line on picture)
  4. Select a point on the new line created (currently works - green dot on picture)
  5. Limit the points on the new line to 1 (where I'm stuck in trying to make a conditional statement)
  6. Select a 3rd point from my scatter plot that doesn't have a line (I'm waiting to do this until I can fix the previous step. I'll have another data set that I'm pulling from that I'll allow to select from - red dot on picture)
  7. Create new lines based on the points I've already selected (orange lines on picture)

在此处输入图像描述

I would have thought using the conditional fake_click_check statement would work, but it isn't doing anything. I think once I can fix this current conditional statement (and how I can use them with on_click ), I'll be able to do the rest of the steps.

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

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM