为何运行相同Python SymPy绘图代码每次得到不同图像?
SymPy大区间绘图结果不一致的原因分析
问题复现
在Linux Mint 21.2、Python 3.10环境下运行SymPy 1.9的绘图代码:
import sympy print(sympy.__version__) # '1.9' from sympy import symbols, sin from sympy.plotting import plot t = symbols('t') plotP = plot(50*sin(t/30)+30*sin(1.3*t/30)+20*sin(2.7*t/30)+25*sin(3.7*t/30), (t, 24800, 35800))
出现的异常现象:
- 每次运行生成的图像形态都有差异
- 升级SymPy、matplotlib版本或改用shell执行脚本,问题仍存在
- 切换为0-400这类小区间绘图时,结果完全一致,图像平滑无异常
核心原因
自适应采样的随机性
SymPy的plot函数默认采用自适应采样逻辑:先在区间内取少量初始点,再根据曲线波动程度动态补充采样点。但在跨度11000的大区间下,函数包含多个不同频率的正弦项,高频项的峰值间距(比如3.7*t/30的周期约为50.6)远小于初始采样点的间隔,导致每次采样捕捉到的峰值位置存在随机性,最终绘制的曲线形态出现差异。大数值下的浮点精度误差
当t取值达到2万以上时,t/30这类大数值无法被浮点数精确表示,计算正弦函数时会产生微小的精度偏差。多个正弦项的偏差叠加后,会放大为曲线整体形态的差异,这也是每次绘图结果不同的诱因之一。小区间的稳定逻辑
在0-400的小区间里,采样点密度足够覆盖所有正弦项的周期,且t数值小,浮点精度误差可以忽略,自适应采样能稳定捕捉曲线特征,因此每次绘图结果完全一致。
稳定绘图的解决思路
如果需要大区间下的稳定绘图结果,可以尝试两种方式:
- 关闭自适应采样,手动指定足够多的采样点:
plotP = plot(50*sin(t/30)+30*sin(1.3*t/30)+20*sin(2.7*t/30)+25*sin(3.7*t/30), (t, 24800, 35800), adaptive=False, nb_of_points=10000) - 将符号函数转换为数值函数,直接用matplotlib控制采样精度:
import numpy as np import matplotlib.pyplot as plt t_vals = np.linspace(24800, 35800, 20000) f = lambda t: 50*np.sin(t/30)+30*np.sin(1.3*t/30)+20*np.sin(2.7*t/30)+25*np.sin(3.7*t/30) plt.plot(t_vals, f(t_vals)) plt.show()
内容的提问来源于stack exchange,提问作者user7711283
相关产品推荐
相关产品推荐

