No zdata in motion_notify_event when using a 3D plot

Hi:

I am trying to use the event associated to motion_notify_event in a 3D
plot, and I found that the event does not have the zdata property.

The following code illustrate the problem:

···

##################################
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt

def on_hover(event):
    print dir(event)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = [1, 2, 3]
y = [1, 5, 4]
z = [3, 5, 6]
ax.scatter(x, y, z)

cid = fig.canvas.mpl_connect('motion_notify_event', on_hover)

plt.show()
##################################

When you move the mouse over the figure, you can see the properties of event:

['__doc__', '__init__', '__module__', '__str__',
'_update_enter_leave', 'button', 'canvas', 'dblclick', 'guiEvent',
'inaxes', 'key', 'lastevent', 'name', 'step', 'x', 'xdata', 'y',
'ydata']

There is xdata, ydata, but not zdata.

Is zdata missing or should I be using a different event type?

Alejandro.

Be careful, I don’t think the xdata and ydata are in the coordinate system that you believe they are in. Because of the way mplot3d works outside of the proper projections transform framework, it can only guess at what the 3d coordinates are. The x/ydata are probably in the 2d axes coordinates and not the coordinates that you are using for the 3d axes that is embedded in the 2d axes, I can’t recall for sure.

The following is the function from the Axes3D class used to report a 3d coordinate that is displayed in the lower-right corner of the figure. You might be able to adapt this for your use. Note that self.M is the internal projection matrix for the Axes3D object.

def format_coord(self, xd, yd):
    """
    Given the 2D view coordinates attempt to guess a 3D coordinate.
    Looks for the nearest edge to the point and then assumes that

    the point is at the same z location as the nearest point on the edge.
    """

    if self.M is None:
        return ''

    if self.button_pressed in self._rotate_btn:

        return 'azimuth=%d deg, elevation=%d deg ' % (self.azim, self.elev)
        # ignore xd and yd and display angles instead

    p = (xd, yd)
    edges = self.tunit_edges()
    #lines = [proj3d.line2d(p0,p1) for (p0,p1) in edges]

    ldists = [(proj3d.line2d_seg_dist(p0, p1, p), i) for \
            i, (p0, p1) in enumerate(edges)]
    ldists.sort()
    # nearest edge
    edgei = ldists[0][1]

    p0, p1 = edges[edgei]

    # scale the z value to match
    x0, y0, z0 = p0
    x1, y1, z1 = p1
    d0 = np.hypot(x0-xd, y0-yd)
    d1 = np.hypot(x1-xd, y1-yd)
    dt = d0+d1
    z = d1/dt * z0 + d0/dt * z1

    x, y, z = proj3d.inv_transform(xd, yd, z, self.M)

    xs = self.format_xdata(x)
    ys = self.format_ydata(y)
    zs = self.format_zdata(z)
    return 'x=%s, y=%s, z=%s' % (xs, ys, zs)

I hope this helps!
Ben Root

···

On Tue, Nov 8, 2011 at 4:50 PM, Alejandro Weinstein <alejandro.weinstein@…287…> wrote:

Hi:

I am trying to use the event associated to motion_notify_event in a 3D

plot, and I found that the event does not have the zdata property.

The following code illustrate the problem:

##################################

from mpl_toolkits.mplot3d import Axes3D

import matplotlib.pyplot as plt

def on_hover(event):

print dir(event)

fig = plt.figure()

ax = fig.add_subplot(111, projection=‘3d’)

x = [1, 2, 3]

y = [1, 5, 4]

z = [3, 5, 6]

ax.scatter(x, y, z)

cid = fig.canvas.mpl_connect(‘motion_notify_event’, on_hover)

plt.show()

##################################

When you move the mouse over the figure, you can see the properties of event:

[‘doc’, ‘init’, ‘module’, ‘str’,

‘_update_enter_leave’, ‘button’, ‘canvas’, ‘dblclick’, ‘guiEvent’,

‘inaxes’, ‘key’, ‘lastevent’, ‘name’, ‘step’, ‘x’, ‘xdata’, ‘y’,

‘ydata’]

There is xdata, ydata, but not zdata.

Is zdata missing or should I be using a different event type?

Alejandro.