Python绘图报错:ValueError: err需为标量/1D/(2,n)类数组求助
刚看了你的代码和报错,这几个问题其实都是新手容易踩的小坑,我帮你一步步拆解修正:
核心报错原因:plt.errorbar参数顺序完全搞反
你当前写的:
plt.errorbar(m, sigma_m, V, sigma_V, marker='.', fmt='.')
完全不符合plt.errorbar的参数逻辑!它的标准调用顺序是:plt.errorbar(x, y, yerr=None, xerr=None, ...)
你的图表是质量-体积关系,x轴对应体积(V),y轴对应质量(m),所以正确写法应该是把x设为V、y设为m,然后yerr传质量的误差sigma_m,xerr传体积的误差sigma_V。你现在把误差值直接放在了x、y的位置,导致程序把V当成了yerr参数,而V是数组格式不符合要求,这就是触发ValueError: err must be a scalar or a 1D or (2, n) array-like的直接原因。
第二个关键问题:curve_fit参数顺序颠倒
curve_fit的调用逻辑是:curve_fit(拟合函数, x数据, y数据, ...),你现在写的:
popt, pcov=curve_fit(m, V, line)
不仅把拟合函数放在了最后,还搞反了x、y数据的顺序,正确写法应该是curve_fit(line, V, m)——毕竟你是要用体积V去拟合质量m。
隐性小问题:数据加载导致的二维数组
你加载数据时用了np.array([np.loadtxt('xxx.txt')]),比如:
m=np.array([np.loadtxt('masse.txt')])
这会把原本一维的数值数组变成二维数组(形状为(1, n)),而Matplotlib和curve_fit都需要一维数组处理,直接改成m = np.loadtxt('masse.txt')即可,其他加载数据的行同理。
误差计算的疏漏
你的sigma_Vpe计算少了开平方步骤,误差传递公式里平方和之后需要开根号,所以应该改成:
sigma_Vpe=np.sqrt((lpe*a)**2 *(0.01)**2 +(lpe*hpe)**2 *(0.01)**2 +(hpe*a)**2 *(0.01)**2)
修正后的完整代码
import numpy as np from matplotlib import pyplot as plt from scipy.optimize import curve_fit # 修正:直接加载为一维数组,去掉外层冗余的np.array([...]) m = np.loadtxt('masse.txt') sigma_m = np.loadtxt('errore_masse.txt') lati = np.loadtxt('lati.txt') sigma_lati = np.loadtxt('errore_lati.txt') h = np.loadtxt('altezze.txt') sigma_h = np.loadtxt('errore_altezza.txt') dc = np.array([6.45, 8.56, 10.45, 10.46]) hc = np.array([16.25, 40.80, 75., 17.67]) lpe = np.array([8.56]) a = np.array([7.41]) hpe = np.array([37.3]) lb = np.array([10.46]) rc = dc/2 Vc = 2*np.pi*a**2 *hc sigma_rc = sigma_lati/2 sigma_Vc = Vc*2*(0.01/dc) # 修正:误差计算添加开平方步骤 Vpe = 6*lpe*a*hpe sigma_Vpe = np.sqrt((lpe*a)**2 *(0.01)**2 +(lpe*hpe)**2 *(0.01)**2 +(hpe*a)**2 *(0.01)**2) Vp = lb**2 sigma_Vp = 2*Vp*(0.01/lb) # 修正:一维数组加载体积数据 V = np.loadtxt('volumi.txt') sigma_V = np.loadtxt('errore_volumi.txt') def line(x, a, q): '''funzione retta ''' return a*x+q plt.figure('Grafico massa-volume oggetti di ottone') # 修正:errorbar参数顺序,x=体积V,y=质量m,对应误差分别传入 plt.errorbar(V, m, xerr=sigma_V, yerr=sigma_m, marker='.', fmt='.') # 修正:curve_fit参数顺序,拟合函数在前,x=V、y=m popt, pcov = curve_fit(line, V, m) a_fit, q_fit = popt sigma_a_fit, sigma_q_fit = np.sqrt(pcov.diagonal()) print(a_fit, q_fit, sigma_a_fit, sigma_q_fit) # 优化:用数据的实际范围生成拟合线的x轴,更贴合图表 x = np.linspace(V.min(), V.max(), 100) # 100个点让拟合线更平滑 plt.plot(x, line(x, a_fit, q_fit)) plt.xlabel('Volume [mm$^3$]') plt.ylabel('Massa [g]') plt.grid(ls='dashed', which='both') plt.show()
额外小建议
- 以后调用陌生函数前,可以快速查一下官方文档的参数顺序,
plt.errorbar和curve_fit的参数顺序很容易搞混; - 加载数据后可以用
print(m.shape)检查数组维度,避免二维数组带来的隐性问题; - 如果想让拟合结果更准确,可以在
curve_fit里加上误差权重参数:popt, pcov = curve_fit(line, V, m, sigma=sigma_m, absolute_sigma=True)
内容的提问来源于stack exchange,提问作者lore_caram

