Plotly调用add_trace添加拟合线时触发numpy.float64类型无效报错
问题场景
调用plotly的add_trace方法添加拟合曲线时报类型错误,场景为:
- 存在2个自变量x1、x2,1个因变量y
- 已通过
scipy.optimize.curve_fit完成二元函数拟合,需要在散点图上追加拟合轨迹线 - 测试用数据为随机生成,拟合结果无实际业务意义
附复现代码与报错:
import pandas as pd import numpy as np import plotly.graph_objects as go from scipy.optimize import curve_fit np.random.seed(0) x1 = np.random.randint(0, 100, 100) x2 = np.random.randint(0, 100, 100) y = np.random.randint(0, 100, 100) def func(x, a, b, c, d, e, f, g): return (a * x[0]**3 + b * x[0]**2 + c * x[0]) + (d * x[1]**3 + e * x[1]**2 + f * x[1]) + g def inv(x1, x2, y): (a, b, c, d, e, f, g), _ = curve_fit(func, np.stack([x1, x2]), y) # create graph x3 = [sum(i) for i in zip(x1, x2 )] x = np.linspace(min(x3), max(y), 1000) fig = go.Figure(go.Scatter(x=x3, y=y, name='data')) fig.add_trace(go.Scatter(x=x, y=func(x, a, b, c, d, e, f, g), name='fit')) fig.show() return (a, b, c, d, e, f, g) inv(x1, x2, y)
报错信息:
ValueError: Invalid value of type 'numpy.float64' received for the 'y' property of scatter Received value: 49.464592654826 The 'y' property is an array that may be specified as a tuple, list, numpy array, or pandas Series
报错原因
问题出在两处逻辑错误:
- 直接触发报错的原因:定义的拟合函数
func要求输入的x是形状为(2, n)的二维数组(第一行存x1序列、第二行存x2序列),但绘图时生成的x是一维数组,直接传入func后,x[0]取到的是数组第一个元素(单个numpy.float64数值),整个函数计算后返回的是单个浮点数,不符合plotly Scatter的y参数需要传入序列的要求。 - 额外的逻辑偏差:
- 生成拟合x轴范围时用了
max(y)作为上限,但散点x轴是x1+x2的和x3,x轴范围应该对齐x3的极值,和y的最大值无关。 - 二元函数拟合结果本质是三维曲面,要在二维平面图上绘制拟合线,必须先明确一维x轴上每个点对应的x1、x2取值规则,不能直接把一维x传入二元拟合函数。
- 生成拟合x轴范围时用了
修复方案
- 调整拟合x轴的生成范围,对齐原始散点x轴(x3)的最小、最大值
- 定义一维拟合x对应的x1、x2取值规则(示例中取x1=x2=x/2,可根据实际展示需求调整,比如固定其中一个变量为样本均值,另一个随x变化),将两个拟合自变量拼成
(2, n)形状的二维数组后再传入func计算拟合y值。
修正后可运行代码:
import numpy as np import plotly.graph_objects as go from scipy.optimize import curve_fit np.random.seed(0) x1 = np.random.randint(0, 100, 100) x2 = np.random.randint(0, 100, 100) y = np.random.randint(0, 100, 100) def func(x, a, b, c, d, e, f, g): return (a * x[0]**3 + b * x[0]**2 + c * x[0]) + (d * x[1]**3 + e * x[1]**2 + f * x[1]) + g def inv(x1, x2, y): (a, b, c, d, e, f, g), _ = curve_fit(func, np.stack([x1, x2]), y) # 原始散点x轴为x1+x2的和 x3 = x1 + x2 # 生成拟合x轴,范围对齐x3 x_fit = np.linspace(x3.min(), x3.max(), 1000) # 定义x_fit对应的x1、x2取值,示例为x1=x2=x_fit/2,可按需调整 x1_fit = x_fit / 2 x2_fit = x_fit / 2 # 拼成func要求的(2, n)形状输入 x_fit_2d = np.stack([x1_fit, x2_fit]) # 计算拟合y值 y_fit = func(x_fit_2d, a, b, c, d, e, f, g) fig = go.Figure() fig.add_trace(go.Scatter(x=x3, y=y, mode='markers', name='raw data')) fig.add_trace(go.Scatter(x=x_fit, y=y_fit, mode='lines', name='fit curve')) fig.show() return (a, b, c, d, e, f, g) inv(x1, x2, y)
注:如果需要完整展示二元拟合的曲面效果,应改用3D散点+3D曲面图绘制,不要在二维图中强行降维展示。
内容的提问来源于stack exchange,提问作者user032020
相关产品推荐
相关产品推荐

