Sympy绘制分段函数图像添加垂直竖线触发报错问题
问题说明
在Jupyter Notebook中定义如下分段弯矩函数:
from sympy import * Mt, F1, Fax, Fay, Faz, Fbz, Fby, l, x, alpha, a, b, c, d, e = symbols('Mt, F1, Fax, Fay, Faz, Fbz, Fby, l, x, alpha, a, b, c, d, e') My1 = 0 My2 = sin(alpha)*F1*(x-a) My3 = sin(alpha)*F1*(x-a) - Fay*(x-(a+b)) My4 = sin(alpha)*F1*(x-a) - Fay*(x-(a+b))- Fby*(x-(a+b+c)) My5 = 0 My = Piecewise((My1, x<a), (My2, And(a<x, x<b)), (My3, And(b<x, x<c)), (My4, And(c<x, x<d)), (My5, And(d<x, x<e))) My
使用如下代码绘制函数图像,基础效果符合预期:
params = {alpha: 30, a:0.024, b:0.074, c:0.132, d:0.189, e:0.219, F1:11700, Fay:-8762.57, Fby:26973.41} plot(My.subs(params), (x, 0, e.subs(params)), title= "Biegemoment $M_y(x)$")

现在需要在x=0.074位置添加一条垂直竖线,尝试调整adaptive、nb_of_points参数时触发如下浮点运算报错:
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) /usr/lib/python3/dist-packages/sympy/plotting/experimental_lambdify.py in __call__(self, *args) 118 temp_args = (np.array(a, dtype=np.complex) for a in args) --> 119 results = self.vector_func(*temp_args) 120 results = np.ma.masked_where( ... /usr/lib/python3/dist-packages/numpy/lib/function_base.py in _vectorize_call(self, func, args) 2165 for a in args] 2166 -> 2167 outputs = ufunc(*inputs) 2168 2169 if ufunc.nout == 1: FloatingPointError: invalid value encountered in ? (vectorized)
报错原因
- 核心诱因是分段函数定义存在逻辑漏洞:函数表达式中用到的分段节点为
a、a+b、a+b+c、a+b+c+d,但Piecewise里写的区间判断条件是x<b、x<c、x<d、x<e,两者分界位置不匹配,导致x轴上存在部分区间没有被任何分段条件覆盖,属于无定义区域。默认自适应采样可能刚好避开了这些异常点,一旦调整nb_of_points增加采样密度,采样点落到无定义区域就会触发计算错误。 - 额外注意:SymPy的三角函数默认输入为弧度,直接传
alpha:30会按30弧度计算,和工程上常用的30度物理意义不符,如果要使用角度单位需要手动转弧度。
实现方案
添加垂直竖线完全不需要修改原函数的采样参数,SymPy的plot底层封装了Matplotlib,直接调用底层接口添加竖线是最稳定的方案,不会涉及原函数的额外采样计算,自然可以规避报错。
如果已经验证过分段函数的物理意义不需要修改,直接用如下代码即可:
params = {alpha: 30, a:0.024, b:0.074, c:0.132, d:0.189, e:0.219, F1:11700, Fay:-8762.57, Fby:26973.41} x_end = e.subs(params) # 绘制原函数,暂不显示 p = plot(My.subs(params), (x, 0, x_end), title= "Biegemoment $M_y(x)$", show=False) # 获取底层Matplotlib轴对象 ax = p._backend.ax[0] # 添加x=0.074位置的垂直竖线,可自定义颜色、线型、线宽 ax.axvline(x=0.074, color='crimson', linestyle='--', linewidth=1.5, label='x = 0.074') ax.legend() # 展示最终图像 p.show()
如果要彻底解决采样报错的隐患,建议修正分段函数的区间判断条件,让区间分界和表达式中的节点完全对应,同时修正角度单位问题:
# 若alpha输入为角度,可将My2-My4中的sin(alpha)替换为sin(alpha*pi/180) My = Piecewise( (My1, x<a), (My2, And(a<=x, x<a+b)), (My3, And(a+b<=x, x<a+b+c)), (My4, And(a+b+c<=x, x<a+b+c+d)), (My5, x>=a+b+c+d) )
修正后再调整采样参数也不会触发浮点错误。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

