Reputation: 758
I'm using following line for plotting a 3D surface:
surf = ax3.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha=0.5, linewidth=0, cmap=cm.jet,antialiased=True)
Now the color comes very nice, although a bit scaly appearance, though fine.
But I want to change the surface color w.r.t. another data, stored in list
as:
m = [104.48, 111.73,109.93,139.95,95.05,150.49,136.96,157.75]
I was trying with:
norm = cls.Normalize() # Norm to map the 'm' values to [0,1]
norm.autoscale(m)
cmap = cm.ScalarMappable(norm, 'jet')
surf = ax3.plot_surface(X, Y, Z, rstride=5, cstride=5, alpha=0.5, linewidth=0, color=cmap.to_rgba(m), antialiased=True)
But this is raising an error as cmap.to_rgba
takes 1D arrays only.
Any suggestions on how can I be able to change the colormap
of the surface would be highly appreciated.
Upvotes: 11
Views: 45894
Reputation: 105
I find the previous answers somewhat misleading. The facecolors should be one column and row smaller than the grid values! Otherwise, the faces will be colorized shifted according to one value in the face corner (may not matter for many values). This becomes obvious for a few symetric values (see example below). You could either calculate new values in the middle of the faces or average the values at the face corners, which is what I needed for measured values. Likewise, it would be possible to linearly interpolate the intermediate values and plot more faces. Here is an example for comparison:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
x_lst = np.linspace(-5, 5, 4)
y_lst = np.linspace(-5, 5, 4)
x_grid, y_grid = np.meshgrid(x_lst, y_lst)
z_grid = x_grid + y_grid
# values at face corners (at the grid points)
c_grid = np.abs(x_grid + y_grid) # same size like x_val, y_val, z_val
print(c_grid)
# averaged corner values for each face
c_faces = np.lib.stride_tricks.sliding_window_view(c_grid, (2,2))
c_faces = np.mean(c_faces, axis=(2, 3)) # size reduces by 1
print(c_faces)
# color map and normalization
c_min, c_max = np.min(c_grid), np.max(c_grid) # could also be min and max of c_faces
norm = mpl.colors.Normalize(vmin=c_min, vmax=c_max)
cmap = mpl.cm.viridis
for c_vals in [c_grid, # values at face corners
c_faces]: # averaged corner values
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(x_grid, y_grid, z_grid,
rstride=1, cstride=1, # no downsampling
facecolors = cmap(norm(c_vals)), shade=False)
cbar = plt.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax, pad=0.2)
ax.dist = 8
plt.show()
Shifted plot with grid values: Plot with averaged values:
Upvotes: 0
Reputation: 5408
Well, it looks awful but I think you can adapt it:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
my_col = cm.jet(np.random.rand(Z.shape[0],Z.shape[1]))
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors = my_col,
linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)
I would not use jet but some linear colormap like cubehelix
. You can trick the eye easily using the wrong colormap (one of many posts on that topic)
Upvotes: 10
Reputation: 3473
To get the correct colors, use the Z values to pick values from the color map:
my_col = cm.jet(Z/np.amax(Z))
The result:
using otherwise the same code as @Moritz.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
my_col = cm.jet(Z/np.amax(Z))
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors = my_col,
linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)
plt.show()
Upvotes: 9