user26502206
user26502206

Reputation: 23

How to plot sympy functions with units

I am trying to create a 3d plot with sympy that has units, but I am getting different errors depending on where I try to type the units in. Below the units are built in the function itself, but I get an error also if I type the units into the plot axis variable: (a, 2.*meter/second^2., 0.*meter/second^2.), etc. I plunged through the Sympy documentation and couldn't find anything on plotting with units. Is there an established way to do this?

import matplotlib.pyplot as plt
from sympy.physics.units.systems.si import SI
from sympy.physics.units import second, newton, meter, kilogram
from sympy import init_printing
from sympy import *
from IPython.display import display
from sympy.plotting import plot3d

F, m, a = symbols('F_ m_ a_')

def F(a,m):
    return a*(meter/second**2.)*m*kilogram

plot3d(F(a,m), (a, 2.,0.), (m, 0.,1.), zlabel=S('F_'))

I tried to use plot3d in sympy to plot a function with units, but it didn't work. I get either TypeError: Cannot convert the expression to float OR TypeError: cannot determine the truth value of Relational

Upvotes: 1

Views: 50

Answers (1)

Davide_sd
Davide_sd

Reputation: 13150

Generally, you can't plot a symbolic expression containing units. Here is why.

When you create your expression with F(a,m), a and m are symbols. However, the expression also contains other entities, kilogram, meter, second, which are instances of Quantity (from sympy.physics.units).

When you execute plot3d(F(a,m), (a, 2.,0.), (m, 0.,1.)), this is what happens:

  1. F(a,m) generates a symbolic expression: kilogram*meter*a_*m_/second**2
  2. The plotting module uses lambdify to convert that symbolic expression to a numerical function: f = lambdify([a, m], F(a,m)). Let's look at it:
    help(f)
    
    Help on function _lambdifygenerated:
    
    _lambdifygenerated(a_, m_)
        Created with lambdify. Signature:
    
        func(a_, m_)
    
        Expression:
    
        kilogram*meter*a_*m_/second**2
    
        Source code:
    
        def _lambdifygenerated(a_, m_):
            return kilogram*meter*a_*m_/second**2
    
    The numerical function has two parameters, a_, m_, but it doesn't know what kilogram, meter, second are.
  3. The plotting module generates numerical array for a_, m_, provides them to the numerical function. At evaluation, you get those errors.

Possible solution: remove the units from the symbolic expression. You can either rewrite your expression without units, or you can remove them with a substitution. Here is how:

from sympy.physics.units import Quantity
expr_with_units = F(a, m)
# create a substitution dictionary: replace each quantity with number 1
sd = {k: 1 for k in expr_with_units.find(Quantity)}
expr_without_units = expr_with_units.subs(sd)

plot3d(expr_without_units, (a, 0, 2), (m, 0, 1), zlabel=r"$kg \cdot m / s^2$")

enter image description here

Upvotes: 1

Related Questions