Search code examples
pythonnumpymatplotlibcomplex-numbersmatplotlib-3d

A complex function 3D plot


I have a complex function and want to plot a 3D graph using Matplotlib. Here is my code:

import numpy as np
from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
plt.style.use('seaborn-poster')
fig = plt.figure(figsize = (10,10))
ax = plt.axes(projection='3d')
           
x = np.arange(-23, 23, 0.1)
y = np.arange(-23, 23, 0.1)           


x1=25
y1=22
x2=15
y2=17
x3=25
y3=12
A1=np.exp(np.deg2rad(0.0) * 1j)
A2=np.exp(np.deg2rad(10.) * 1j)
A3=np.exp(np.deg2rad(20.) * 1j)
z=(((2*A1*(y1-y))/((x1-x)**2+(y1-y)**2))+((2*A2*(y2-y))/((x2-x)**2+(y2-y)**2))+((2*A3*(y3-y))/((x3-x)**2+(y3-y)**2)))
z_abs=np.abs(z)

X, Y = np.meshgrid(x, y)
Z = z_abs(X, Y)

surf = ax.plot_surface(X, Y, Z, cmap = plt.cm.cividis)
# Set axes label
ax.set_xlabel('x', labelpad=20)
ax.set_ylabel('y', labelpad=20)
ax.set_zlabel('z', labelpad=20)

fig.colorbar(surf, shrink=0.5, aspect=8)

plt.show()

but when running the code, I get this error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[5], line 22
     19 z_abs=np.abs(z)
     21 X, Y = np.meshgrid(x, y)
---> 22 Z = z_abs(X, Y)
     24 surf = ax.plot_surface(X, Y, Z, cmap = plt.cm.cividis)
     25 # Set axes label

TypeError: 'numpy.ndarray' object is not callable

I think the imaginary part of the function is the problem.


Solution

  • @jared correctly identified the problem: your z_abs was already a Numpy array, which can't be called (it is not a function). You can define your complex function like in the following example:

    import numpy as np
    from mpl_toolkits import mplot3d
    import matplotlib.pyplot as plt
    # plt.style.use('seaborn-poster')
    
    fig = plt.figure()
    ax = plt.axes(projection='3d')
    
    x1=25
    y1=22
    x2=15
    y2=17
    x3=25
    y3=12
    A1=np.exp(np.deg2rad(0.0) * 1j)
    A2=np.exp(np.deg2rad(10.) * 1j)
    A3=np.exp(np.deg2rad(20.) * 1j)
    
    # this lambda function represents your "complex function"
    z = lambda x, y: (((2*A1*(y1-y))/((x1-x)**2+(y1-y)**2))+((2*A2*(y2-y))/((x2-x)**2+(y2-y)**2))+((2*A3*(y3-y))/((x3-x)**2+(y3-y)**2)))
    # this lambda function represents the absolute value of your complex function
    z_abs = lambda x, y: np.abs(z(x, y))
    
    n = 250
    x = np.linspace(13, 18, n)
    y = np.linspace(15, 20, n)  
    X, Y = np.meshgrid(x, y)
    # now you can evaluate the absolute value
    Z = z_abs(X, Y)
    
    surf = ax.plot_surface(X, Y, Z, cmap = plt.cm.cividis)
    # Set axes label
    ax.set_xlabel('x', labelpad=20)
    ax.set_ylabel('y', labelpad=20)
    
    fig.colorbar(surf, shrink=0.5, aspect=8, label='abs(z)')
    
    plt.show()
    

    enter image description here

    The picture above is not really good. Sure, you can see a pole at some location, but nothing else. If I were you, I would plot the log10 of the absolute value of your complex function:

    n = 250
    x = np.linspace(13, 18, n)
    y = np.linspace(15, 20, n)  
    X, Y = np.meshgrid(x, y)
    Z = np.log10(z_abs(X, Y))
    
    fig = plt.figure()
    ax = plt.axes(projection='3d')
    surf = ax.plot_surface(X, Y, Z, cmap = plt.cm.cividis)
    ax.set_xlabel('x', labelpad=20)
    ax.set_ylabel('y', labelpad=20)
    fig.colorbar(surf, shrink=0.5, aspect=8, label='abs(z)')
    plt.show()
    

    enter image description here