I would like to track the coordinates of the mouse with respect to data coordinates on two axes simultaneously. I can track the mouse position with respect to one axis just fine. The problem is: when I add a second axis with twinx()
, both Cursors
report data coordinates with respect to the second axis only.
For example, my Cursors (fern
and muffy
) report the y
-value is 7.93
Fern: (1597.63, 7.93)
Muffy: (1597.63, 7.93)
If I use:
inv = ax.transData.inverted()
x, y = inv.transform((event.x, event.y))
I get an IndexError.
So the question is: How can I modify the code to track the data coordinates with respect to both axes?
import numpy as np
import matplotlib.pyplot as plt
import logging
logger = logging.getLogger(__name__)
class Cursor(object):
def __init__(self, ax, name):
self.ax = ax
self.name = name
plt.connect('motion_notify_event', self)
def __call__(self, event):
x, y = event.xdata, event.ydata
ax = self.ax
# inv = ax.transData.inverted()
# x, y = inv.transform((event.x, event.y))
logger.debug('{n}: ({x:0.2f}, {y:0.2f})'.format(n=self.name,x=x,y=y))
logging.basicConfig(level=logging.DEBUG,
format='%(message)s',)
fig, ax = plt.subplots()
x = np.linspace(1000, 2000, 500)
y = 100*np.sin(20*np.pi*(x-1500)/2000.0)
fern = Cursor(ax, 'Fern')
ax.plot(x,y)
ax2 = ax.twinx()
z = x/200.0
muffy = Cursor(ax2, 'Muffy')
ax2.semilogy(x,z)
plt.show()
Due to the way that the call backs work, the event always returns in the top axes. You just need a bit of logic to check which if the event happens in the axes we want:
class Cursor(object):
def __init__(self, ax, x, y, name):
self.ax = ax
self.name = name
plt.connect('motion_notify_event', self)
def __call__(self, event):
if event.inaxes is None:
return
ax = self.ax
if ax != event.inaxes:
inv = ax.transData.inverted()
x, y = inv.transform(np.array((event.x, event.y)).reshape(1, 2)).ravel()
elif ax == event.inaxes:
x, y = event.xdata, event.ydata
else:
return
logger.debug('{n}: ({x:0.2f}, {y:0.2f})'.format(n=self.name,x=x,y=y))
This might be a subtle bug down in the transform stack (or this is the correct usage and it was by luck it worked with tuples before), but at any rate, this will make it work. The issue is that the code at line 1996 in transform.py
expects to get a 2D ndarray
back, but the identity transform just returns the tuple that get handed into it, which is what generates the errors.
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