I'm using matplotlib.imshow
to get an interactive display of a 2D array. The x/y coordinate under the cursor is displayed at the bottom left of the window. Is it possible to also get the value of the array under the cursor as well?
Asked
Active
Viewed 3.1k times
34

ajwood
- 18,227
- 15
- 61
- 104
-
http://stackoverflow.com/questions/14349289/in-a-matplotlib-figure-window-with-imshow-how-can-i-remove-hide-or-redefine possible duplicate – tacaswell Feb 07 '13 at 15:55
-
http://stackoverflow.com/questions/14666114/matplotlib-coordinates-format/14666889#14666889 related to – tacaswell Feb 07 '13 at 15:55
-
I was afraid this would be a duplicate (triplicate, quadruplicate..) but searched and could not find.. – ajwood Feb 07 '13 at 16:04
-
no worries, just adds more google post-markers for the future – tacaswell Feb 07 '13 at 16:29
2 Answers
25
You simply need to re-assign ax.format_coord
. See this example from the documentation.
(code lifted directly from example)
"""
Show how to modify the coordinate formatter to report the image "z"
value of the nearest pixel given x and y
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
X = 10*np.random.rand(5,3)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(X, cmap=cm.jet, interpolation='nearest')
numrows, numcols = X.shape
def format_coord(x, y):
col = int(x+0.5)
row = int(y+0.5)
if col>=0 and col<numcols and row>=0 and row<numrows:
z = X[row,col]
return 'x=%1.4f, y=%1.4f, z=%1.4f'%(x, y, z)
else:
return 'x=%1.4f, y=%1.4f'%(x, y)
ax.format_coord = format_coord
plt.show()

tacaswell
- 84,579
- 22
- 210
- 199
7
I needed something I could re-use, so I encapsulated the solution through a class:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import numpy as np
class imshow_show_z:
def __init__(self, ax, z, x, y):
self.ax = ax
self.x = x
self.y = y
self.z = z
self.dx = self.x[1] - self.x[0]
self.dy = self.y[1] - self.y[0]
self.numrows, self.numcols = self.z.shape
self.ax.format_coord = self.format_coord
def format_coord(self, x, y):
col = int(x/self.dx+0.5)
row = int(y/self.dy+0.5)
#print "Nx, Nf = ", len(self.x), len(self.y), " x, y =", x, y, " dx, dy =", self.dx, self.dy, " col, row =", col, row
xyz_str = ''
if ((col>=0) and (col<self.numcols) and (row>=0) and (row<self.numrows)):
zij = self.z[row,col]
#print "zij =", zij, ' |zij| =', abs(zij)
if (np.iscomplex(zij)):
amp = abs(zij)
phs = np.angle(zij) / np.pi
if (zij.imag >= 0.0):
signz = '+'
else:
signz = '-'
xyz_str = 'x=' + str('%.4g' % x) + ', y=' + str('%.4g' % y) + ',' \
+ ' z=(' + str('%.4g' % zij.real) + signz + str('%.4g' % abs(zij.imag)) + 'j)' \
+ '=' + str('%.4g' % amp) + r'*exp{' + str('%.4g' % phs) + u' π j})'
else:
xyz_str = 'x=' + str('%.4g' % x) + ', y=' + str('%.4g' % y) + ', z=' + str('%.4g' % zij)
else:
xyz_str = 'x=%1.4f, y=%1.4f'%(x, y)
return xyz_str
def new_imshow(ax, x, y, z, *args, **kwargs):
assert(len(x) == z.shape[1])
assert(len(y) == z.shape[0])
dx = x[1] - x[0]
dy = y[1] - y[0]
if (np.iscomplex(z).any()):
zabs = abs(z)
else:
zabs = z
# Use this to center pixel around (x,y) values
extent = (x[0]-dx/2.0, x[-1]+dx/2.0, y[0]-dy/2.0, y[-1]+dy/2.0)
# Use this to let (x,y) be the lower-left pixel location (upper-left when origin = 'lower' is not used)
#extent = (x[0]-dx/2.0, x[-1]+dx/2.0, y[0]-dy/2.0, y[-1]+dy/2.0)
im = ax.imshow(zabs, extent = extent, *args, **kwargs)
imshow_show_z(ax, z, x, y)
ax.set_xlim((x[0], x[-1]))
ax.set_ylim((y[0], y[-1]))
return im
Example usage:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-5, 10, 100)
y = np.linspace(-2.0, 5, 51)
xx, yy = np.meshgrid(x, y)
Z = np.sin(xx**2 + yy**2) / (xx**2 + yy**2)
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
im = new_imshow(ax, x, y, Z, aspect = 'auto', origin = 'lower', interpolation = 'nearest')
ax.set_xlabel('x')
ax.set_ylabel('y')
plt.show()
Features:
- Can show both floats and complex values. For complex, the real+imaginary parts and polar form are shown.
- Will set the extent for you, based on the x and y arrays. Note that the matplotlib example works only if you don't use the extent keyword.
- Pixels are centered around their (x,y) position instead of (x,y) being the lower (or upper) left location.

big_gie
- 2,829
- 3
- 31
- 45
-
Reading this again, the use use of that class is a bit funny as you don't keep a ref to it but rely on the format_coord ref to keep the object alive. You can run exactly the same thing by just doing a closure directly. – tacaswell Dec 30 '14 at 16:58