Cannot get on_click() to work with plotly and go.Scatter

Hello,

The following code snippet works great in my Jupyter notebook. It successfully displays a plotly scatter graph, and when I hover over any one of the points it correctly displays the title of an article that the point corresponds to:

import chart_studio.plotly as py
import chart_studio.tools as tools
import plotly.figure_factory as ff
import plotly.graph_objects as go


spectral = ["#E69F00", "#56B4E9", "#009E73", "#F0E442", "#D55E00", "#0072B2",  "#CC79A7"] 
traces = []

data = list(zip(processed_articles_pca, df.title.tolist(), df.cluster.tolist()))

for i in range(n_clusters):
    # Assign the pca feature values, x[0] for each point in cluster n, x[2]
    point_slice = np.asarray([x[0] for x in data if x[2] == i])
    # Assign the titles for each point, x[1] in cluster n, x[2]
    title_slice = [x[1] for x in data if x[2] == i]
    
    # Regardless of the number of pca components, assign the pca values of index 0 to x, 
    # and index 1 to y, and set color equal to the corresponding cluster index color
    trace = go.Scatter(x = point_slice[:, 0], y = point_slice[:, 1], text = title_slice, 
                       hoverinfo = 'text', 
                       marker = dict(size = 16, color = spectral[i], showscale = False),
                       mode = 'markers', name = 'cluster {}'.format(i))
    
    traces.append(trace)

layout = go.Layout(title = 'Clustering of magazine Articles', 
                   xaxis = dict(title = 'X PCA value', titlefont = dict(size = 18, color='#7f7f7f')),
                   yaxis = dict(title = 'Y PCA value', titlefont = dict(size = 18, color='#7f7f7f')))

fig = go.Figure(data = traces, layout = layout)
py.iplot(fig, filename = 'td_medium_nlp_2')

Now I would like to enhance the code above, such that when a user clicks on any point in the scatter graph, a corresponding URL is opened in a separate web browser tab (i.e., each point corresponds to a title of an article and a URL that are both stored in my DataFrame).

I wrote the following callback function:

# Create our callback function
def open_url(trace, points, selector):
    if points.point_inds:
        ind = points.point_inds[0]
        url = df.url.iloc[ind]
        webbrowser.open_new_tab(url)

And have tried a variety of ways to have it invoked, but none of them work. For example:

    fig = go.FigureWidget(data = traces, layout = layout)

    for trace in traces:
        scatter = trace
        scatter.on_click(open_url, True)
        
    fig

Not only does this not work, but when I try to convert the plotly scatter graph to a FigureWidget, the underlying scatter graph no longer is displayed.

The one plotly page that addresses Click Events in Python (https://plot.ly/python/click-events/#reference) has an example, that, when I copy it into a Jupyter notebook cell, also displays nothing.

I read the help text at the bottom of the page that says,

“Callbacks will only be triggered when the trace belongs to a instance of plotly.graph_objs. FigureWidget and it is displayed in an ipywidget context. Callbacks will not be triggered on figures that are displayed using plot/iplot.”

Unfortunately, the only way to get the figure to display is by calling iplot(). So I tried displaying the scatter graph in the context of an ipywidget context, but, again, nothing is displayed:

@interact(n_clusters = widgets.IntSlider(min = 2, max = 7, step = 1, value = 3))
def display_interactive_clusters(n_clusters):
    spectral = ["#E69F00", "#56B4E9", "#009E73", "#F0E442", "#D55E00", "#0072B2",  "#CC79A7"]    # generate color dict
    traces = []
    
    data = list(zip(processed_articles_pca, df.title.tolist(), df.cluster.tolist()))

    for i in range(n_clusters):        
        # Assign the pca feature values, x[0] for each point in cluster n, x[2]
        point_slice = np.asarray([x[0] for x in data if x[2] == i])
        # Assign the titles for each point, x[1] in cluster n, x[2]
        title_slice = [x[1] for x in data if x[2] == i]

        # Regardless of the number of pca components, assign the pca values of index 0 to x, 
        # and index 1 to y, and set color equal to the corresponding cluster index color
        trace = go.Scatter(x = point_slice[:, 0], y = point_slice[:, 1], text = title_slice, 
                           hoverinfo = 'text', 
                           marker = dict(size = 16, color = spectral[i], showscale = False),
                           mode = 'markers', name = 'cluster {}'.format(i))

        traces.append(trace)

    layout = go.Layout(title = 'Clustering of magazine Articles', 
                       xaxis = dict(title = 'X PCA value', titlefont = dict(size = 18, color='#7f7f7f')),
                       yaxis = dict(title = 'Y PCA value', titlefont = dict(size = 18, color='#7f7f7f')))

    fig = go.FigureWidget(data = traces, layout = layout)

    for trace in traces:
        scatter = trace
        scatter.on_click(open_url, True)
        
    fig

Can someone help me figure out what I am doing wrong? My goals are to:

  1. Display my scatter graph as a FigureWidget such that I am not using iplot (per the documentation).
  2. Successfully add an on_click() callback function that gets invoked when a user clicks on the points in the scatter graph.

Thank you.

three reasons why you should buy plotly pro: support open source, get great support, host your plots and dashboards online