「—使用plottable库绘制精美表格」
1.内容概要 Matplotlib 作为 python 数据可视化的强力第三方库,可以创作各式各样的数据可视化图表,其中 matplotlib.pyplot.table 模块就专门用于绘制表格,但是由于参数复杂,默认样式单一简陋,想基于该模块绘制精美的表格较为困难。「plottable」 是一个基于 matplotlib 的第三方库,可用于简单实现精美表格的绘制。本文将基于plottable 的官方文档,总结 plottable 的使用方法,并通过实际案例,来展示 plottable 绘制表格的效果。本案例使用杭州市 2022 和 2023 年各区县人口数量、城镇化率和人口增长率等数据来绘制表格,绘制效果如下: 若需要本案例数据,还请「点赞+在看」 支持,在公众号对话框回复「20240315」 即可获取。
2.plttable 的使用说明 plottable 的官方文档地址为:
https://plottable./en/latest/index.html
plottable 安装命令如下:
pip install plottable
☆在已有 DataFrame 的基础上,调用 plottable 中的 Table 模块即可绘制表格。Table()函数中用于绘制和美化表格的参数如下:df: pd.DataFrame, 要显示为表格的 DataFrame 对象; ax: mpl.axes.Axes, 绘制表格的坐标轴对象,默认为 None; index_col: str, DataFrame 中的索引列名。默认为 None; columns: List[str], 哪些列用于绘图。为 None 表示使用所有列; column_definitions: List[ColumnDefinition], 需要设置样式列的 style 定义类,默认为 None; textprops: Dict[str, Any], 文本属性的字典,默认为空字典; cell_kw: Dict[str, Any], 单元格属性的字典,默认为空字典; col_label_cell_kw: Dict[str, Any], 列标签单元格属性的字典,默认为空字典; col_label_divider: bool, 是否在列标签下方绘制分隔线,默认为 True; footer_divider: bool, 是否在表格下方绘制分隔线,默认为 False; row_dividers: bool, 是否显示行分隔线,默认为 True; row_divider_kw: Dict[str, Any], 行分隔线属性的字典,默认为空字典; col_label_divider_kw: Dict[str, Any], 列标签分隔线属性的字典,默认为空字典; footer_divider_kw: Dict[str, Any], 页脚分隔线属性的字典,默认为空字典; column_border_kw: Dict[str, Any], 列边框属性的字典,默认为空字典; even_row_color: str | Tuple, 偶数行单元格的填充颜色,默认为 None; odd_row_color: str | Tuple, 奇数行单元格的填充颜色,默认为 None; ☆在这些参数之中,控制表格绘图效果的参数有以下几类:column_definitions:列的样式自定义; 其中最常用数为 column_definitions,可用于控制表格几乎所有的绘制效果。通过 ColumnDefinition 类来设置 Table 类的 column_definitions 参数,可以实现不同表格多列样式的绘制,输入的参数如下:
title: str = None,用于覆盖列名的绘图标题; width: float = 1,列的宽度,默认情况下各列的宽度为轴的宽度/列的总数; textprops: Dict[str, Any] = field(default_factory=dict),提供给每个文本单元格的文本属性; formatter: Callable = None,用于格式化文本外观的可调用函数; cmap: Callable = None,根据单元格的值返回颜色的可调用函数; text_cmap: Callable = None,根据单元格的值返回颜色的可调用函数; group: str = None,设置每个组都会在列标签上方显示的分组列标签; plot_fn: Callable = None,一个可调用函数,将单元格的值作为输入,并在每个单元格上创建一个子图并绘制在其上; plot_kw: Dict[str, Any] = field(default_factory=dict),提供给 plot_fn 的附加关键字参数; border: str | List = None,绘制垂直边界线,可以是'left' / 'l'、'right' / 'r'或'both'; 如果要对多个列的绘图效果进行自定义,则需要使用[ColumnDefinition(), ColumnDefinition()...]列表的形式,同时对多个列的样式进行自定义。
☆此外,plottable 可以直接访问 Table 中的某一行、某一列:# 根据列名A,提取整列 tab.columns['A' ]# 根据行索引,提取第2行整行 tab.rows[1]# 读取A列第1行的内容 tab.columns['A' ].cells[1].content# 提取表头列名 tab.col_label_row
可以通过设置指定行列的绘图属性来直接更改其绘图效果或文字效果,所支持更改的属性如下:
单元格属性:
set_edgecolor:设置单元格边缘的颜色; set_facecolor:设置单元格内部的颜色; set_linestyle:设置单元格边缘线的样式; set_linewidth:设置单元格边缘线的宽度; 字体属性:
2.表格绘制案例 原始数据如图所示:
绘制表格完整代码及详细注释:
import matplotlib.pyplot as pltimport pandas as pdfrom plottable import Table, ColumnDefinitionfrom plottable.plots import bar, progress_donutfrom matplotlib.colors import LinearSegmentedColormap# 设置字体为微软雅黑,防止绘制表格时由于存在中文而报错 plt.rcParams['font.sans-serif' ] = 'Microsoft YaHei' df = pd.read_excel('2022和2023年杭州市人口主要数据公报.xlsx' )# 由于原始数据“城镇化率(%)”和“常住人口(万人)”列名重复,所以pandas在读取数据后自动将第二个重名列的名称后面加了“.1”的后缀。 df['城镇化率(%)' ] = df['城镇化率(%)' ] / 100 #将百分数转换为小数,方便后续绘图 df['城镇化率(%).1' ] = df['城镇化率(%).1' ] / 100 df['人口增长率' ] = (df['常住人口(万人).1' ] - df['常住人口(万人)' ]) / df['常住人口(万人)' ] #计算人口增长率 print(df)# 创造一个颜色映射带 cmap = LinearSegmentedColormap.from_list( name='bugw' , colors=['#ffffff' , '#f2fbd2' , '#c9ecb4' , '#93d3ab' , '#35b0ab' ], N=256 )# 设置绘图背景的长宽 fig, ax = plt.subplots(figsize=(9 , 12 ))# 绘制表格 tab = Table(df,ax=ax, odd_row_color='#a5d8ff' , #设置奇偶列的表格背景颜色 even_row_color='white' , footer_divider=True , #显示表格尾端边界线 textprops={'ha' : 'center' }, # 设置表格中文字居中对齐 column_definitions=[ # 设置“index”列,将其名称设为空,宽度改为0,文本居右对齐,颜色设置为白色从而将其隐藏 ColumnDefinition(name='index' , title='' , width=0 , textprops={'ha' : 'right' ,'color' :'w' }), ColumnDefinition(name='地区' , textprops={'ha' : 'center' , 'fontsize' : 12 }), # 设置“常住人口(万人)”列的组别为2022年,绘制表格会在表头显示分组信息,字体设置为加粗。 ColumnDefinition(name='常住人口(万人)' , group='2022年' , textprops={'weight' : 'bold' }), # 设置“城镇化率(%)”列的组别为2022年,修改列名为’城镇化率'。 ColumnDefinition(name='城镇化率(%)' , title='城镇化率' , group='2022年' , plot_fn=progress_donut, # 将数据转换为圆环图形 plot_kw={'is_pct' : True , # True代表数据为比率数,不需要再除以100 'formatter' : '{:.2f}' , # 数据保留两位小数 'radius' : 0.48 , # 圆环的显示半0径 'textprops' :{'fontsize' :8 }}), # 数据的文本显示大小 ColumnDefinition(name='常住人口(万人).1' , title='常住人口(万人)' , group='2023年' , textprops={'weight' : 'bold' }), ColumnDefinition(name='城镇化率(%).1' , title='城镇化率' , group='2023年' , plot_fn=bar, plot_kw={'cmap' : cmap, # 给图形传入映射颜色带,从而根据数据大小,显示颜色的深浅。 'plot_bg_bar' : True , 'annotate' : True , 'height' : 0.8 , 'lw' : 0.5 , 'formatter' : '{:.1%}' }), ColumnDefinition(name='人口增长率' , formatter='{:.1%}' , textprops={'color' : 'g' , # 修改该列中文本颜色为绿色 'weight' : 'bold' }) ] )# 保存图片,裁掉其周围空白的区域。 plt.savefig('杭州市2022年和2023年人口主要数据公报.png' , dpi=600 , bbox_inches='tight' ) plt.show()
END