如何基于Pandas DataFrame的三列数据(x、y、z)使用Pandas和Matplotlib绘制2D标量图(如imshow或contour)
如何基于Pandas DataFrame的三列数据(x、y、z)使用Pandas和Matplotlib绘制2D标量图(如imshow或contour)
我完全懂你的感受——明明是很基础的需求,居然一开始没找到纯Pandas+Matplotlib的方案,还要用到Seaborn。其实不用Seaborn也能轻松实现,核心是先把你的长格式DataFrame转换成网格状的宽格式数据,然后直接用Matplotlib的绘图函数就行,下面给你两种常用的实现方式:
方法一:用imshow绘制热力图
这和你用Seaborn画的heatmap效果类似,步骤很简单:
- 先通过
pivot把数据转成宽格式:把x作为列、y作为索引,z作为对应的值,这样就得到了二维的矩阵,刚好符合imshow的输入要求。 - 用Matplotlib的
imshow绘制,再补充坐标轴标签、颜色条等细节。
完整代码如下:
import pandas as pd import matplotlib.pyplot as plt # 你的原始数据 d = {'x': [1, 1, 1, 2, 2, 2], 'y': [1, 2, 3, 1, 2, 3], 'z': [30, 31, 33, 10, 8, 6]} df = pd.DataFrame(data=d) # 将长格式数据转为宽格式(网格状) df_pivoted = df.pivot(columns='x', index='y', values='z') # 绘制imshow热力图 fig, ax = plt.subplots() im = ax.imshow(df_pivoted, cmap='RdYlGn', aspect='auto') # 添加颜色条,并设置标签 cbar = plt.colorbar(im) cbar.set_label('z') # 设置坐标轴标签 ax.set_xlabel('x') ax.set_ylabel('y') # 设置坐标轴刻度(因为pivot后的columns和index就是x、y的取值) ax.set_xticks(range(len(df_pivoted.columns))) ax.set_xticklabels(df_pivoted.columns) ax.set_yticks(range(len(df_pivoted.index))) ax.set_yticklabels(df_pivoted.index) # 反转y轴,让y值从下往上递增(和常规认知一致) ax.invert_yaxis() plt.show()
方法二:用contour/contourf绘制等高线图
如果想要画等高线(填充或非填充),同样先处理数据,然后利用pivot后的索引和列生成网格,再调用Matplotlib的等高线函数:
import pandas as pd import matplotlib.pyplot as plt import numpy as np # 原始数据同上 d = {'x': [1, 1, 1, 2, 2, 2], 'y': [1, 2, 3, 1, 2, 3], 'z': [30, 31, 33, 10, 8, 6]} df = pd.DataFrame(data=d) df_pivoted = df.pivot(columns='x', index='y', values='z') # 获取x、y的网格数据 x = df_pivoted.columns.values y = df_pivoted.index.values X, Y = np.meshgrid(x, y) Z = df_pivoted.values # 绘制填充等高线图(contourf)+ 等高线(contour) fig, ax = plt.subplots() contour_filled = ax.contourf(X, Y, Z, cmap='RdYlGn') contour_lines = ax.contour(X, Y, Z, colors='black') # 添加颜色条和标签 cbar = plt.colorbar(contour_filled) cbar.set_label('z') ax.set_xlabel('x') ax.set_ylabel('y') # 添加等高线数值标签 ax.clabel(contour_lines, inline=True, fontsize=10) plt.show()
补充说明
你之前尝试meshgrid遇到的问题,其实是因为一开始数据是长格式的,没有先转成规整的网格矩阵。通过pivot处理后,数据已经是x、y每个组合对应的z值,此时再用meshgrid生成网格就很顺畅了——当然如果是imshow的话,甚至不需要手动生成网格,直接用pivot后的DataFrame.values就行。
备注:内容来源于stack exchange,提问作者TeddyD
相关产品推荐
相关产品推荐

