Python Forum

Full Version: Pick a line in a plot with matplotlib
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi all.

I have an issue with a picking event using the matplotlib library. I am trying to pick a vertical line that I draw on a X-Y plot when I click near the line. However, wherever I click, the line is picked, and I do not understand why.

Here's my code:

import numpy as np
import matplotlib.pyplot as plt

class my_class:
    def __init__( self , **kwargs ):
        self.fig , self.ax = plt.subplots()
        self.line = self.ax.axvline( x = 0.5 , **kwargs )
        self.connect()
        plt.show()
        return
        
    def connect( self ):
        cid = self.fig.canvas.mpl_connect( 'button_press_event' , self.on_click )
        return
        
    def on_click( self , event ):
        if self.line.contains( event ):
            print( "Line picked." )
        return

def main():
    my_plot = my_class( pickradius = .5 )

if __name__ == "__main__":
    main()
The constructor creates the plot, the line, and connects to mouse events via the function "connect". The function "on_click" is a callback function to mouse clicking events that (should) print "Line picked." whenever I click near the line. But it prints "Line picked" wherever I click.

Any idea?
You could perhaps try an integer pickradius such as 5
Thanks for the answer Gribouillis.

I tried that, but it still picks the line wherever I click.
The issue with your code is that the contains method of the Line2D object returned by axvline is always returning True, regardless of where you click, because you're not checking if the click is within a certain distance of the line.

To fix this, you can calculate the distance between the click event and the line using the dist method of the Line2D object. Here's the updated on_click method that should work correctly:

def on_click(self, event):
if event.inaxes == self.ax:
distance = abs(event.xdata - self.line.get_xdata()[0])
if distance < self.ax.get_xbound()[1] * 0.01:
print("Line picked.")
return


This code first checks if the click event is within the axes of the plot. Then, it calculates the distance between the x-coordinate of the click event and the x-coordinate of the line using the get_xdata method. Finally, it checks if the distance is less than 1% of the x-axis range of the plot, and prints "Line picked." if it is.

You can adjust the 0.01 factor to change the sensitivity of the picking event. In this case, it checks if the click is within 1% of the x-axis range of the plot, but you can adjust this to make it more or less sensitive depending on your needs.

I hope this helps!