Matplotlib子图柱状图:为不同指标柱子设置固定对应颜色
问题描述
我有多个共享坐标轴的子图,希望在每个子图中,对应Recall指标的柱子使用指定颜色,对应Precision指标的柱子使用另一固定颜色,其余指标的柱子也分别匹配专属固定颜色。
原代码运行效果参考:
共享轴子图示例
原实现代码
# data values = list([['nan', 'nan', 0.25, 0.25], ['nan', 'nan', 0.813, 0.413], ['nan', 'nan', 0.13793, 0.793], [0.5, 0.4666, 0.6666666, 0.75], [0.725, 0.13, 0.444, 0.5], [0.33337, 0.7776, 0.53, 0.86], [0.296, 0.33, 0.68, 0.4722], [0.158, 0.166, 0.45, 0.3477], [0.22063, 0.2218, 0.54, 0.7778], [0.8421, 0.199, 0.57, 0.4333], [0.36842105, 0.545, 0.386, 0.155567], [0.62281, 0.23394, 0.46, 0.36667]]) index_1 = ['1', '2', '4', '5'] index_2 = ['Recall', 'Precision', 'F1'] iterables = [index_1, index_2] index = pd.MultiIndex.from_product(iterables, names=["ClusterID", "Metric"]) df = pd.DataFrame(values, columns = ['Method1', 'Method2', 'Method3', 'Method4'], index = index) c = ['red', 'yellow', 'black'] ax = df.unstack(level=0).plot(kind='bar', subplots=True, rot=0, figsize=(20, 18), layout=(4, 4), color = c) def_ylim = (0.0, 0.8) plt.setp(ax, ylim = def_ylim) plt.tight_layout(pad=0.6, w_pad=0.6, h_pad=1.0)
问题原因
直接在plot()方法里传入长度为3的颜色列表时,pandas会按列的顺序循环分配颜色,和你需要按行索引(Metric)固定匹配颜色的逻辑不匹配,无法实现同指标同色的效果。另外原数据里的'nan'是字符串格式,不是真正的空值,容易触发绘图类型错误。
实现方案
核心思路是先建立指标和颜色的固定映射表,绘图完成后遍历所有子图,按柱子对应的指标名逐一设置颜色,不受列顺序影响。
完整可运行代码如下:
import pandas as pd import numpy as np import matplotlib.pyplot as plt # 加载并预处理数据 把字符串'nan'替换为真正的空值 values = [ [np.nan, np.nan, 0.25, 0.25], [np.nan, np.nan, 0.813, 0.413], [np.nan, np.nan, 0.13793, 0.793], [0.5, 0.4666, 0.6666666, 0.75], [0.725, 0.13, 0.444, 0.5], [0.33337, 0.7776, 0.53, 0.86], [0.296, 0.33, 0.68, 0.4722], [0.158, 0.166, 0.45, 0.3477], [0.22063, 0.2218, 0.54, 0.7778], [0.8421, 0.199, 0.57, 0.4333], [0.36842105, 0.545, 0.386, 0.155567], [0.62281, 0.23394, 0.46, 0.36667] ] index_1 = ['1', '2', '4', '5'] index_2 = ['Recall', 'Precision', 'F1'] iterables = [index_1, index_2] index = pd.MultiIndex.from_product(iterables, names=["ClusterID", "Metric"]) df = pd.DataFrame(values, columns=['Method1', 'Method2', 'Method3', 'Method4'], index=index) # 自定义指标-颜色映射 可根据汇报需求自行修改色值 metric_color = { 'Recall': 'red', 'Precision': 'yellow', 'F1': 'black' } plot_data = df.unstack(level=0) # 先绘图 不指定颜色 axs = plot_data.plot( kind='bar', subplots=True, rot=0, figsize=(20, 18), layout=(4, 4) ) # 遍历所有子图 给对应指标的柱子设置固定颜色 metrics = plot_data.index.tolist() for row in axs: for ax in row: if not ax.has_data(): continue # 子图内柱子顺序和metrics顺序完全一致 按索引匹配即可 for i, bar_group in enumerate(ax.containers): current_metric = metrics[i] for bar in bar_group: bar.set_color(metric_color[current_metric]) # 统一设置坐标轴范围 原0.8上限会截断0.813、0.86的高值柱子,调整为0.9更合适 plt.setp(axs, ylim=(0.0, 0.9)) plt.tight_layout(pad=0.6, w_pad=0.6, h_pad=1.0) plt.show()
调整说明
- 颜色映射直接修改
metric_color字典即可,支持十六进制色值、RGB元组、matplotlib内置颜色名等所有合法颜色格式 - 如果需要显示图例,可以在
plot()参数里加legend=True,再统一给图例设置对应颜色标签即可 - 子图标题、坐标轴标签可以根据汇报需求在遍历子图时通过
ax.set_title()、ax.set_xlabel()等方法自定义
内容的提问来源于stack exchange,提问作者rollhech
相关产品推荐
相关产品推荐

