3D plot with Matplotlib 3D plot with Matplotlib python python

3D plot with Matplotlib


I agree with Ajean. I believe the problem arises because each matplotlib's artist (i.e. PolygonCollection) is rendered separately. There is no way different faces from the same object to be rendered on different sides of another object in the scene.

Here is a useful piece of code :

from mpl_toolkits.mplot3d import axes3dimport matplotlib.pyplot as pltfrom matplotlib import cmimport numpy as npfile_path = "./3D_surface_and_contour.jpg"p = 0.05f = -0.01def get_data(p):    x, y, z = axes3d.get_test_data(p)    z = f * z    return x, y, zdef plot_3d_contour(p, f):    nrows = 4    ncols = 5    x, y, z = get_data(p)    x_min, x_max = np.min(x), np.max(x)    y_min, y_max = np.min(y), np.max(y)    z_min, z_max = np.min(z), np.max(z)    fig = plt.figure(figsize=(15, 10))    for n in range(nrows * ncols):        i = n % ncols        j = n / ncols        k = n + 1        if j == 0:            azim = -60 + (i - 2) * 15            elev = 30        elif j == 1:            azim = -60            elev = 30 + (i - 2) * 5        elif j == 2:            azim = 60 + (i - 2) * 10            elev = 30        elif j == 3:            azim = 60            elev = 30 + (i - 2) * 5        ax = fig.add_subplot(nrows, ncols, k, projection='3d')        ax.set_title("azim=" + str(azim) + " elev=" + str(elev))        ax.tick_params(labelsize=8)        ax.view_init(azim=azim, elev=elev)        ax.plot_surface(x, y, z, rstride=10, cstride=10, alpha=0.3)        ax.contourf(x, y, z, zdir='z', offset=z_min, cmap=cm.coolwarm)        ax.contourf(x, y, z, zdir='x', offset=x_min, cmap=cm.coolwarm)        if j == 0 or j == 1:            ax.contourf(x, y, z, zdir='y', offset=y_max, cmap=cm.coolwarm)        elif j == 2 or j == 3:            ax.contourf(x, y, z, zdir='y', offset=y_min, cmap=cm.coolwarm)        ax.set_xlabel('X')        ax.set_xlim(x_min, x_max)        ax.set_ylabel('Y')        ax.set_ylim(y_min, y_max)        ax.set_zlabel('Z')        ax.set_zlim(z_min, z_max)    plt.savefig(file_path, dpi=80)    plt.close()plot_3d_contour(p, f)

which gives the following image :

enter image description here

The first two rows are produced by a code similar to yours. You might notice that setting the elevation with view_init to a higher value solve the problem. But it is not satisfactory. I have also determined the influence of the range of the z-values (not shown here), the bug seems to appear only when this range is small (you can use the f parameter to test it) which explain why the example does not suffer from it.

The solution I propose is to replace :

ax.contourf(x, y, scalar_field, zdir='y', offset=y_dim/2+1, cmap=cm.coolwarm)

by :

ax.contourf(x, y, scalar_field, zdir='y', offset=-y_dim/2-1, cmap=cm.coolwarm)

in your code and add this additional line :

ax.view_init(azim=60, elev=30)

As shown in the last two rows of the previous image, this way you will be able to avoid the whims of matplotlib.