Rahat Zaman
Rahat Zaman

Reputation: 1382

Display hover when clicked instead of hovering over a datapoint in plotly python?

Suppose I have a scatterplot in plotly (python). When I hover over a point, I see the hover of the points x and y immediately. But what I want to do it click on the point, then the hover text will appear (and stay). And when I click on another point, the hover text will appear there for that point. How do I do this?

Upvotes: 4

Views: 3837

Answers (1)

Derek O
Derek O

Reputation: 19635

As mentioned in the comments, I don't believe you can create this functionality in plotly python because this library alone can't process clickevents on markers.

However, in plotly-dash you can use callbacks to process clickData (see the documentation for an example), and this will allow you to modify the figure when the user clicks on a marker.

Since you want to display text next to each marker, I thought the easiest solution would be to have the text associated with each trace (with one marker per trace) and set the opacity of the text to 0 so it doesn't display initially. Then when the user clicks on the marker, the opacity of the text changes to 1 if it is 0, or changes to 0 when the opacity is 1. Also you can pass the argument hoverinfo='none' to hide the default hoverinfo that Plotly displays with each marker.

import plotly.graph_objects as go
import dash
from dash import dcc, html
from dash.dependencies import Input, Output

app = dash.Dash()

x_array = [1,2,3,4]
y_array = [5,6,7,8]
text_array = [f"x:{x}<br>y:{y}" for (x,y) in zip(x_array,y_array)]

fig = go.Figure()
for (x,y,text) in zip(x_array,y_array,text_array):
    fig.add_trace(go.Scatter(
        x=[x],
        y=[y],
        text=[text],
        marker=dict(color="blue", size=20),
        textfont=dict(color='rgba(0,0,0,0)'),
        textposition="middle right",
        mode="markers+text",
        hoverinfo='none',
        showlegend=False
    ))
fig.update_layout(title="Display Hovertext when Clicked", title_x=0.5)
fig.update_yaxes(range=[4,10])

app.layout = html.Div(children=[
    dcc.Graph(
        id='example-graph',
        figure=fig
    )
])

@app.callback(
    Output('example-graph', 'figure'),
    [Input('example-graph', 'clickData')])
def toggle_text(clickData, fig=fig, x_array=x_array, y_array=y_array, text_array=text_array):
    if clickData is None:
        return fig
    else:
        trace_number = clickData['points'][0]['curveNumber']
        trace_color = fig.data[trace_number].textfont.color
        # print(f"you clicked on trace_number {trace_number} with color {trace_color}")
        if fig.data[trace_number].textfont.color == 'rgba(0,0,0,0)':
            # print(f"setting trace_number {trace_number} invisible to visible")
            fig.data[trace_number].textfont.color = 'rgba(0,0,0,1)'
        elif fig.data[trace_number].textfont.color == 'rgba(0,0,0,1)':
            # print(f"setting trace_number {trace_number} visible to invisible")
            fig.data[trace_number].textfont.color = 'rgba(0,0,0,0)'
        return fig

if __name__ == '__main__':
    app.run_server(debug=True)

enter image description here

Upvotes: 2

Related Questions