如何在Matplotlib 3D图的X/Y轴使用日期数据并解决qhull报错
报错原因
- 触发
qhull Delaunay triangulation calculation: singular input data错误的核心原因是:plot_trisurf要求输入的X、Y样本点在X-Y平面上覆盖一片连续区域,不能完全共线的点无法执行三角剖分。你提供的示例代码中,date1和date2是固定偏移14天的等间隔序列,所有(date1, date2)坐标点严格落在同一条直线上,不符合算法输入要求。 - 代码还存在几处语法问题:
- 创建画布时使用
plt.figure(),后续创建3D轴时调用了未定义的fig变量 - 未导入
cm模块就直接使用cm.coolwarm - 刻度定位用的
some_dates变量未定义
- 创建画布时使用
解决方法
要绘制trisurf、plot_surface类3D曲面,需要先将输入数据调整为二维网格结构,覆盖X-Y平面的连续区域,而非逐行配对的一维共线点。修改后的可运行代码如下:
from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt import numpy as np import matplotlib.dates as dates import matplotlib.ticker as ticker import pandas as pd from matplotlib import cm # 生成覆盖二维区域的日期序列 date1_all = pd.date_range(start='2018-01-05', end='2018-01-20', freq='1D') date2_all = pd.date_range(start='2018-01-19', end='2018-02-03', freq='1D') # 生成二维网格 date1_grid, date2_grid = np.meshgrid(date1_all, date2_all) # 生成对应网格的测量值(模拟真实业务数据 z_data = np.sin(2*np.linspace(-1,1,date1_grid.size)).reshape(date1_grid.shape) + np.cos(2*np.linspace(-1,1,date2_grid.size).reshape(date2_grid.shape) def format_date(x, pos=None): return dates.num2date(x).strftime('%Y-%m-%d') # 创建画布与3D轴 fig = plt.figure(figsize=(10,7)) ax = Axes3D(fig, rect=[0,0.1,1,1]) # 两种绘图方式二选一即可 # 方式1:plot_surface绘制曲面 ax.plot_surface(dates.date2num(date1_grid), dates.date2num(date2_grid), z_data, cmap=cm.coolwarm, linewidth=0.2) # 方式2:plot_trisurf绘制三角曲面,需将网格展平为一维 # ax.plot_trisurf(dates.date2num(date1_grid.flatten()), dates.date2num(date2_grid.flatten()), z_data.flatten(), cmap=cm.coolwarm, linewidth=0.2) # 配置日期刻度,按间隔3个日期显示一个刻度 some_dates_x = dates.date2num(date1_all[::3]) ax.w_xaxis.set_major_locator(ticker.FixedLocator(some_dates_x)) ax.w_xaxis.set_major_formatter(ticker.FuncFormatter(format_date)) some_dates_y = dates.date2num(date2_all[::3]) ax.w_yaxis.set_major_locator(ticker.FixedLocator(some_dates_y)) ax.w_yaxis.set_major_formatter(ticker.FuncFormatter(format_date)) # 调整刻度标签显示角度 for tl in ax.w_xaxis.get_ticklabels(): tl.set_ha('right') tl.set_rotation(30) for tl in ax.w_yaxis.get_ticklabels(): tl.set_ha('right') tl.set_rotation(-30) ax.set_xlabel('date1') ax.set_ylabel('date2') ax.set_zlabel('mydata') plt.show()
内容的提问来源于stack exchange,提问作者Medulla Oblongata
相关产品推荐
相关产品推荐

