Search code examples
pythonpython-3.xnumpymatplotlibmplot3d

surface plots for rectangular arrays in matplotlib


I am trying to use matplotlib to generate surface plot of a rectangular array (in my case, it's 47x70). The way this array is organized is:

47 - this dimension indicates the number of features

70 - this dimension indicates the number of samples

The array contains values for these features across each sample.

If I were to generate a surface plot in MATLAB or Octave, it's really simple.

vals = csvread("vals.csv"); surf(vals)

The output looks something like this -

Surface plot of a 47x70 array generated using numpy.random.randint

The array in vals.csv was generated as follows -

tempvals = np.random.randint(0, 10000, size = (47, 70))
np.savetxt("vals.csv", tempvals, delimiter=',')

How can I do this in python/matplotlib?

There is a pretty nice answer here. However, this answer uses some interpolation which I cannot use. I want to plot my values directly.

I tried writing something very basic. Like this -

import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt

vals = np.genfromtxt('vals.csv', delimiter=',')

fig1 = plt.figure(1, figsize = (9, 6))
ax1 = fig1.add_subplot(111, projection = '3d')
xax = np.arange(0, 46)
yax = np.arange(0, 70)
xax, yax = np.meshgrid(yax, xax)

Axes3D.plot3D(xax, yax, vals)

This, of course, fails with the error -

AttributeError: 'numpy.ndarray' object has no attribute 'has_data'

I have gone through this entire page but I am missing something. How can I generate surface plots for rectangular arrays?


Solution

  • I think this produces a result that is similar to the surf(vals) matlab plot you linked to: matplotlib - 3d surface from a rectangular array of heights.

    import numpy as np
    from mpl_toolkits.mplot3d import Axes3D
    import matplotlib.pyplot as plt
    
    # gen random 2d array and write to csv file
    tempvals = np.random.randint(0, 10000, size = (47, 70))
    np.savetxt("vals.csv", tempvals, delimiter=',')
    
    # read from csv
    vals = np.genfromtxt('vals.csv', delimiter=',')
    val_xdim, val_ydim = vals.shape
    
    # generate meshgrid for plot
    xax = np.arange(0, val_xdim)
    yax = np.arange(0, val_ydim)
    xax, yax = np.meshgrid(yax, xax)
    
    # plot and save
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    surf = ax.plot_surface(xax, yax, vals, rstride=1, cstride=1, cmap='viridis', linewidth=0, antialiased=False)
    ax.plot_wireframe(xax, yax, vals, color='k', lw=0.05, alpha=0.3)
    fig.colorbar(surf, shrink=0.5, aspect=5)
    plt.savefig("rand_3d_surf.png", dpi=160)
    

    Which produces: Example 3d surface plot