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

Matplotlib自定义线条颜色后图例未更新问题求助

问题:自定义线条颜色后图例未同步更新

基于Pandas透视表绘制12个月对应线条时,手动设置自定义颜色后图表线条颜色已更新,但图例仍显示旧颜色。涉及4个国家的子图布局,代码片段如下:

fig, axs = plt.subplots(4, 3)

for i, country in enumerate(countries):
    
    pivot_yearly = pd.pivot_table(df[country].to_frame(), index=df.index.month, columns=df.index.year)
    pivot_monthly = pd.pivot_table(df[country].to_frame(), index=df.index.weekday, columns=df.index.month) # 问题出在此处
    pivot_dyyr = pd.pivot_table(df[country].to_frame(), index=df.index.weekday, columns=df.index.year)
    
    axs[i,0].plot(pivot_yearly)

    cm = plt.get_cmap('gist_rainbow')
    cNorm = colors.Normalize(vmin=0, vmax=11)
    scalarMap = mplcm.ScalarMappable(norm=cNorm, cmap=cm)

    axs[i,1].set_prop_cycle(color=[scalarMap.to_rgba(j) for j in range(12)])
    axs[i,1].plot(pivot_monthly)

    axs[i,3].plot(pivot_dyyr)

labels = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split()
leg1 = fig.legend(pivot_yearly.columsn.get_level_values('Date'), ncols=3)
leg2 = fig.legend(pivot_monthly.columns.get_level_values('Date'), labels=labels, ncols=3)
leg3 = fig.legend(pivot_dyyr.columns.get_level_values('Date'), ncols=3)

plt.tight_layout()
plt.show()

注:数据包含4个国家,索引为DateTimeIndex,无法共享数据。执行axs[i,1].set_prop_cycle()后线条颜色更新,但图例未同步更新。


解决方案

问题根源

直接通过fig.legend()从透视表列生成图例时,没有关联子图中已生效的自定义颜色循环,导致图例使用Matplotlib默认颜色,而非你设置的自定义颜色。

修正代码及关键说明

import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cm as mplcm
import pandas as pd

# 初始化子图(修复原代码列索引越界问题:4行3列,列索引为0/1/2)
fig, axs = plt.subplots(4, 3, figsize=(16, 12))
month_labels = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split()

for i, country in enumerate(countries):
    # 生成透视表
    pivot_yearly = pd.pivot_table(df[country].to_frame(), index=df.index.month, columns=df.index.year)
    pivot_monthly = pd.pivot_table(df[country].to_frame(), index=df.index.weekday, columns=df.index.month)
    pivot_dyyr = pd.pivot_table(df[country].to_frame(), index=df.index.weekday, columns=df.index.year)
    
    # 年度子图
    axs[i, 0].plot(pivot_yearly)
    axs[i, 0].set_title(f"{country} - 年度趋势")
    
    # 月度子图:应用自定义颜色并保存线条对象
    cm = plt.get_cmap('gist_rainbow')
    cNorm = colors.Normalize(vmin=0, vmax=11)
    scalarMap = mplcm.ScalarMappable(norm=cNorm, cmap=cm)
    custom_colors = [scalarMap.to_rgba(j) for j in range(12)]
    
    axs[i, 1].set_prop_cycle(color=custom_colors)
    # 保存绘图返回的线条对象,用于后续关联图例
    monthly_lines = axs[i, 1].plot(pivot_monthly)
    axs[i, 1].set_title(f"{country} - 月度趋势")
    
    # 日度-年度子图(修复原代码axs[i,3]的索引错误)
    axs[i, 2].plot(pivot_dyyr)
    axs[i, 2].set_title(f"{country} - 周内日度年度趋势")

# 生成匹配颜色的图例
# 月度图例:从子图线条对象获取颜色,确保和图表一致
first_month_lines = axs[0, 1].get_lines()
fig.legend(first_month_lines, month_labels, loc='lower center', ncols=6, fontsize=10)

# 年度图例:从第一个子图的线条和透视表列标签生成
first_year_lines = axs[0, 0].get_lines()
year_labels = pivot_yearly.columns.get_level_values('Date').unique()
fig.legend(first_year_lines, year_labels, loc='upper center', ncols=3, fontsize=10)

# 日度-年度图例
first_dyyr_lines = axs[0, 2].get_lines()
dyyr_labels = pivot_dyyr.columns.get_level_values('Date').unique()
fig.legend(first_dyyr_lines, dyyr_labels, loc='center', ncols=3, fontsize=10)

# 调整布局,给图例预留空间
plt.tight_layout(rect=[0, 0.08, 1, 0.92])
plt.show()

核心修改点

  1. 修复索引错误:原代码中axs[i,3]超出4行3列的子图索引范围,改为axs[i,2]。
  2. 关联线条与图例:不再直接从透视表列生成图例,而是从子图的lines对象(已应用自定义颜色循环)获取颜色和标签,确保图例与图表线条颜色完全匹配。
  3. 优化布局:通过tight_layout的rect参数调整画布范围,避免图例与子图重叠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 06:30:31