将相同的颜色图和颜色条应用于多个 3D 图

Impose same colormap and colorbar to multiple 3D plot

目标是输出两个不同的 3D 图 (plot_surface),以 "fair" 的方式为表面 (facecolors) 提供特定颜色,即使用相同的颜色比例对于两个图形(固定相同的 x、y 和 z 轴,但这很容易)。此外,颜色条必须相同(即相同的刻度和范围)。换句话说,假设在图 1 中,(任意)值 8 与深红色相关联。然后,还必须申请图 2。请注意,在示例中,两个图形的 X、Y 和 Z 相同,以使事情更简单。与表面相关的颜色有什么变化(即 V1 和 V2)。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
# Generate data. V1 (V2) will determine the colours of the first figure1 (figure2)
X = np.array([[ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500],
              [ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500],
              [ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500],
              [ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500],
              [ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500],
              [ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500],
              [ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500],
              [ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500],
              [ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500]])
Y = np.array([[ 75,  75,  75,  75,  75,  75,  75,  75,  75,  75],
               [125, 125, 125, 125, 125, 125, 125, 125, 125, 125],
               [175, 175, 175, 175, 175, 175, 175, 175, 175, 175],
               [225, 225, 225, 225, 225, 225, 225, 225, 225, 225],
               [275, 275, 275, 275, 275, 275, 275, 275, 275, 275],
               [325, 325, 325, 325, 325, 325, 325, 325, 325, 325],
               [375, 375, 375, 375, 375, 375, 375, 375, 375, 375],
               [425, 425, 425, 425, 425, 425, 425, 425, 425, 425],
               [475, 475, 475, 475, 475, 475, 475, 475, 475, 475]])
Z = pd.DataFrame([[2.11, 2.14, 2.12, 2.10, 2.09, 2.08, 2.07, 2.07, 2.08, 2.05],
                   [2.01, 2.03, 1.99, 1.96, 1.95, 1.93, 1.90, 1.90, 1.92, 1.92],
                   [1.89, 1.90, 1.90, 1.94, 1.92, 1.89, 1.88, 1.87, 1.86, 1.86],
                   [1.79, 1.79, 1.75, 1.79, 1.77, 1.78, 1.78, 1.78, 1.79, 1.76],
                   [1.75, 1.77, 1.8, 1.79, 1.8, 1.77, 1.73, 1.73, 1.77, 1.77],
                   [1.72, 1.76, 1.77, 1.77, 1.79, 1.8, 1.78, 1.78, 1.74, 1.7],
                   [1.67, 1.66, 1.69, 1.7, 1.65, 1.62, 1.63, 1.65, 1.7, 1.69],
                   [1.64, 1.64, 1.61, 1.59, 1.61, 1.67, 1.71, 1.7, 1.72, 1.69],
                   [1.63, 1.63, 1.62, 1.67, 1.7, 1.67, 1.67, 1.69, 1.69, 1.68]],
                 index=np.arange(75, 525, 50), columns=np.arange(50, 525, 50))
V1 = pd.DataFrame([[  7.53,   7.53,   7.53,   7.53,   7.53,   7.53,   7.53,   7.53, 7.53,   7.53],
       [  7.53,   7.53,   7.53,   7.53,   7.66,   8.09,   8.08,   8.05, 8.05,   8.05],
       [  7.53,   7.77,   8.08,   8.05,   8.19,   8.95,   8.93,   8.79,8.79,   8.62],
       [  8.95,   7.92,   8.95,   8.93,   8.62,   7.93,   8.96,   8.95, 9.09,   8.75],
       [  8.61,   8.95,   8.62,   8.61,   8.95,   8.93,   8.82,   9.42, 9.67,   8.48],
       [  9.23,   8.61,   8.95,   9.24,   9.42,   8.48,   8.47,   8.65, 8.92,   9.17],
       [  8.6 ,   9.01,   9.66,   8.05,   9.42,   8.92,   8.81,   7.53, 7.53,   7.53],
       [  9.42,   9.25,   8.65,   8.92,   8.25,   7.97,   8.09,   8.49, 8.49,   7.58],
       [ 10.15,   9.79,   9.1 ,   9.35,   9.35,   9.35,   9.25,   9.3 , 9.3 ,   8.19]],
                index=np.arange(75, 525, 50), columns=np.arange(50, 525, 50))
V2 = (V1-8) * 3 + 8
def my_plot3d(V):
    # % matplotlib inline  # Uncomment if you are using IPython
    fig = plt.figure(figsize=[15,10])
    ax = fig.add_subplot(111, projection='3d')
    ax.view_init(45,60)
    # Normalize in [0, 1] the DataFrame V that defines the color of the surface.
    V_normalized = (V - V.min().min())
    V_normalized = V_normalized / V_normalized.max().max()
    # Plot
    ax.plot_surface(X, Y, Z, facecolors=plt.cm.jet(V_normalized))
    ax.set_xlabel('x', fontsize=18)
    ax.set_ylabel('y', fontsize=18)
    ax.set_zlabel('z', fontsize=18)
    m = cm.ScalarMappable(cmap=cm.jet)
    m.set_array(V)
    #plt.colorbar(m)
    clrbar = plt.colorbar(m)
    min_V = np.min([V1.min().min(), V2.min().min()])
    max_V = np.max([V1.max().max(), V2.max().max()])
    clrbar.set_clim(min_V, max_V)
my_plot3d(V1)

my_plot3d(V2)

如您所见,存在两个问题:

  1. 尽管 V1 和 V2 不同,但两个表面的颜色相同(实际上我应用了线性缩放从 V1 获得 V2)。
  2. 颜色条具有不同的值范围。

好处是颜色条将所有图形中的相同颜色与相同值相关联。如何解决前两个问题?

在循环中调用 m.set_array(V2)。所以都使用 V2 作为数组;因此它们是相同的。

它应该是你应该使用的 lopp 变量 V:

m.set_array(V)


我想我已经为您提供了 来规范化 V 的值。当使用两个不同的数组进行着色时,您需要确保对它们使用相同的规范化,而不是分别规范化每个数组。

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.colors

x = np.arange(3)
X,Y = np.meshgrid(x,x)
Z = np.ones_like(X)

V1 = np.array([[3,2,2],[1,0,3],[2,1,0]])
V2 = 1+ V1*1.6

def plot_array(V, vmin, vmax):

    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)
    ax.plot_surface(X, Y, Z, facecolors=plt.cm.jet(norm(V)), shade=False)

    m = cm.ScalarMappable(cmap=plt.cm.jet, norm=norm)
    m.set_array([])
    plt.colorbar(m)

    ax.set_xlabel('x')
    ax.set_ylabel('y')


plot_array(V1, np.min([V1.min(), V2.min()]), np.max([V1.max(), V2.max()]))
plot_array(V2, np.min([V1.min(), V2.min()]), np.max([V1.max(), V2.max()]))

plt.show()