Search code examples
matplotlibevent-handlingpicker

Picker Event to display legend labels in matplotlib


I want the picker event to simply display the legend label when I click on any of the points on my scatter plot. This is what I have and looks like:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# x y data and legend labels
x = np.random.uniform(0, 100, 50)
y = np.random.uniform(0, 100, 50)
ID = np.random.randint(0,25,50)

# define the event
def onpick(event):
    ind = event.ind
    print('x:', x[ind], 'y:', y[ind])

# create the plot
fig, ax = plt.subplots()
scatter = ax.scatter(x, y, c = ID, picker=True)

ax.set_xlabel('x')
ax.set_ylabel('y')
ax.legend(*scatter.legend_elements(num=list(np.unique(ID))),
          loc="center left", 
          title='ID', 
          bbox_to_anchor=(1, 0.5),
          ncol=2
         )    
ax.ticklabel_format(useOffset=False)
ax.tick_params(axis = 'x',labelrotation = 45)
plt.tight_layout()


# call the event
fig.canvas.mpl_connect('pick_event', onpick)    

The scatter plot: The scatter plot:

The current output on click: The current output when click on a point:

I want it to print something like:

x: [76.25650514] y: [59.85198124] ID: 11 # the corresponding legend label

I have been searching through the web and couldn't find much I can duplicate from.


Solution

  • Generally, the way you would get the label of the point you clicked on would be print(event.artist.get_label()) but with your custom legends labels, the only thing that prints is _child0. However, due to your custom labels, you can use your variable ID just like how you are using your x and y variables e.g. print('id:', ID[ind]).

    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    
    # x y data and legend labels
    x = np.random.uniform(0, 100, 50)
    y = np.random.uniform(0, 100, 50)
    ID = np.random.randint(0,25,50)
    
    # define the event
    def onpick(event):
        ind = event.ind
        print(event.artist.get_label()) # How you normally get the legend label
        print('id:', ID[ind])           # How you can get your custom legend label
        print('x:', x[ind], 'y:', y[ind])
    
    # create the plot
    fig, ax = plt.subplots()
    scatter = ax.scatter(x, y, c = ID, picker=True)
    
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.legend(*scatter.legend_elements(num=list(np.unique(ID))),
              loc="center left", 
              title='ID', 
              bbox_to_anchor=(1, 0.5),
              ncol=2
             )    
    ax.ticklabel_format(useOffset=False)
    ax.tick_params(axis = 'x',labelrotation = 45)
    plt.tight_layout()
    
    
    # call the event
    fig.canvas.mpl_connect('pick_event', onpick)
    plt.show()
    

    Clicking on the yellow most point gives:

    _child0
    id: [24]
    x: [84.73899472] y: [3.07532246]
    

    Clicking on a very purple point gives:

    _child0
    id: [2]
    x: [99.88397652] y: [98.89144833]