如何按DataFrame列分配散点标记?解决‘unhashable type: Series’错误
解决Matplotlib散点图标记类型的"不可哈希类型"错误
问题场景
想要按DataFrame的Year列分组绘制散点图,同时根据detector列的值为每个点分配不同的标记类型,但运行代码时抛出TypeError: unhashable type: 'Series'错误。尝试过循环内用if-elif块创建标记、单独生成标记向量两种方式,均未解决问题。
错误原因
Matplotlib的plt.scatter()函数的marker参数仅接受单个标记字符串(如'.'、'd'),无法直接传入Series或数组类型。原代码中试图将整个Series传给marker,这是导致错误的核心原因,和数据是否复制无关。
解决方案
方法1:按探测器类型分组绘制
在年份循环内,再嵌套探测器类型的循环,每次绘制同一年份、同一探测器类型的点,确保每个scatter调用的marker是单个有效值。同时修正缺失值的判断逻辑(原代码中strings=='NaN'无法识别真实的缺失值,需用pd.isna())。
修正后的代码:
import pandas as pd import matplotlib.pyplot as plt # 定义探测器与标记的映射关系 detector_marker = { 'semiflex': '.', 'diamond': 'd', pd.NA: '1' # 处理缺失值 } data = pd.read_excel("../data.xlsx") fig, ax = plt.subplots() for Year in range(2019, 2024): # 先筛选当前年份、Energy=12的子数据 year_data = data[(data.Energy == 12) & (data.Year == Year)] # 按探测器类型分组绘制 for detector, marker in detector_marker.items(): # 筛选当前探测器类型的数据(注意缺失值的判断) if pd.isna(detector): subset = year_data[pd.isna(year_data.detector)] else: subset = year_data[year_data.detector == detector] # 只有当子集有数据时才绘制 if not subset.empty: label_text = f"{Year}-{detector}" if detector is not pd.NA else f"{Year}-缺失值" ax.scatter(subset.Cone, subset.CalcOverCom, marker=marker, label=label_text) ax.set_xlabel('xlabel') ax.set_ylabel('ylabel') ax.legend(bbox_to_anchor=(1, 1)) ax.set_title('title') plt.show()
方法2:逐个点绘制(适用于数据量较小的场景)
如果需要保留每个年份的统一图例,可以先生成每个点的标记列表,然后循环逐个绘制点,同时只在第一次绘制年份时添加图例:
import pandas as pd import matplotlib.pyplot as plt detector_marker = { 'semiflex': '.', 'diamond': 'd', pd.NA: '1' } data = pd.read_excel("../data.xlsx") fig, ax = plt.subplots() for Year in range(2019, 2024): year_data = data[(data.Energy == 12) & (data.Year == Year)] # 生成每个点的标记列表 markers = year_data.detector.apply(lambda d: detector_marker.get(d, '1')) # 逐个绘制点,仅第一次添加图例 for idx, (x, y, marker) in enumerate(zip(year_data.Cone, year_data.CalcOverCom, markers)): if idx == 0: ax.scatter(x, y, marker=marker, label=Year) else: ax.scatter(x, y, marker=marker) ax.set_xlabel('xlabel') ax.set_ylabel('ylabel') ax.legend(bbox_to_anchor=(1, 1)) ax.set_title('title') plt.show()
关键说明
- 用字典统一管理探测器与标记的映射,避免重复的条件判断,代码更易维护。
- 处理缺失值时必须用
pd.isna(),而非判断字符串是否等于'NaN',因为DataFrame中的缺失值是pd.NA或np.nan,不是字符串。 - 每次
scatter调用的marker参数必须是单个字符串,这是Matplotlib的硬性要求。
内容的提问来源于stack exchange,提问作者LifelongLearner
相关产品推荐
相关产品推荐

