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

如何简化Pandas散点图组合图例?拆分颜色与形状图例方案

问题描述

我用Pandas绘制了一幅散点图,涉及两个参数:干预类型(ventilation、filtration、source control、combination)和收益类型(health、productivity、both)。当前图例生成了两个参数的所有组合条目(共15个),我希望将图例简化为仅展示干预类型对应的点颜色、收益类型对应的点形状(或分为两个独立图例)。已尝试在循环前使用plt.close()但未解决问题,代码如下:

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

df = pd.read_csv('merged_data.csv',index_col=False)

sns.set_theme(style="ticks")

x_values = []
y_values = []
errors = []
colors = []
markers = []

color_map = {
    'ventilation': 'blue',
    'filtration': 'green',
    'filtration ': 'green',
    'source control': 'orange',
    'combination': 'purple'
}

marker_map = {
    'health': 'o',      # Circle
    'productivity': 's', # Square
    'both': '^'                  # Triangle
}

for idx, row in df.iterrows():
    x_values.extend([row['citation']] * row['n'])
    y_values.extend([row['net']] * row['n'])
    colors.extend([color_map[row['type']]] * row['n'])
    markers.extend([marker_map[row['benefit']]] * row['n'])

plt.figure(figsize=(10, 6))

for type_, color in color_map.items():
    for benefit, marker in marker_map.items():
        mask = (df['type'] == type_) & (df['benefit'] == benefit)
        plt.scatter(df['citation'][mask].repeat(df['n'][mask]).values, 
                    df['netnew'][mask].repeat(df['n'][mask]).values, 
                    color=color, marker=marker, zorder=1, alpha=0.6, s = 60, edgecolor=color, linewidth=0.8, label=f"{type_} - {benefit}")

plt.xticks(rotation=90)
plt.ylabel('Net Benefit ($/person/year)', fontsize=14)
plt.title('Health and Indirect Benefits of Indoor Air Quality Interventions', fontsize=14)

plt.legend(title='Type and Benefit', bbox_to_anchor=(1.05, 1), loc='upper left')

plt.axhline(0, color='grey', linestyle='--', linewidth=1, label='y=0')

plt.tight_layout()
plt.show()

解决方案:拆分双属性图例

核心问题是原代码为每个类型+收益的组合都添加了图例标签,导致条目冗余。下面提供两种实现方式:

方式1:创建两个独立图例(颜色对应干预类型,形状对应收益类型)

通过手动创建图例元素,分离颜色和形状的说明:

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.lines import Line2D

df = pd.read_csv('merged_data.csv', index_col=False)
# 先清洗数据:统一type字段的格式(去除空格)
df['type'] = df['type'].str.strip()

sns.set_theme(style="ticks")

color_map = {
    'ventilation': 'blue',
    'filtration': 'green',
    'source control': 'orange',
    'combination': 'purple'
}

marker_map = {
    'health': 'o',      # 圆形
    'productivity': 's', # 方形
    'both': '^'         # 三角形
}

plt.figure(figsize=(10, 6))

# 绘制散点,仅为每种干预类型添加一次颜色标签
for type_, color in color_map.items():
    color_label_added = False
    for benefit, marker in marker_map.items():
        mask = (df['type'] == type_) & (df['benefit'] == benefit)
        if not mask.any():
            continue
        # 仅第一次绘制该颜色时添加标签,避免重复
        current_label = type_ if not color_label_added else None
        plt.scatter(df['citation'][mask].repeat(df['n'][mask]).values, 
                    df['netnew'][mask].repeat(df['n'][mask]).values, 
                    color=color, marker=marker, zorder=1, alpha=0.6, s=60, 
                    edgecolor=color, linewidth=0.8, label=current_label)
        color_label_added = True

# 手动创建收益类型对应的形状图例元素
marker_legend = [
    Line2D([0], [0], marker=marker, color='black', linestyle='None',
           markersize=8, label=benefit)
    for benefit, marker in marker_map.items()
]

# 获取自动生成的干预类型颜色图例
color_handles, color_labels = plt.gca().get_legend_handles_labels()
# 添加y=0的线到颜色图例
color_handles.append(Line2D([0], [0], color='grey', linestyle='--', linewidth=1))
color_labels.append('y=0')

# 绘制第一个图例(干预类型+基准线)
legend1 = plt.legend(handles=color_handles, labels=color_labels, 
                     title='干预类型', bbox_to_anchor=(1.05, 1), loc='upper left')
# 保留第一个图例,再绘制第二个图例(收益类型)
plt.gca().add_artist(legend1)
plt.legend(handles=marker_legend, title='收益类型', 
           bbox_to_anchor=(1.05, 0.7), loc='upper left')

plt.xticks(rotation=90)
plt.ylabel('净收益(美元/人/年)', fontsize=14)
plt.title('室内空气质量干预的健康与间接收益', fontsize=14)

plt.tight_layout()
plt.show()

方式2:合并为一个图例,分块展示颜色和形状说明

如果需要在同一个图例中区分颜色和形状的含义,可以自定义图例元素:

# 前面的绘图代码和方式1一致,替换图例部分即可
# 创建自定义图例元素
custom_legend = []
# 添加干预类型颜色条目
for type_, color in color_map.items():
    custom_legend.append(Line2D([0], [0], marker='o', color=color, linestyle='None',
                                markersize=8, label=type_))
# 添加分隔线(可选,提升可读性)
custom_legend.append(Line2D([0], [0], color='white', linestyle='None', label=''))
# 添加收益类型形状条目
for benefit, marker in marker_map.items():
    custom_legend.append(Line2D([0], [0], marker=marker, color='black', linestyle='None',
                                markersize=8, label=benefit))
# 添加y=0基准线
custom_legend.append(Line2D([0], [0], color='grey', linestyle='--', linewidth=1, label='y=0'))

plt.legend(handles=custom_legend, title='图例说明', bbox_to_anchor=(1.05, 1), loc='upper left')

内容的提问来源于stack exchange,提问作者ZHoskin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 12:32:04