1

The goal is to output two different 3D plots (plot_surface) providing specific colours for the surface (facecolors) in a "fair" way, namely using the same scale of colours for the two figures (and the same x, y and z axis fixed, but this is easy). In addition, the colorbar must be the same (i.e. same ticks and range). In other words, Let say that in figure1 the (arbitrary) value 8 is associated with dark red. Then, the must apply for figure2 as well. Note that in the example X, Y and Z are the same for both figures to make things simpler. What change are the colours associated with the surface (i.e. V1 and 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

As you can see, there are two problems:

  1. The colors of the two surfaces are the same (in fact I've applied a linear scaling to obtain V2 from V1) despite the fact that V1 and V2 are different.
  2. The colorbars have different ranges of values.

The good thing is that the colorbar associates the same colour to the same value across all figures. How to fix the previous two problems?

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
MLguy
  • 1,776
  • 3
  • 15
  • 28

1 Answers1

1

In the loop you call m.set_array(V2). So both use V2 as array; they are thus the same.

It should rather be the lopp variable V that you should use:

m.set_array(V)


I think I already provided you with a solution on normalizing the values of V. When using two different arrays for the coloring, you need to make sure that the same normalization is used for both of them, instead of normalizing each individually.
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

Community
  • 1
  • 1
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712