How to visualize scalar 2D data with Matplotlib?


Question

So i have a meshgrid (matrices X and Y) together with scalar data (matrix Z), and i need to visualize this. Preferably some 2D image with colors at the points showing the value of Z there. I've done some research but haven't found anything which does exactly what i want.

pyplot.imshow(Z) has a good look, but it doesn't take my X and Y matrices, so the axes are wrong and it is unable to handle non-linearly spaced points given by X and Y.

pyplot.pcolor(X,Y,Z) makes colored squares with colors corresponding to the data at one of its corners, so it kind of misrepresents the data (it should show the data in its center or something). In addition it ignores two of the edges from the data matrix.

I pretty sure there must exist some better way somewhere in Matplotlib, but the documentation makes it hard to get an overview. So i'm asking if someone else knows of a better way. Bonus if it allows me to refresh the matrix Z to make an animation.

1
10
2/26/2011 3:10:28 PM

Accepted Answer

This looks nice, but it's inefficient:

from pylab import *
origin = 'lower'

delta = 0.025

x = y = arange(-3.0, 3.01, delta)
X, Y = meshgrid(x, y)
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10 * (Z1 - Z2)

nr, nc = Z.shape

CS = contourf(
    X, Y, Z,
    levels = linspace(Z.min(), Z.max(), len(x)),
    ls = '-',
    cmap=cm.bone,
    origin=origin)

CS1 = contour(
    CS,
    levels = linspace(Z.min(), Z.max(), len(x)),
    ls = '-',
    cmap=cm.bone,
    origin=origin)

show()

It it were me, I'd re-interpolate (using scipy.interpolate) the data to a regular grid and use imshow(), setting the extents to fix the axes.

fine contour

Edit (per comment):

Animating a contour plot can be accomplished like this, but, like I said, the above is inefficient just plain abuse of the contour plot function. The most efficient way to do what you want is to employ SciPy. Do you have that installed?

import matplotlib
matplotlib.use('TkAgg') # do this before importing pylab
import time
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

def animate():
    origin = 'lower'
    delta = 0.025

    x = y = arange(-3.0, 3.01, delta)
    X, Y = meshgrid(x, y)
    Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
    Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
    Z = 10 * (Z1 - Z2)

    CS1 = ax.contourf(
        X, Y, Z,
        levels = linspace(Z.min(), Z.max(), 10),
        cmap=cm.bone,
        origin=origin)

    for i in range(10):
        tempCS1 = contourf(
            X, Y, Z,
            levels = linspace(Z.min(), Z.max(), 10),
            cmap=cm.bone,
            origin=origin)
        del tempCS1
        fig.canvas.draw()
        time.sleep(0.1)
        Z += x/10

win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate)
plt.show()
10
2/26/2011 6:17:15 PM

If your meshgrid has uniform spacing, you could continue to use pcolor, but just shift X and Y for the purposes of centering the data at the particular values rather than at the corners.

You could also use a scatter plot to explicitly place points of some size at the exact X and Y points and then set the color to Z:

x = numpy.arange(10)
y = numpy.arange(10)
X,Y = numpy.meshgrid(x,y)
Z = numpy.arange(100).reshape((10,10))
scatter(X,Y,c=Z,marker='s',s=1500) 
#I picked a marker size that basically overlapped the symbols at the edges
axis('equal')

or:

pcolor(X+0.5,Y+0.5,Z)
axis('equal')

or as Paul suggested, using one of the contour functions


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon