如何在Matplotlib折线图中添加同色系数据点并区分归属
解决Matplotlib折线图与对应数据点颜色匹配的问题
你遇到的问题其实很常见——当用pandas的plot接口分别画折线和散点时,两者默认的颜色循环是独立的,导致散点颜色和折线对不上,尤其是ID多的时候更混乱。这里有两种靠谱的解决办法,帮你轻松搞定:
方法1:获取折线的颜色并复用给散点
在循环里,每次画完折线后,我们可以提取出这条折线的颜色,然后把它传给散点图的c参数,这样散点就和折线颜色完全一致了。
修改后的代码如下:
import pandas as pd import matplotlib.pyplot as plt import numpy as np # 构造数据(特意加了缺失值测试场景) df = pd.DataFrame({ 'year': ['1988', '1989', '1990', '1988', '1989', '1990', '1988', '1989', '1990'], 'id': ['1', '1', '1', '2', '2', '2', '3', '3', '3'], 'money': ['5', '7', '8', '8', np.nan, '3', '7', '8', '10'] }).astype({'year': int, 'id': str, 'money': float}) fig, ax = plt.subplots() for i in df.id.unique(): # 画折线,并获取对应的线条对象 line_plot = df[df['id']==i].plot.line(x='year', y='money', ax=ax, label=f'id = {i}') # 提取当前折线的颜色值 line_color = line_plot.get_lines()[0].get_color() # 画散点,指定颜色与折线一致,加白边让点更清晰 df[df['id']==i].plot.scatter(x='year', y='money', ax=ax, c=line_color, edgecolor='white') plt.xticks(np.unique(df.year)) plt.legend() plt.show()
这里的核心是line_plot.get_lines()[0].get_color()——pandas的plot.line返回Axes对象,我们通过get_lines()拿到里面的线条列表,取第一个就是当前ID的折线,再用get_color()提取颜色值,直接传给散点图的c参数即可。
方法2:用单个plot函数同时画折线和标记点(更简便)
其实没必要分开画折线和散点,matplotlib的plot函数本身就支持同时绘制线条和标记点,颜色会自动保持一致,代码也更简洁:
import pandas as pd import matplotlib.pyplot as plt import numpy as np df = pd.DataFrame({ 'year': ['1988', '1989', '1990', '1988', '1989', '1990', '1988', '1989', '1990'], 'id': ['1', '1', '1', '2', '2', '2', '3', '3', '3'], 'money': ['5', '7', '8', '8', np.nan, '3', '7', '8', '10'] }).astype({'year': int, 'id': str, 'money': float}) fig, ax = plt.subplots() for i in df.id.unique(): subset = df[df['id']==i].sort_values('year') # 确保年份按顺序排列 # 用plot同时绘制折线和标记点,marker指定点样式,linestyle指定折线样式 ax.plot(subset['year'], subset['money'], marker='o', linestyle='-', label=f'id = {i}') plt.xticks(np.unique(df.year)) plt.legend() plt.show()
这种方法的优势很明显:
- 颜色自动匹配,完全不用手动提取和设置
- 代码更短,逻辑更清晰
- 即使有缺失值,折线会自动断开,但存在的数据点依然会显示标记,完美对应所属ID
额外提示:处理大量ID的情况
如果ID数量特别多,matplotlib的默认颜色循环可能不够用,你可以自定义颜色映射,比如用连续色系来生成足够多的独特颜色:
# 用tab20颜色映射,适合多类别场景,第二个参数指定颜色数量 cmap = plt.cm.get_cmap('tab20', len(df.id.unique())) for idx, i in enumerate(df.id.unique()): subset = df[df['id']==i].sort_values('year') ax.plot(subset['year'], subset['money'], marker='o', linestyle='-', color=cmap(idx), label=f'id = {i}')
这样不管有多少个ID,每个ID的折线和标记点都会有独特且对应的颜色,再也不会搞混啦!
内容的提问来源于stack exchange,提问作者Marco
相关产品推荐
相关产品推荐

