How can I combine a 3D scatter plot with a 3D surface plot while keeping the surface plot transparent so that I can still see all the points?
3 Answers
To combine various types of plots in the same graph you should use the function
plt.hold(True).
The following code plots a 3D scatter plot with a 3D surface plot:
from mpl_toolkits.mplot3d import *
import matplotlib.pyplot as plt
import numpy as np
from random import random, seed
from matplotlib import cm
fig = plt.figure()
ax = fig.gca(projection='3d') # to work in 3d
plt.hold(True)
x_surf=np.arange(0, 1, 0.01) # generate a mesh
y_surf=np.arange(0, 1, 0.01)
x_surf, y_surf = np.meshgrid(x_surf, y_surf)
z_surf = np.sqrt(x_surf+y_surf) # ex. function, which depends on x and y
ax.plot_surface(x_surf, y_surf, z_surf, cmap=cm.hot); # plot a 3d surface plot
n = 100
seed(0) # seed let us to have a reproducible set of random numbers
x=[random() for i in range(n)] # generate n random points
y=[random() for i in range(n)]
z=[random() for i in range(n)]
ax.scatter(x, y, z); # plot a 3d scatter plot
ax.set_xlabel('x label')
ax.set_ylabel('y label')
ax.set_zlabel('z label')
plt.show()
result:
you can see some other examples with 3d plots here:
http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html
I've changed the colours of the surface plot from the default to a colormap "hot" in order to distinguish the colours of the two plots - now, it's seen that the surface plot overrides the scatter plot, independently of the order...
EDIT: To fix that issue, it should be used transparency in the colormap of the surface plot; adding the code in: Transparent colormap and changing the line:
ax.plot_surface(x_surf, y_surf, z_surf, cmap=cm.hot); # plot a 3d surface plot
to
ax.plot_surface(x_surf, y_surf, z_surf, cmap=theCM);
we get:

- 21,988
- 13
- 81
- 109

- 2,839
- 21
- 28
-
1A work around to this is to (by hand) split the data in the scatter plot in half (the data above the plane and the data below), and then plot the three things in the proper order. see http://stackoverflow.com/questions/14824893/how-to-draw-diagrams-like-this/14825951#14825951 – tacaswell Mar 05 '13 at 20:04
-
If you need 'true' 3D rendering, look into mayavi from enthought. http://code.enthought.com/projects/mayavi/ – tacaswell Mar 05 '13 at 20:05
-
1@tcaswell I noticed that even changing the order of the plots, the surface appears always on top, and that's strange... (the zorder also doesn't work) That's why I've chosen to use transparencies. – sissi_luaty Mar 05 '13 at 20:45
-
2hold has been deprecated and hold(True) is the default behavior in matplotlib 2.2 https://matplotlib.org/api/api_changes.html Not sure how to update the answer in view of this.. – Yuri Feldman May 04 '18 at 16:40
-
It seems that the `zorder` argument does still work for 3d lines. It's kind of a messy hack, but I have plotted the scatter over the top of the surface plot by iterating over the points and plotting them individually as a line from the point to itself. – RGWinston Apr 24 '19 at 15:52
Using siluaty's example; instead of using transparency through the cmap=theCM command, you can adjust the alpha value. This may get you what you want?
ax.plot_surface(x_surf, y_surf, z_surf, cmap=cm.hot, alpha=0.2)
-
I wanted to know if there was something like alpha, and your comment made that obvious! – bzm3r Apr 01 '15 at 18:06
-
2does anyone know how to make the scatter points come out bright and visible without setting a low alpha? – Aerinmund Fagelson Oct 19 '18 at 14:48
-
3A [post](https://github.com/matplotlib/matplotlib/issues/7684/) written by a matplotlib developer: _this is a known limitation of mplot3d. It is not a true 3d rendering toolkit, and it is constrained by the layering engine of matplotlib. Each artist gets a single zorder value, which determines the order in which artists and collections are drawn. As such, the rendering of mixed 3d scenes is impossible in the general case because either the surface artist or the scatter artist has to be drawn before the other._ – Baumann Apr 25 '19 at 01:34
As others mentioned, if you want transparent 3d plot, just provide alpha argument:
# elve, azim are custom viewpoint/angle
ax = plt.axes(projection='3d', elev=35, azim=-125)
ax.plot_surface(x, y, z, alpha=0.7)
ax.plot(scatter_x, scatter_y, scatter_z, 'b.', markersize=10, label='top')
If you want to plot points on top of the 3d plot, use zorder. For example, the following code will generate:
ax = plt.axes(projection='3d', elev=35, azim=-125)
ax.plot_surface(x, y, z, cmap=plt.cm.coolwarm, linewidth=0.1, zorder=1)
ax.plot(scatter_x, scatter_y, scatter_z, 'b.', markersize=10, label='top', zorder=4)

- 12,710
- 2
- 40
- 44