Skip to content
Advertisement

Python interactive plotting with click events

I’m currently trying to bring in some data through np, do some processing on that initial data, plot it, but then be interactive with my plot. Plotly has a tutorial of how to take the plot and change the color of the data points (in jupyter using the click event https://plotly.com/python/click-events/). What I’m hoping to do is be able to take the click event click on 2 points and then create a line between the points selected and gather my positions of the line. The only thing I have found in plotly is just hovering over the data but not being able to do this processing. Is there a better way of doing this rather than using plotly? The documentation on plotly is suggesting to just use dash, but I haven’t found a way of doing this with dash. The follow-up question would be how do I get this data if I export my plot (fig.write_html)?

Sample of what I have is:

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

# Import libraries
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go


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

fig=go.FigureWidget([go.Scatter(x=x, y=y, mode='markers')])

fig.update_layout(template='simple_white')

scatter=fig.data[0]
colors=['#a3a7e4']*100
scatter.marker.color=colors
scatter.marker.size=[10]*100
fig.layout.hovermode='closest'

fig.update_traces(marker=dict(line=dict(color='DarkSlateGrey')))

# create our callback function
def update_point(trace, points, selector):
    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

scatter.on_click(update_point)

fig

Advertisement

Answer

  • given you attempted example is ipwidgets I have extended this
  • create an empty trace that will be target for lines
  • for debugging create widgets.Output()
  • now just a case of creating UI using HBox() and VBox()
  • for now have demonstrated how you can export by printing to stdout. This clearly could save the JSON to a file
# Import libraries
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import json
import ipywidgets as widgets

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

fig=go.FigureWidget([go.Scatter(x=x, y=y, mode='markers'), go.Scatter(x=[], y=[], mode="lines")])

fig.update_layout(template='simple_white')

scatter=fig.data[0]
line = fig.data[1]
colors=['#a3a7e4']*100
scatter.marker.color=colors
scatter.marker.size=[10]*100
fig.layout.hovermode='closest'

fig.update_traces(marker=dict(line=dict(color='DarkSlateGrey')))

out = widgets.Output(layout={'border': '1px solid black'})
out.append_stdout('Output appended with append_stdoutn')

# create our callback function
@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)
scatter.on_click(update_point)

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

@out.capture()
def on_reset_clicked(b):
    line.update(x=[], y=[])
    out.clear_output()
@out.capture()
def on_export_clicked(b):
    print(fig.to_dict()["data"][1])

reset.on_click(on_reset_clicked)
export.on_click(on_export_clicked)

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

enter image description here

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement