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()
核心修改点
- 修复索引错误:原代码中
axs[i,3]超出4行3列的子图索引范围,改为axs[i,2]。 - 关联线条与图例:不再直接从透视表列生成图例,而是从子图的
lines对象(已应用自定义颜色循环)获取颜色和标签,确保图例与图表线条颜色完全匹配。 - 优化布局:通过
tight_layout的rect参数调整画布范围,避免图例与子图重叠。
内容的提问来源于stack exchange,提问作者user21551428
相关产品推荐
相关产品推荐

