I have a simple code that shows two subplots, and lets the user left click on the second subplot while recording the x,y
coordinates of those clicks.
The problem is that clicks to select a region to zoom and to drag the subplot are also identified as left clicks.
Is there a way to distinguish and filter out these left clicks?
import numpy as np
import matplotlib.pyplot as plt
def onclick(event, ax):
# Only clicks inside this axis are valid.
if event.inaxes == ax:
if event.button == 1:
print(event.xdata, event.ydata)
# Draw the click just made
ax.scatter(event.xdata, event.ydata)
ax.figure.canvas.draw()
elif event.button == 2:
# Do nothing
print("scroll click")
elif event.button == 3:
# Do nothing
print("right click")
else:
pass
fig, (ax1, ax2) = plt.subplots(1, 2)
# Plot some random scatter data
ax2.scatter(np.random.uniform(0., 10., 10), np.random.uniform(0., 10., 10))
fig.canvas.mpl_connect(
'button_press_event', lambda event: onclick(event, ax2))
plt.show()
Press the right mouse button to zoom, dragging it to a new position. The x axis will be zoomed in proportionately to the rightward movement and zoomed out proportionately to the leftward movement. The same is true for the y axis and up/down motions.
The matplotlib. pyplot. subplots method provides a way to plot multiple plots on a single figure. Given the number of rows and columns , it returns a tuple ( fig , ax ), giving a single figure fig with an array of axes ax .
How do you zoom a plot on a Jupyter notebook? Just drag the right bottom corner of the plot..
You may check if the mouse button is released after the mouse has previously been moved. Since for zooming and panning, this would be the case you may call the function to draw a new point only when no previous movement has happened.
import numpy as np
import matplotlib.pyplot as plt
class Click():
def __init__(self, ax, func, button=1):
self.ax=ax
self.func=func
self.button=button
self.press=False
self.move = False
self.c1=self.ax.figure.canvas.mpl_connect('button_press_event', self.onpress)
self.c2=self.ax.figure.canvas.mpl_connect('button_release_event', self.onrelease)
self.c3=self.ax.figure.canvas.mpl_connect('motion_notify_event', self.onmove)
def onclick(self,event):
if event.inaxes == self.ax:
if event.button == self.button:
self.func(event, self.ax)
def onpress(self,event):
self.press=True
def onmove(self,event):
if self.press:
self.move=True
def onrelease(self,event):
if self.press and not self.move:
self.onclick(event)
self.press=False; self.move=False
def func(event, ax):
print(event.xdata, event.ydata)
ax.scatter(event.xdata, event.ydata)
ax.figure.canvas.draw()
fig, (ax1, ax2) = plt.subplots(1, 2)
# Plot some random scatter data
ax2.scatter(np.random.uniform(0., 10., 10), np.random.uniform(0., 10., 10))
click = Click(ax2, func, button=1)
plt.show()
I realize that this is an old question, but I just had the same problem and I think I found a neat solution; however it currently works only for the Qt backend (similar solutions might exist for other backends too). The idea is that matplotlib changes the cursor shape while zooming or panning, so you can check for that. This is the adapted code:
import numpy as np
import matplotlib
matplotlib.use('qt5agg')
import matplotlib.pyplot as plt
def onclick(event, ax):
# Only clicks inside this axis are valid.
try: # use try/except in case we are not using Qt backend
zooming_panning = ( fig.canvas.cursor().shape() != 0 ) # 0 is the arrow, which means we are not zooming or panning.
except:
zooming_panning = False
if zooming_panning:
print("Zooming or panning")
return
if event.inaxes == ax:
if event.button == 1:
print(event.xdata, event.ydata)
# Draw the click just made
ax.scatter(event.xdata, event.ydata)
ax.figure.canvas.draw()
elif event.button == 2:
# Do nothing
print("scroll click")
elif event.button == 3:
# Do nothing
print("right click")
else:
pass
fig, (ax1, ax2) = plt.subplots(1, 2)
# Plot some random scatter data
ax2.scatter(np.random.uniform(0., 10., 10), np.random.uniform(0., 10., 10))
fig.canvas.mpl_connect(
'button_press_event', lambda event: onclick(event, ax2))
plt.show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With