文章目录(Table of Contents)
简介
有的时候看论文的时候, 会看到表格与柱状图结合的例子, 像下面这样. 这一篇我们就来使用matplotlib来复现一下这种图像.
参考链接
- 完整的notebook链接, 绘制表格与柱状图.ipynb
- 关于matplotlib中table的介绍, 包括各个参数的含义(matplotlib的官方文档), matplotlib.pyplot.table;
- matplotlib中table和bar的结合的例子(matplotlib的官方文档), Table Demo
- 关于table中标题加粗的方法, bold text in matplotlib table
表格与柱状图结合的简单例子
下面简单看一下使用matplotlib来实现表格与柱状图结合. 首先导入需要的库. 关于完整的代码, 可以参考链接, 绘制表格与柱状图.ipynb.
- import numpy as np
- import pandas as pd
- import matplotlib.pyplot as plt
生成测试数据
首先我们生成需要的测试数据. 假设我们现在有5个模型, 有4个评测指标, 得到了如下的数据.
- data = [[ 66386, 174296, 75131, 577908, 32015],
- [ 58230, 381139, 78045, 99308, 160454],
- [ 89135, 80552, 152558, 497981, 603535],
- [ 78415, 81858, 150656, 193263, 69638]]
- columns = ('Model 1', 'Model 2', 'Model 3', 'Model 4', 'Model 5')
- rows = ['Metric %d' % x for x in (1, 2, 3, 4)]
- pltPD = pd.DataFrame(data, columns=columns, index=rows)
- pltPD
得到的表格如下所示, 一般情况下, 如果比较不同模型之间的结果, 都会有如下的表格:
按照模型进行汇总绘制
首先我们按照模型进行绘制. 将同一个模型的不同指标绘制在一起. 下面是完整的代码. 我们简单说一下需要注意的点:
- 绘制这种图像就是首先绘制柱状图, 接着绘制table, 把这两个和在一起.
- 自定义颜色, colors, 是用来指定柱状图的颜色, 这个颜色会和下面表格中的颜色对应.
- 我们会对矩阵也进行高亮, 为了更加突出颜色的分布, 我们会对数据进行最大最小标准化, 即(x-min)/(max-min).
- 最后需要注意, 需要把xticks设置为空.
同时, 我们要使用下面的代码对表格里的文字进行适当的放大. 这里scale中的1.7是纵向进行拉伸.
- the_table.set_fontsize(14)
- the_table.scale(1.0, 1.7) # may help
下面是完整的代码.
- # 按照model来进行汇总, 这里共有5个model
- fig = plt.figure(figsize=(12,8))
- ax = fig.add_subplot(1,1,1)
- # 自定义颜色
- # colors = plt.cm.BuPu(np.linspace(0, 0.5, len(pltPD.index.values)))
- colors = plt.cm.rainbow(np.linspace(0, 1, len(pltPD.index.values))) # plasma, rainbow, jet
- n_rows = len(pltPD.index.values)
- # 设置barchart的x轴
- w=0.3
- index = np.arange(len(pltPD.columns.values))*n_rows*w*1.5 # 5个model, 所以是5
- # 首先绘制柱状图
- for row in range(n_rows):
- plt.bar(index+row*w, pltPD.values[row], width=w, align='center', color=colors[row], label=pltPD.index.values[row])
- # 添加图例
- ax.legend(fontsize=12)
- # 矩阵的颜色高亮
- # norm = plt.Normalize(0, 1)
- # cellColours = plt.cm.Blues(norm(pltPD.values))
- # 使用最大最小标准化, 使得颜色区分更大
- minmax = (pltPD.values - pltPD.values.min(1, keepdims=True)) / (pltPD.values.max(1, keepdims=True) - pltPD.values.min(1, keepdims=True))
- cellColours = plt.cm.Blues(minmax)
- # 添加一个表格在底部
- the_table = plt.table(cellText=pltPD.values,
- cellColours = cellColours,
- rowLabels=pltPD.index.values,
- rowColours=colors, # 每一列的颜色
- colLabels=pltPD.columns.values,
- loc='bottom',
- cellLoc='center')
- the_table.set_fontsize(14)
- the_table.scale(1.0, 1.7) # may help
- # 调整table的布局
- # plt.subplots_adjust(left=0.2, bottom=0.1)
- # label和ticks的设置
- # minN, maxN = pltPD.values.flatten().min(), pltPD.values.flatten().max()
- # plt.yticks(np.arange(minN, maxN, (maxN-minN)/5), fontsize=14)
- plt.yticks(np.arange(0, 1.1, 0.2), fontsize=14)
- plt.xticks([])
- plt.title('Comparison between Different Models', fontsize=14)
- plt.show()
最终绘制出来的图像如下图所示, 有几个点我们再强调一下:
- 下图是按照模型来进行汇总的, 同一个model的4个不同的指标会放在一起;
- 柱状图不同的颜色对应不同的指标, 这里的颜色是和下面table中的颜色是对应的;
按照评价指标进行汇总绘制
上面我们是按照模型进行汇总, 也就是同一个模型的不同的指标放在一起. 那么我们也可以按照指标来进行汇总. 例如将同一个模型的不同指标放在一起.
这里和上面代码几乎是一样的, 我们只需要对原始的矩阵进行转置操作即可.
- # 按照metric来进行汇总, 这里共有4种metric, 可以很容易比较模型的好坏
- fig = plt.figure(figsize=(12,8))
- ax = fig.add_subplot(1,1,1)
- # 进行转置
- pltPD = pltPD.T
- # 自定义颜色
- # colors = plt.cm.BuPu(np.linspace(0, 0.5, len(pltPD.index.values)))
- colors = plt.cm.rainbow(np.linspace(0, 1, len(pltPD.index.values))) # plasma, rainbow, jet
- n_rows = len(pltPD.index.values)
- # 设置barchart的x轴
- w=0.3
- index = np.arange(len(pltPD.columns.values))*n_rows*w*1.5 # 5个model, 所以是5
- # 首先绘制柱状图
- for row in range(n_rows):
- plt.bar(index+row*w, pltPD.values[row], width=w, align='center', color=colors[row], label=pltPD.index.values[row])
- # 添加图例
- ax.legend(fontsize=12, loc='upper left')
- # 矩阵的颜色高亮
- # norm = plt.Normalize(pltPD.values.min(), pltPD.values.max())
- # cellColours = plt.cm.Blues(norm(pltPD.values))
- minmax = (pltPD.values - pltPD.values.min(1, keepdims=True)) / (pltPD.values.max(1, keepdims=True) - pltPD.values.min(1, keepdims=True))
- cellColours = plt.cm.Blues(minmax)
- # 添加一个表格在底部
- the_table = plt.table(cellText=pltPD.values,
- cellColours=cellColours,
- rowLabels=pltPD.index.values,
- rowColours=colors, # 每一列的颜色
- colLabels=pltPD.columns.values,
- loc='bottom',
- cellLoc='center')
- the_table.set_fontsize(14)
- the_table.scale(1.0, 1.7) # may help
- # 调整table的布局
- # plt.subplots_adjust(left=0.2, bottom=0.1)
- # label和ticks的设置
- # minN, maxN = pltPD.values.flatten().min(), pltPD.values.flatten().max()
- plt.yticks(np.arange(0, 1.1, 0.2), fontsize=14)
- plt.xticks([])
- plt.title('Comparison between Different Models', fontsize=14)
- plt.show()
最终可以得到下面的图像, 可以看到这样就是相同的评价指标会在一起. 这样很容易比较, 同一个评价指标, 哪一个模型是最好的.
表格双标题的情况(double headers)
上面说了最基础的绘制柱状图与表格结合的情况. 下面给一个例子, 当我们的table比较复杂的时候, 即拥有double headers的时候, 应该如何处理.
参考链接: Matplotlib table with double headers
其实主要的想法很简单, 我们同时添加多个table, 然后通过bbox来控制表格的位置即可. 这里说一下bbox的参数, 分别是(x0, y0, width, height). 需要注意的是, 这里(x0,y0)相当于矩形的左下角的点.
- header = plt.table(cellText=[['']*2],
- colLabels=['$\\bf{\lambda=0.02}$', '$\\bf{\lambda=0.99}$'],
- loc='bottom',
- cellLoc='center',
- bbox=[0, -0.2, 0.8, 0.2] # x0, y0, width, height
- )
- header.set_fontsize(14)
- header.scale(1.0, 1.7) # may help
- header_1 = plt.table(cellText=[['']],
- colLabels=['$\\bf{RL}$'],
- loc='bottom',
- cellLoc='center',
- bbox=[0.8, -0.2, 0.2, 0.2]
- )
- header_1.set_fontsize(14)
- header_1.scale(1.0, 1.7) # may help
下面是完整的代码, 我们只需要添加上面的部分即可, 剩下的都是一样的.
- # 按照model来进行汇总, 这里共有5个model
- fig = plt.figure(figsize=(12,8))
- ax = fig.add_subplot(1,1,1)
- # 自定义颜色
- # colors = plt.cm.BuPu(np.linspace(0, 0.5, len(pltPD.index.values)))
- colors = plt.cm.rainbow(np.linspace(0, 1, len(pltPD.index.values))) # plasma, rainbow, jet
- n_rows = len(pltPD.index.values)
- # 设置barchart的x轴
- w=0.3
- index = np.arange(len(pltPD.columns.values))*n_rows*w*1.5 # 5个model, 所以是5
- # 首先绘制柱状图
- for row in range(n_rows):
- plt.bar(index+row*w, pltPD.values[row], width=w, align='center', color=colors[row], label=pltPD.index.values[row])
- # 添加图例
- ax.legend(fontsize=12)
- # 矩阵的颜色高亮
- # norm = plt.Normalize(0, 1)
- # cellColours = plt.cm.Blues(norm(pltPD.values))
- # 使用最大最小标准化, 使得颜色区分更大
- minmax = (pltPD.values - pltPD.values.min(1, keepdims=True)) / (pltPD.values.max(1, keepdims=True) - pltPD.values.min(1, keepdims=True))
- cellColours = plt.cm.Blues(minmax)
- # 给表格添加一个标题
- header = plt.table(cellText=[['']*2],
- colLabels=['$\\bf{\lambda=0.02}$', '$\\bf{\lambda=0.99}$'],
- loc='bottom',
- cellLoc='center',
- bbox=[0, -0.2, 0.8, 0.2] # x0, y0, width, height
- )
- header.set_fontsize(14)
- header.scale(1.0, 1.7) # may help
- header_1 = plt.table(cellText=[['']],
- colLabels=['$\\bf{RL}$'],
- loc='bottom',
- cellLoc='center',
- bbox=[0.8, -0.2, 0.2, 0.2]
- )
- header_1.set_fontsize(14)
- header_1.scale(1.0, 1.7) # may help
- # 添加一个表格在底部
- the_table = plt.table(cellText=pltPD.values,
- cellColours = cellColours,
- rowLabels=pltPD.index.values,
- rowColours=colors, # 每一列的颜色
- colLabels=pltPD.columns.values,
- loc='bottom',
- cellLoc='center',
- bbox=[0, -0.6, 1.0, 0.5])
- the_table.set_fontsize(14)
- the_table.scale(1.0, 1.7) # may help
- # 调整table的布局
- # plt.subplots_adjust(left=0.2, bottom=0.1)
- # label和ticks的设置
- # minN, maxN = pltPD.values.flatten().min(), pltPD.values.flatten().max()
- # plt.yticks(np.arange(minN, maxN, (maxN-minN)/5), fontsize=14)
- plt.yticks(np.arange(0, 1.1, 0.2), fontsize=14)
- plt.xticks([])
- plt.title('Comparison between Different Models', fontsize=14)
- plt.show()
最终的效果如下所示:
- 微信公众号
- 关注微信公众号
- QQ群
- 我们的QQ群号
评论