Search code examples
pythonmatplotlibmatplotlib-3d

Scale vertical (z) axis of 3D surface plot with plot_surface


How can I scale the Z-axis of a surface plot in matplotlib? Take the following example dataset and plot.

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
x, y = np.meshgrid(x, y)
# Generate a 3D surface 
z = np.exp(-0.1*x**2 - 0.1*y**2)

fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d')
# Create the surface plot
surf = ax.plot_surface(x, y, z, cmap='plasma')
plt.show()

3d plot

And I want to scale it so it looks like the below plot (which I have done by adjusting the axis limits) but with with the z-axis limits still between 0 and 1. Is this possible? I couldn't find anything in the docs about how to do this. For illustration the persp function in R has the expand argument that does exactly what I want to do.

fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d')
# Create the surface plot
surf = ax.plot_surface(x, y, z, cmap='plasma')
ax.set_zlim([0, 2.5])
plt.show()

Scaled 3d plot


Update

For clarification, here's an example of exactly what I'm trying to do using R code. I'm trying to adjust the z-axis aspect ratio. With the persp function in R we can just use the `expand argument to do this. For example:

# Generate synthetic data for demonstration purposes
x <- seq(-5, 5, length.out = 50)
y <- seq(-5, 5, length.out = 50)
z <- matrix(0, length(x), length(y))

# Generate a Gaussian surface
for(i in 1:length(x)) {
  for(j in 1:length(y)) {
    z[i, j] <- exp(-0.1 * x[i]^2 - 0.1 * y[j]^2)
  }
}

nrz <- nrow(z)
ncz <- ncol(z)
# Create a function interpolating colors in the range of specified colors
jet.colors <- colorRampPalette(c("#0d0887", "#cc4678", "#f0f921"))
# Generate the desired number of colors from this palette
nbcol <- 100
color <- jet.colors(nbcol)
# Compute the z-value at the facet centres
zfacet <- z[-1, -1] + z[-1, -ncz] + z[-nrz, -1] + z[-nrz, -ncz]
# Recode facet z-values into color indices
facetcol <- cut(zfacet, nbcol)

expand = 1.0

persp(x, y, z, theta = 45, phi = 30, expand = 1.0, col = color[facetcol])

expand = 1.0

expand = 0.3

persp(x, y, z, theta = 45, phi = 30, expand = 0.3, col = color[facetcol])

expand = 0.3


Solution

  • It sounds like you're looking to change the aspect ratio of the 3D plot. Following your R example where you change the aspect ratio to be 0.3 in the z, you can do this in matplotlib using the ax.set_box_aspect function. The function takes a tuple that provides the XYZ ratios.

    ax.set_box_aspect((1,1,0.3))