如何使用Sympy绘制带单位的3D函数?
问题描述
尝试使用Sympy创建带单位的3D绘图,无论将单位嵌入函数本身,还是添加到绘图轴变量(如(a, 2.*meter/second^2., 0.*meter/second^2.))中,都会出现错误,错误类型为TypeError: Cannot convert the expression to float或TypeError: cannot determine the truth value of Relational。查阅Sympy文档后未找到相关实现方法,询问是否有既定方案。
用户提供的测试代码:
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_'))
解决方案
Sympy的plot3d工具本身不支持直接处理带单位的表达式,因为绘图过程需要将符号表达式转换为数值,而单位符号会干扰这一转换流程。以下是两种可行的实现方式:
方式一:分离数值与单位,手动标注轴单位
先定义纯数值的物理关系函数,避免单位符号进入绘图计算,完成绘图后再为坐标轴添加单位标注:
from sympy import symbols, plot3d, S from sympy.physics.units import meter, kilogram, newton, second # 定义无单位的符号变量 a, m = symbols('a_ m_') # 纯数值函数(对应F=ma的物理关系) def F(a, m): return a * m # 绘制3D图,轴范围使用纯数值,手动添加单位标注 p = plot3d(F(a, m), (a, 0., 2.), (m, 0., 1.), xlabel=S('a_ (m/s²)'), ylabel=S('m_ (kg)'), zlabel=S('F_ (N)'), show=False) p.show()
这种方式既保证绘图功能正常运行,又能清晰展示各物理量的单位,是最简便的解决方案。
方式二:保留单位计算,转换数值后用Matplotlib绘图
如果需要在计算过程中保留单位,可以先将带单位的表达式转换为纯数值,再使用Matplotlib直接绘制3D图形(Sympy的plot3d对带单位的数值转换支持有限):
import numpy as np import matplotlib.pyplot as plt from sympy import symbols from sympy.physics.units import meter, kilogram, second, newton, convert_to a, m = symbols('a_ m_') # 带单位的物理函数 def F_with_units(a_val, m_val): return a_val*(meter/second**2) * m_val*kilogram # 将带单位的结果转换为牛顿并提取数值 F_numeric = lambda a_num, m_num: convert_to(F_with_units(a_num, m_num), newton).evalf() # 生成网格数据 a_vals = np.linspace(0, 2, 100) m_vals = np.linspace(0, 1, 100) A, M = np.meshgrid(a_vals, m_vals) # 向量化函数以处理数组 Z = np.vectorize(F_numeric)(A, M) # 使用Matplotlib绘制3D曲面图 fig = plt.figure() ax = fig.add_subplot(projection='3d') ax.plot_surface(A, M, Z) # 添加轴标签与单位 ax.set_xlabel('a (m/s²)') ax.set_ylabel('m (kg)') ax.set_zlabel('F (N)') plt.show()
这种方式保留了单位计算的严谨性,同时借助Matplotlib的灵活性完成绘图,适合需要严格单位校验的场景。
内容的提问来源于stack exchange,提问作者user26502206
相关产品推荐
相关产品推荐

