You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 17:01:22