修复Python 3D散点图绘制中的KeyError索引错误
问题排查与修复
问题描述
使用pandas读取CSV文件,结合matplotlib绘制3D散点图时,全量数据绘图正常,但绘制误差点时触发KeyError。需求是绘制t3/e1/e2范围内的Z值误差点,通过Zup=ZMax-Z、Zlow=Z-ZMin定位目标点,怀疑是CSV格式或代码逻辑问题。
错误信息
runfile('C:/Users/GregL/.matplotlib/test of loops.py', wdir='C:/Users/GregL/.matplotlib') c:\users\gregl\.matplotlib\test of loops.py:19: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access mergeddata.z = mergeddata['central distance'] c:\users\gregl\.matplotlib\test of loops.py:20: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access mergeddata.x = mergeddata['x par'] c:\users\gregl\.matplotlib\test of loops.py:21: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access mergeddata.y = mergeddata['y rad'] c:\users\gregl\.matplotlib\test of loops.py:22: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access mergeddata.ZMax = mergeddata ['Z Max'] c:\users\gregl\.matplotlib\test of loops.py:23: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access mergeddata.ZMin = mergeddata ['Z Min'] c:\users\gregl\.matplotlib\test of loops.py:24: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access mergeddata.Zup = mergeddata ['Upper Lim'] c:\users\gregl\.matplotlib\test of loops.py:25: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access mergeddata.Zlow = mergeddata ['Lower Lim'] Traceback (most recent call last): File "C:\Users\GregL\AppData\Local\Programs\Spyder\pkgs\spyder_kernels\py3compat.py", line 356, in compat_exec exec(code, globals, locals) File "c:\users\gregl\.matplotlib\test of loops.py", line 53, in <module> surf=ax.scatter3D(x[z1],y[z1],z[z1],c='red',cmap=plt.cm.coolwarm,s=.1,marker='x') File "C:\Users\GregL\AppData\Local\Programs\Spyder\pkgs\pandas\core\series.py", line 984, in __getitem__ return self._get_with(key) File "C:\Users\GregL\AppData\Local\Programs\Spyder\pkgs\pandas\core\series.py", line 1024, in _get_with return self.loc[key] File "C:\Users\GregL\AppData\Local\Programs\Spyder\pkgs\pandas\core\indexing.py", line 967, in __getitem__ return self._getitem_axis(maybe_callable, axis=axis) File "C:\Users\GregL\AppData\Local\Programs\Spyder\pkgs\pandas\core\indexing.py", line 1191, in _getitem_axis return self._getitem_iterable(key, axis=axis) File "C:\Users\GregL\AppData\Local\Programs\Spyder\pkgs\pandas\core\indexing.py", line 1132, in _getitem_iterable keyarr, indexer = self._get_listlike_indexer(key, axis) File "C:\Users\GregL\AppData\Local\Programs\Spyder\pkgs\pandas\core\indexing.py", line 1327, in _get_listlike_indexer keyarr, indexer = ax._get_indexer_strict(key, axis_name) File "C:\Users\GregL\AppData\Local\Programs\Spyder\pkgs\pandas\core\indexes\base.py", line 5782, in _get_indexer_strict self._raise_if_missing(keyarr, indexer, axis_name) File "C:\Users\GregL\AppData\Local\Programs\Spyder\pkgs\pandas\core\indexes\base.py", line 5842, in _raise_if_missing raise KeyError(f"None of [{key}] are in the [{axis_name}]") KeyError: "None of [Float64Index([ 2313.3108334, 57.91915734032, 70.6299190667,\n 120.02294505, 124.254986712, 243.31550280000002,\n 243.31550280000002, 146.105908289, 146.105908289,\n 141.393578059,\n ...\n 383118.4458, 406598.8082, 466337.6262,\n 485021.8653, 676614.4588, 816073.0216,\n 1032968.11, 3354015.867, 7916505.371,\n 7953742.675],\n dtype='float64', length=8544)] are in the [index]"
原代码
from mpl_toolkits import mplot3d import matplotlib.colors as col import matplotlib.pyplot as plt import numpy as np from matplotlib import cm from mpl_toolkits.mplot3d import Axes3D import pandas as pd headers = ['name','ra','x rads','x par','dec','y rad','Parallax','Parallax Error','central distance','Z Max','Upper Lim','Z Min','Lower Lim'] mergeddata = pd.read_csv(r'C:\Users\GregL\Downloads\mergedata - no neg parallax #s (3).csv') mergeddata.z = mergeddata['central distance'] mergeddata.x = mergeddata['x par'] mergeddata.y = mergeddata['y rad'] mergeddata.ZMax = mergeddata ['Z Max'] mergeddata.ZMin = mergeddata ['Z Min'] mergeddata.Zup = mergeddata ['Upper Lim'] mergeddata.Zlow = mergeddata ['Lower Lim'] x = mergeddata.x y = mergeddata.y z = mergeddata.z ZMax = mergeddata.ZMax ZMin = mergeddata.ZMin Zup = mergeddata.Zup Zlow = mergeddata.Zlow t3 = (z >= 1695.477401) & (z <= 2313.310833) e1 = (z <= 1695.477401) & (z <= 2313.310833) & (ZMax >= 1695.477301) & (ZMax <= (1.5*2313.310833)) e2 = (z <=1695.477401) & (z <= 2313.310833) & (ZMin >= (1.5*1695.477401)) & (ZMin <=2313.310833) for z1 in e1: z1 = z + Zup for z2 in e2: z2 = z - Zlow fig = plt.figure(figsize=(10,10)) ax = fig.add_subplot(111,projection ='3d') surf=ax.scatter3D(x[t3],y[t3],z[t3],c='green',cmap=plt.cm.coolwarm,s=.5,marker='^') surf=ax.scatter3D(x[z1],y[z1],z[z1],c='red',cmap=plt.cm.coolwarm,s=.1,marker='x') surf=ax.scatter3D(x[z2],y[z2],z[z2],c='blue',cmap=plt.cm.coolwarm,s=.1,marker='-') ax.set_title('3D Data Distance Plot') ax.set_zlim(-100,10000) ax.set_xlim(-50,50) ax.set_ylim(-50,50) ax.set_xlabel('RA') ax.set_ylabel('DEC') ax.set_zlabel('CENTRAL DISTANCE') plt.show()
问题根源与修复方案
1. DataFrame列赋值警告
pandas不允许通过属性方式(mergeddata.z)创建新列,必须使用字典索引语法(mergeddata['z']),否则会触发警告且可能导致后续逻辑异常。
2. 布尔索引与误差点计算逻辑错误
原代码中的for循环完全错误:
- e1、e2是布尔数组(掩码),用于筛选符合条件的行,而非可迭代的数值列表
- 误差点的Z坐标应该是筛选后的数据行对应的
z + Zup和z - Zlow,而非对全量数据进行计算
3. 索引错误
原代码用z1(数值数组)去索引x/y/z,这相当于用数值作为行索引查找,而DataFrame的行索引是整数,导致KeyError。正确做法是用布尔掩码e1/e2筛选数据,再计算对应的误差Z值。
4. 条件逻辑冗余
e1中的z <=1695.477401 & z <=2313.310833重复,可简化为z <=1695.477401;同理e2的条件也可简化。
修正后的完整代码
from mpl_toolkits import mplot3d import matplotlib.pyplot as plt import numpy as np import pandas as pd # 读取CSV文件,指定表头(如果CSV文件本身没有表头的话) headers = ['name','ra','x rads','x par','dec','y rad','Parallax','Parallax Error','central distance','Z Max','Upper Lim','Z Min','Lower Lim'] mergeddata = pd.read_csv(r'C:\Users\GregL\Downloads\mergedata - no neg parallax #s (3).csv', names=headers) # 用字典索引创建新列,修复警告 mergeddata['z'] = mergeddata['central distance'] mergeddata['x'] = mergeddata['x par'] mergeddata['y'] = mergeddata['y rad'] mergeddata['ZMax'] = mergeddata['Z Max'] mergeddata['ZMin'] = mergeddata['Z Min'] mergeddata['Zup'] = mergeddata['Upper Lim'] mergeddata['Zlow'] = mergeddata['Lower Lim'] # 提取所需列 x = mergeddata['x'] y = mergeddata['y'] z = mergeddata['z'] ZMax = mergeddata['ZMax'] ZMin = mergeddata['ZMin'] Zup = mergeddata['Zup'] Zlow = mergeddata['Zlow'] # 定义筛选条件,简化冗余逻辑 t3_mask = (z >= 1695.477401) & (z <= 2313.310833) e1_mask = (z <= 1695.477401) & (ZMax >= 1695.477301) & (ZMax <= 1.5 * 2313.310833) e2_mask = (z <= 1695.477401) & (ZMin >= 1.5 * 1695.477401) & (ZMin <= 2313.310833) # 计算误差点的Z坐标:仅对符合条件的行计算 z_e1 = z[e1_mask] + Zup[e1_mask] z_e2 = z[e2_mask] - Zlow[e2_mask] # 绘制3D散点图 fig = plt.figure(figsize=(10,10)) ax = fig.add_subplot(111, projection='3d') # 绘制t3范围内的点 ax.scatter3D(x[t3_mask], y[t3_mask], z[t3_mask], c='green', s=.5, marker='^') # 绘制e1误差点 ax.scatter3D(x[e1_mask], y[e1_mask], z_e1, c='red', s=.1, marker='x') # 绘制e2误差点:将'-'改为'o',因为'-'不是有效的3D散点标记 ax.scatter3D(x[e2_mask], y[e2_mask], z_e2, c='blue', s=.1, marker='o') ax.set_title('3D Data Distance Plot') ax.set_zlim(-100, 10000) ax.set_xlim(-50, 50) ax.set_ylim(-50, 50) ax.set_xlabel('RA') ax.set_ylabel('DEC') ax.set_zlabel('CENTRAL DISTANCE') plt.show()
额外说明
- 读取CSV时添加了
names=headers参数,如果你的CSV文件本身已经包含表头,可以去掉这个参数 - 将
marker='-'改为marker='o',因为'-'不是matplotlib支持的3D散点图标记
内容的提问来源于stack exchange,提问作者gl3327
相关产品推荐
相关产品推荐

