Home > Software engineering >  Lambdify a function in two variables and plot a surface
Lambdify a function in two variables and plot a surface

Time:09-07

I have a function f(x,y) where t is a parameter. I'm trying to plot the function where t = 1 for x and y values ranging from -5 to 5. The plot doesn't render.

import sympy as sp 
import numpy as np 
import matplotlib.pyplot as plt 
%matplotlib notebook

C = sv.CoordSys3D("")
x, y, z = C.base_scalars()
t = sp.symbols("t")

f = sp.sin(2*sp.pi*t)*sp.exp(-(x-3*sp.sin(sp.pi*t))**2 -(y-3*sp.cos(sp.pi*t))**2)

fig    = plt.figure(figsize=(6, 6))
ax     = fig.add_subplot(projection='3d')

X = np.linspace(-5,5,100)
Y = np.linspace(-5,5,100)

xvals, yvals = np.meshgrid(X,Y)
zvals = sp.lambdify((x,y),f.subs(t,1),"numpy")(xvals,yvals)

ax.plot_surface(xvals,yvals,zvals)

plt.show()

I get an error 'int' object has no attribute 'ndim' which I don't know how to solve.

CodePudding user response:

The problem is that when you execute f.subs(t,1) it returns a number (zero in this case). So, f=0 is the expression that you are going to lambdify. Let's see the function generated by lambdify:

import inspect
print(inspect.getsource(sp.lambdify((x,y),f.subs(t,1),"numpy")))
# def _lambdifygenerated(Dummy_25, Dummy_24):
#    return 0

So, no matter the values and shape of xvals and yvals, that numerical function will always return 0, which is an integer number.

However, ax.plot_surface requires zvals to have the same shape as xvals or yval. Luckily, we can easily fix that with a simple if statement:

import sympy as sp 
import sympy.vector as sv 
import numpy as np 
import matplotlib.pyplot as plt 

C = sv.CoordSys3D("")
x, y, z = C.base_scalars()
t = sp.symbols("t")

f = sp.sin(2*sp.pi*t)*sp.exp(-(x-3*sp.sin(sp.pi*t))**2 -(y-3*sp.cos(sp.pi*t))**2)

fig    = plt.figure(figsize=(6, 6))
ax     = fig.add_subplot(projection='3d')

X = np.linspace(-5,5,100)
Y = np.linspace(-5,5,100)

xvals, yvals = np.meshgrid(X,Y)
zvals = sp.lambdify((x,y),f.subs(t,1),"numpy")(xvals,yvals)

# if zvals is just a number, create a proper matrix
if not isinstance(zvals, np.ndarray):
    zvals = zvals * np.ones_like(xvals)

ax.plot_surface(xvals,yvals,zvals)
plt.show()

enter image description here

CodePudding user response:

The fact that this doesn't render is bug in lambdify that it doesn't work well for constant expressions.

Your real problem though is that the expression you are trying to plot is just zero:

In [5]: f
Out[5]: 
                    2                    2           
 - (x_ - 3⋅sin(π⋅t))  - (y_ - 3⋅cos(π⋅t))            
ℯ                                         ⋅sin(2⋅π⋅t)

In [6]: f.subs(t, 1)
Out[6]: 0
  • Related