How to visualize scalar 2D data with Matplotlib?

前端 未结 4 994
梦谈多话
梦谈多话 2021-02-08 10:17

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

相关标签:
4条回答
  • 2021-02-08 10:42

    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()
    
    0 讨论(0)
  • 2021-02-08 10:48

    The following function creates boxes of half the size at the boundary (as shown in the attached picture).

    import matplotlib.pyplot as plt
    import numpy as np
    from scipy.ndimage.filters import convolve
    
    def pcolor_all(X, Y, C, **kwargs):
        X = np.concatenate([X[0:1,:], X], axis=0)
        X = np.concatenate([X[:,0:1], X], axis=1)
    
        Y = np.concatenate([Y[0:1,:], Y], axis=0)
        Y = np.concatenate([Y[:,0:1], Y], axis=1)
    
        X = convolve(X, [[1,1],[1,1]])/4
        Y = convolve(Y, [[1,1],[1,1]])/4
    
        plt.pcolor(X, Y, C, **kwargs)
    
    X, Y = np.meshgrid(
        [-1,-0.5,0,0.5,1],
        [-2,-1,0,1,2])
    
    C = X**2-Y**2
    
    plt.figure(figsize=(4,4))
    
    pcolor_all(X, Y, C, cmap='gray')
    
    plt.savefig('plot.png')
    

    0 讨论(0)
  • 2021-02-08 10:58

    In case anyone comes across this article looking for what I was looking for, I took the above example and modified it to use imshow with an input stack of frames, instead of generating and using contours on the fly. Starting with a 3D array of images of shape (nBins, nBins, nBins), called frames.

    def animate_frames(frames):
        nBins   = frames.shape[0]
        frame   = frames[0]
        tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
        for k in range(nBins):
            frame   = frames[k]
            tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
            del tempCS1
            fig.canvas.draw()
            #time.sleep(1e-2) #unnecessary, but useful
            fig.clf()
    
    fig = plt.figure()
    ax  = fig.add_subplot(111)
    
    win = fig.canvas.manager.window
    fig.canvas.manager.window.after(100, animate_frames, frames)
    

    I also found a much simpler way to go about this whole process, albeit less robust:

    fig = plt.figure()
    
    for k in range(nBins):
        plt.clf()
        plt.imshow(frames[k],cmap=plt.cm.gray)
        fig.canvas.draw()
        time.sleep(1e-6) #unnecessary, but useful
    

    Note that both of these only seem to work with ipython --pylab=tk, a.k.a.backend = TkAgg

    Thank you for the help with everything.

    0 讨论(0)
  • 2021-02-08 11:03

    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

    0 讨论(0)
提交回复
热议问题