`plot_surface`

A 3D surface plot is the representation of a three-dimensional data set, showing the relationship between a dependent variable (Y) against two independent variables (X and Z). This type of chart can be created with the `plot_surface`

function, specifying a 3D projection. Note that surface plots are the 3D representation of contour plots.

```
import matplotlib.pyplot as plt
import numpy as np
# Sample data
X, Y = np.meshgrid(np.linspace(-8, 8),
np.linspace(-8, 8))
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R) / R
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
# 3D surface plot
ax.plot_surface(X, Y, Z)
# plt.show()
```

**Adding a title and axis labels**

When using 3D charts it is very important to specify the axis labels for better understanding of the plot. You can add the axis labels for the X, Y and Z axis with the `set_xlabel`

, `set_ylabel`

and `set_zlabel`

functions, respectively. You can also add a title to the figure with the `title`

function.

```
import matplotlib.pyplot as plt
import numpy as np
# Sample data
X, Y = np.meshgrid(np.linspace(-8, 8),
np.linspace(-8, 8))
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R) / R
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
# 3D surface plot
ax.plot_surface(X, Y, Z)
# Axis labels
ax.set_xlabel('X-axis label')
ax.set_ylabel('Y-axis label')
ax.set_zlabel('Z-axis label')
# Title
plt.title("3D surface plot")
# plt.show()
```

The color of the surface is blue by default, but specifying a new color to the `color`

argument of the function you can customize it. In the following example we are changing the color to `'lightgreen'`

.

```
import matplotlib.pyplot as plt
import numpy as np
# Sample data
X, Y = np.meshgrid(np.linspace(-8, 8),
np.linspace(-8, 8))
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R) / R
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
# 3D surface plot
ax.plot_surface(X, Y, Z, color = 'lightgreen')
# plt.show()
```

**Transparency**

The 3D surface is not opaque, but if you want to make it more transparent you can use the `alpha`

argument. Note that you can also make the surface opaque setting `antialiased = False`

.

```
import matplotlib.pyplot as plt
import numpy as np
# Sample data
X, Y = np.meshgrid(np.linspace(-8, 8),
np.linspace(-8, 8))
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R) / R
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
# 3D surface plot
ax.plot_surface(X, Y, Z, alpha = 0.7)
# plt.show()
```

**Width and color of the lines**

If you made your surface more transparent you might want to make the lines more visible. In this case you can customize the width and color of the lines with `linewidth`

and `edgecolor`

, respectively.

```
import matplotlib.pyplot as plt
import numpy as np
# Sample data
X, Y = np.meshgrid(np.linspace(-8, 8),
np.linspace(-8, 8))
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R) / R
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
# 3D surface plot
ax.plot_surface(X, Y, Z, alpha = 0.7,
linewidth = 0.3, edgecolor = 'black')
# plt.show()
```

**Color palette**

The color of the surface can also be based on the values of a continuous variable, so higher values will have a different color than the lower values. You can specify a color palette with the `cmap`

argument of the function, like the `'Spectral_r'`

matplotlib color palette.

```
import matplotlib.pyplot as plt
import numpy as np
# Sample data
X, Y = np.meshgrid(np.linspace(-8, 8),
np.linspace(-8, 8))
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R) / R
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
# 3D surface plot
ax.plot_surface(X, Y, Z, cmap = 'Spectral_r')
# plt.show()
```

**Color bar**

Considering that your surface is colored with a color palette, you might want to add a color bar as a legend. For this purpose you will need to use the `colorbar`

function as in the example below. Note that you can customize the size of the color bar with the `shrink`

and `aspect`

arguments of the function.

```
import matplotlib.pyplot as plt
import numpy as np
# Sample data
X, Y = np.meshgrid(np.linspace(-8, 8),
np.linspace(-8, 8))
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R) / R
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
# 3D surface plot
plot = ax.plot_surface(X, Y, Z, cmap = 'bwr')
fig.colorbar(plot, ax = ax, shrink = 0.5, aspect = 10)
# plt.show()
```

3D surface plots are companion plots of contours. You can add both plots on the same chart adding a contour to the 3D plot. Note that you will need to specify the offset based on your data. You can also customize the Z-axis limits if needed.

```
import matplotlib.pyplot as plt
import numpy as np
# Sample data
X, Y = np.meshgrid(np.linspace(-8, 8),
np.linspace(-8, 8))
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R) / R
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
# 3D surface plot
ax.plot_surface(X, Y, Z, cmap = 'viridis')
# Contour
ax.contour(X, Y, Z, lw = 3, cmap = 'viridis', offset = -1)
# Z-axis limits
ax.set(zlim = (-1, 0.8))
# plt.show()
```

**Surface plot with X and Y contour**

The contours can also be placed on the X and Y directions making use of the `zdir`

argument of the `contour`

function. You will need to specify the offset to the maximum value of each axis.

```
import matplotlib.pyplot as plt
import numpy as np
# Sample data
X, Y = np.meshgrid(np.linspace(-8, 8),
np.linspace(-8, 8))
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R) / R
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
# 3D surface plot
ax.plot_surface(X, Y, Z, cmap = 'autumn_r')
# Contours for X and Y axis
ax.contour(X, Y, Z, lw = 3, cmap = 'autumn_r', offset = np.max(X), zdir = 'x')
ax.contour(X, Y, Z, lw = 3, cmap = 'autumn_r', offset = np.max(Y), zdir = 'y')
# plt.show()
```

**Surface plot with filled contour**

If you want to add a filled contour the process is the same but with the `contourf`

function. In the following example we add a contour and also a filled contour to the 3D surface plot for better understanding of the data.

```
import matplotlib.pyplot as plt
import numpy as np
# Sample data
X, Y = np.meshgrid(np.linspace(-8, 8),
np.linspace(-8, 8))
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R) / R
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
# 3D surface plot
ax.plot_surface(X, Y, Z, cmap = 'Spectral_r', alpha = 0.9)
# Filled contour with contour lines
ax.contour(X, Y, Z, lw = 2, colors = 'black', offset = -1)
ax.contourf(X, Y, Z, cmap = 'Spectral_r', offset = -1, alpha = 0.75)
# Z-axis limits
ax.set(zlim = (-1, 0.8))
# plt.show()
```

See also