5

I've been looking around for answers but I can't seem to see why in my code I can't get the projected contours to show up "behind" the surface.

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

fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.array([[200,800,1500,2000,3000],[200,700,1500,2000,3000],[200,800,1500,2000,3000],[200,800,1500,2000,3000]])
Y = np.array([[50,50,50,50,50],[350,350,350,350,350],[500,500,500,500,500],[1000,1000,1000,1000,1000]])
Z = np.array([[0,0,33,64,71],[44,62,69,74,76],[59,67,72,75,77],[63,68,73,76,77]])

ax.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha=0.5)
cset = ax.contourf(X, Y, Z, zdir='z', offset=0, cmap=cm.coolwarm)
cset = ax.contourf(X, Y, Z, zdir='x', offset=200, cmap=cm.coolwarm)
cset = ax.contourf(X, Y, Z, zdir='y', offset=1000, cmap=cm.coolwarm)

ax.set_xlabel('X')
ax.set_xlim(200, 3000)
ax.set_ylabel('Y')
ax.set_ylim(0, 1000)
ax.set_zlabel('Z')
ax.set_zlim(0, 100)

plt.show()

I have been using the one of the Filled Contour Plots from this page as template: http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#scatter-plots

At the moment the best I could get was to change the alpha value of the contours. I also tried plotting the surface after the contours but that didn't change anything.

Any advice would be most welcome !

Sorade
  • 915
  • 1
  • 14
  • 29
  • Your code does not run: `Unknown projection '3d'` – Chiel Apr 12 '16 at 09:03
  • 1
    i just added `from mpl_toolkits.mplot3d import Axes3D` in order to make this mwe work. – WWhisperer Apr 12 '16 at 09:07
  • Apologies for that... I've edited the question. – Sorade Apr 12 '16 at 09:18
  • To me it appears like a bug. I managed to reproduce your problem, but even with setting the `zorder` you cannot make the contour appear behind the surface. The problem remains independent of the chosen offset for the contour that has `zdir='y'` – Chiel Apr 12 '16 at 09:21
  • Okay, thanks. I've tried with unfilled contours and it works. even though I'd prefer filled ones – Sorade Apr 12 '16 at 09:26
  • For me only the last (zdir='y') contour is displayed incorrectly. If I put in on the other side (offset=50) it is shown correctly. I guess the contour plots do not expect something else to be between zero and the offset value. – Dusch Apr 12 '16 at 12:31

1 Answers1

5

The problem you're experiencing is a well-known bug/missing feature in matplotlib. Quoting a co-lead developer of matplotlib:

As I understand it all the 3D plotting as a bit of a hack.

The issue boils down to that contiguous blocks of surfaces are plotted one after the other, such that each is either fully behind any other, or fully in front of it. This will imply that any two objects are drawn properly only from certain angles, and there's no guarantee that all objects will be drawn with the proper order at reasonable angles of interest.

One would think that setting zorder properties for the various objects could affect the result, but this is not the case, since

splitting up the plotting is that 'above' and 'below' are determined in a some what arcane way

in other words

Axes3D ignores zorder and draws artists in the order it thinks they should be.

This manifests itself in all sorts of 3d plots, such as when plotting text with surfaces, plotting complicated surfaces, or even plotting 3d bar plots (even though one could expect that it's easier to determine the plotting order within a single function call).

For surfaces plotted with a single command (i.e. those that comprise a single Poly3DCollection) you can use the set_zsort() method to give a very crude hint to matplotlib regarding the preferred plotting order. Other than this, your only option is moving your surfaces and viewing angles around (if at all possible) in a way that the issue is not visible, or at least not entirely apparent. Another option proposed by @tcaswell is to use mayavi instead of mplot3d (but I've never done that myself).

Community
  • 1
  • 1