将相同的色彩映射和颜色条施加到多个3D绘图

时间:2017-03-24 20:07:53

标签: python matplotlib colorbar mplot3d

目标是输出两个不同的3D图(plot_surface),为表面(facecolors)提供特定的颜色,并在#34; fair"方式,即对两个图形使用相同比例的颜色(并且固定相同的x,y和z轴,但这很容易)。此外,颜色条必须相同(即相同的刻度和范围)。换句话说,假设在图1中,(任意)值8与暗红色相关联。然后,必须也适用于figure2。请注意,在示例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)

enter image description here

my_plot3d(V2)

enter image description here

如您所见,有两个问题:

  1. 两个表面的颜色是相同的(实际上我已经应用了线性缩放以从V1获得V2),尽管V1和V2不同。
  2. 颜色栏具有不同的值范围。
  3. 好的一点是,colorbar将相同的颜色与所有数字中的相同值相关联。如何解决前两个问题?

1 个答案:

答案 0 :(得分:1)

在循环中,您调用m.set_array(V2)。所以都使用V2作为数组;因此他们是一样的。

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

m.set_array(V)

<小时/> 我想我已经为你提供了a solution来规范化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()

enter image description here