如何为Matplotlib 3D绘图添加沿X轴的渐变色?
Matplotlib 3D矩形杆X轴渐变色问题排查与解决方案
问题原因
你当前代码的核心问题是颜色数组维度不匹配:
- 你的
vertices包含8个顶点,因此colors生成了8个RGBA颜色值,但Poly3DCollection的facecolors参数需要的是每个面对应的颜色(你定义了6个面)。 - 当颜色数量和面数量不匹配时,Matplotlib无法正确渲染,最终导致图形变黑。
另外,要实现沿X轴的渐变效果,应该基于每个面的整体X位置分配颜色,而非单个顶点的X值——比如前后端面的所有顶点X值一致,需要用面的平均X坐标来映射颜色。
修复后的代码
下面是修正后的代码,针对每个面计算平均X坐标,再映射到gnuplot配色:
import matplotlib.pyplot as plt from mpl_toolkits.mplot3d.art3d import Poly3DCollection import matplotlib.cm as cm import numpy as np fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # 定义矩形杆顶点 vertices = np.array([ [0, -0.5, -0.5], [0, -0.5, 0.5], [0, 0.5, 0.5], [0, 0.5, -0.5], [10, -0.5, -0.5], [10, -0.5, 0.5], [10, 0.5, 0.5], [10, 0.5, -0.5] ]) # 定义面 faces = np.array([ [0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7] ]) # 计算每个面的平均X坐标,作为颜色映射依据 face_x = [vertices[face, 0].mean() for face in faces] norm = plt.Normalize(min(face_x), max(face_x)) # 为每个面分配对应颜色 colors = cm.gnuplot(norm(face_x)) # 创建3D多边形集合,传入每个面的颜色 rect = Poly3DCollection(vertices[faces], alpha=0.8, facecolors=colors, edgecolors='black') ax.add_collection3d(rect) # 设置轴范围和标签 ax.set_xlim([0, 10]) ax.set_ylim([-1, 1]) ax.set_zlim([-1, 1]) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') plt.show()
自定义6色渐变的替代方法
如果需要自定义6个颜色的渐变效果,可以用LinearSegmentedColormap创建专属色卡,示例如下:
import matplotlib.pyplot as plt from mpl_toolkits.mplot3d.art3d import Poly3DCollection from matplotlib.colors import LinearSegmentedColormap import numpy as np fig = plt.figure() ax = fig.add_subplot(111, projection='3d') vertices = np.array([ [0, -0.5, -0.5], [0, -0.5, 0.5], [0, 0.5, 0.5], [0, 0.5, -0.5], [10, -0.5, -0.5], [10, -0.5, 0.5], [10, 0.5, 0.5], [10, 0.5, -0.5] ]) faces = np.array([ [0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7] ]) # 自定义6个渐变颜色(可根据需求修改) custom_colors = [ '#0000FF', '#00FFFF', '#00FF00', '#FFFF00', '#FF7F00', '#FF0000' ] # 创建线性渐变配色卡 custom_cmap = LinearSegmentedColormap.from_list('custom_6color', custom_colors, N=6) # 计算每个面的X位置,映射到自定义色卡 face_x = [vertices[face, 0].mean() for face in faces] norm = plt.Normalize(min(face_x), max(face_x)) colors = custom_cmap(norm(face_x)) rect = Poly3DCollection(vertices[faces], alpha=0.8, facecolors=colors, edgecolors='black') ax.add_collection3d(rect) ax.set_xlim([0, 10]) ax.set_ylim([-1, 1]) ax.set_zlim([-1, 1]) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') plt.show()
内容的提问来源于stack exchange,提问作者Prashant Priyadarshi
相关产品推荐
相关产品推荐

