Search code examples
pythonmatplotlibmultidimensional-arraynumpy-ndarraymatplotlib-3d

How to plot a 3D function with colors given spacing 2D input


Let's assume I have 3 arrays defined as:

v1=np.linspace(1,100)
v2=np.linspace(1,100)
v3=np.linspace(1,100)   

Then I have a function that takes those 3 values and gives me the desired output, let's assume it is like:

f = (v1 + v2*10)/v3

I want to plot that function on a 3D plot with axis v1,v2,v3 and color it's surface depending on its value. More than the best way to plot it, I was also interested in how to scroll all the values in the in vectors and build the function point by point. I have been trying with for loops inside other for loops but I am always getting one error.

MANY THANKS

I tried this but i'm always getting a line instead of a surface


import mpl_toolkits.mplot3d.axes3d as axes3d
import sympy
from sympy import symbols, Function

# Parameters I use in the function
L = 132
alpha = 45*math.pi/180
beta = 0


s,t = symbols('s,t')
z = Function('z')(s,t)
figure = plt.figure(figsize=(8,8))
ax = figure.add_subplot(1, 1, 1, projection='3d')

# experiment with various range of data in x and y
x1 = np.linspace(-40,-40,100)  
y1 = np.linspace(-40,40,100)
x,y = np.meshgrid(x1,y1)

# My function Z
c1=math.cos(beta)**2
c2=math.cos(alpha)**2
s1=math.sin(alpha)**2
den = math.sqrt((c1*c2)+s1)
z=L*((math.cos(beta)/den)-1)+(s*(math.sin(alpha)))+(t*(1-math.cos(alpha)))


ax.plot_surface(x,y,z,cmap='rainbow')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.show()


Solution

  • In this example I'm going to show you how to achieve your goal. Specifically, I use Numpy because it supports vectorized operations, hence I avoid for loops.

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.colors import Normalize
    import matplotlib.cm as cm
    
    # Parameters I use in the function
    L = 132
    alpha = 45*np.pi/180
    beta = 0
    
    figure = plt.figure()
    ax = figure.add_subplot(1, 1, 1, projection='3d')
    
    # experiment with various range of data in x and y
    x1 = np.linspace(-40,40,100)  
    y1 = np.linspace(-40,40,100)
    x,y = np.meshgrid(x1,y1)
    
    # My function Z
    c1=np.cos(beta)**2
    c2=np.cos(alpha)**2
    s1=np.sin(alpha)**2
    den = np.sqrt((c1*c2)+s1)
    z=L*((np.cos(beta)/den)-1)+(x*(np.sin(alpha)))+(y*(1-np.cos(alpha)))
    
    # compute the color values according to some other function
    color_values = np.sqrt(x**2 + y**2 + z**2)
    # normalize color values between 0 and 1
    norm = Normalize(vmin=color_values.min(), vmax=color_values.max())
    norm_color_values = norm(color_values)
    # chose a colormap and create colors starting from the normalized values
    cmap = cm.rainbow
    colors = cmap(norm_color_values)
    
    surf = ax.plot_surface(x,y,z,facecolors=colors)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    # add a colorbar
    figure.colorbar(cm.ScalarMappable(norm=norm, cmap=cmap), label="radius")
    plt.show()
    

    enter image description here