使用pandas groupby绘制散点图的颜色映射警告及同色问题
Pandas groupby绘制散点图的颜色映射问题
问题描述
使用pandas的groupby绘制散点图时,两类数据颜色完全相同,同时出现颜色映射警告。示例代码如下:
import pandas as pd import matplotlib.pyplot as plt df = pd.DataFrame(data= {'class': ['A']*5 + ['B']*5, 'index': [i for i in range(10)], 'data': [i for i in range(5)] + [i+1 for i in range(5)]}) # Plotting fig, ax = plt.subplots() for key, grp in df.groupby('class'): grp.plot.scatter(ax=ax, x='index', y='data', label=key)
运行后出现警告:
/opt/miniconda3/lib/python3.8/site-packages/pandas/plotting/_matplotlib/core.py:1114: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored
scatter = ax.scatter(
但如果用df.plot(ax=ax, x='index', y='data', label=key)替代散点图方法,颜色显示正常且无警告。
原因分析
- 颜色循环机制差异:
- pandas的
plot.scatter()本质是直接调用matplotlib的ax.scatter(),每次调用都会从颜色循环的起始位置取色,不会自动推进颜色索引,导致多次调用时颜色重复。 - 而
df.plot()默认绘制折线图,pandas会自动维护颜色循环状态,每次调用取下一个颜色,因此分组后的颜色能自动区分。
- pandas的
- 警告产生原因:
plot.scatter()默认尝试使用颜色映射(cmap),但需要通过c参数传入数值型数据实现颜色映射。代码中未提供c参数,因此触发警告,cmap参数被忽略,最终使用默认颜色。
解决方案
方法1:手动指定颜色列表
预先定义颜色列表,循环中按索引取色:
import pandas as pd import matplotlib.pyplot as plt df = pd.DataFrame(data= {'class': ['A']*5 + ['B']*5, 'index': [i for i in range(10)], 'data': [i for i in range(5)] + [i+1 for i in range(5)]}) colors = ['red', 'blue'] # 对应A、B两类的颜色 fig, ax = plt.subplots() for idx, (key, grp) in enumerate(df.groupby('class')): grp.plot.scatter(ax=ax, x='index', y='data', label=key, color=colors[idx]) plt.legend() plt.show()
方法2:使用matplotlib原生scatter方法
绕开pandas的plot包装,直接调用matplotlib的scatter,利用其自动颜色循环:
import pandas as pd import matplotlib.pyplot as plt df = pd.DataFrame(data= {'class': ['A']*5 + ['B']*5, 'index': [i for i in range(10)], 'data': [i for i in range(5)] + [i+1 for i in range(5)]}) fig, ax = plt.subplots() for key, grp in df.groupby('class'): ax.scatter(grp['index'], grp['data'], label=key) plt.legend() plt.show()
方法3:利用seaborn简化分组绘图
seaborn的relplot可直接按列分组绘图,无需手动循环:
import pandas as pd import seaborn as sns df = pd.DataFrame(data= {'class': ['A']*5 + ['B']*5, 'index': [i for i in range(10)], 'data': [i for i in range(5)] + [i+1 for i in range(5)]}) sns.relplot(data=df, x='index', y='data', hue='class', kind='scatter') plt.show()
使用的包版本
- pandas: 1.4.3
- matplotlib: 3.6.2
内容的提问来源于stack exchange,提问作者gioarma
相关产品推荐
相关产品推荐

