如何在Matplotlib的3D散点图中绘制2021、2022年数据拟合线?
用Matplotlib实现3D散点图的分组拟合线
完全可以通过Matplotlib实现该需求,核心是对不同年份的数据子集分别做拟合,再在3D轴上绘制拟合后的线条。以下是具体实现方案:
步骤1:拆分年份数据
从你的原始数据中筛选出2021年和2022年的独立数据集,确保每个子集包含3D坐标(x、y、z)。
步骤2:选择拟合方法并实现
根据数据的趋势选择合适的拟合方式,以下是两种常用方案:
方案A:基于自变量的多项式拟合
如果数据的趋势可以通过某个自变量(比如x轴)来描述y和z的变化,用多项式拟合最直接:
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 替换为你的实际数据 # 示例:假设已有的散点数据及年份标签 x_all = np.random.rand(100) * 10 y_all = x_all * 2 + np.random.randn(100) * 2 z_all = x_all * 1.5 + np.random.randn(100) * 1.5 year_labels = np.random.choice([2021, 2022], size=100) # 拆分2021和2022年数据 mask_2021 = year_labels == 2021 x_21, y_21, z_21 = x_all[mask_2021], y_all[mask_2021], z_all[mask_2021] mask_2022 = year_labels == 2022 x_22, y_22, z_22 = x_all[mask_2022], y_all[mask_2022], z_all[mask_2022] # 对2021年数据做二次多项式拟合(可根据趋势调整阶数) coeff_y_21 = np.polyfit(x_21, y_21, deg=2) coeff_z_21 = np.polyfit(x_21, z_21, deg=2) # 生成拟合用的自变量序列 x_fit_21 = np.linspace(x_21.min(), x_21.max(), 100) # 计算拟合后的y和z值 y_fit_21 = np.polyval(coeff_y_21, x_fit_21) z_fit_21 = np.polyval(coeff_z_21, x_fit_21) # 2022年数据拟合同理 coeff_y_22 = np.polyfit(x_22, y_22, deg=2) coeff_z_22 = np.polyfit(x_22, z_22, deg=2) x_fit_22 = np.linspace(x_22.min(), x_22.max(), 100) y_fit_22 = np.polyval(coeff_y_22, x_fit_22) z_fit_22 = np.polyval(coeff_z_22, x_fit_22) # 绘制3D散点和拟合线 fig = plt.figure(figsize=(10, 7)) ax = fig.add_subplot(111, projection='3d') # 绘制原有散点(保留你已有的散点绘制代码) ax.scatter(x_21, y_21, z_21, label='2021 Data', alpha=0.6) ax.scatter(x_22, y_22, z_22, label='2022 Data', alpha=0.6) # 绘制黑色拟合线(匹配附图样式) ax.plot(x_fit_21, y_fit_21, z_fit_21, color='black', linewidth=2, label='2021 Fit') ax.plot(x_fit_22, y_fit_22, z_fit_22, color='black', linewidth=2, linestyle='--', label='2022 Fit') ax.set_xlabel('X Axis') ax.set_ylabel('Y Axis') ax.set_zlabel('Z Axis') ax.legend() plt.show()
方案B:3D空间样条拟合
如果数据没有明显的单一自变量,需要拟合3D空间中的趋势曲线,可以用样条插值:
from scipy.interpolate import splprep, splev # 对2021年数据排序(避免拟合线混乱) sort_idx_21 = np.argsort(x_21) x_sorted_21, y_sorted_21, z_sorted_21 = x_21[sort_idx_21], y_21[sort_idx_21], z_21[sort_idx_21] # 样条拟合,s参数控制平滑度 tck, u = splprep([x_sorted_21, y_sorted_21, z_sorted_21], s=0.5) # 生成拟合点 u_fit = np.linspace(0, 1, 100) x_fit_21, y_fit_21, z_fit_21 = splev(u_fit, tck) # 2022年数据拟合同理 sort_idx_22 = np.argsort(x_22) x_sorted_22, y_sorted_22, z_sorted_22 = x_22[sort_idx_22], y_22[sort_idx_22], z_22[sort_idx_22] tck_22, u_22 = splprep([x_sorted_22, y_sorted_22, z_sorted_22], s=0.5) u_fit_22 = np.linspace(0, 1, 100) x_fit_22, y_fit_22, z_fit_22 = splev(u_fit_22, tck_22) # 后续绘制代码同方案A,只需替换拟合线的数据源
关键调整点
- 拟合阶数:多项式拟合的
deg参数可根据数据趋势调整,线性趋势用deg=1,非线性尝试deg=2或deg=3,避免过高阶导致过拟合。 - 线条样式:通过
color、linewidth、linestyle参数调整拟合线,完全匹配你附图中的黑色线条样式。 - 数据排序:样条拟合前务必对数据按某个维度排序,否则拟合线会出现交叉混乱。
内容的提问来源于stack exchange,提问作者Harmash Ivan
相关产品推荐
相关产品推荐

