概述
效果图镇楼
想看细节的可以一点点看,想Copy代码的,直接看下面代码部分
背景
最近在研究使用matplotlib直接从数据生成表格图片的实现方式。
进阶需求是把其中一列按百分比使背景色从左到右填充单元格,这里给出了一个可以用来解决问题的方法。
实现相关的技术点
- matplotlib绘制图表时的x,y是坐标轴里的x,y,并不是像素位置
- Table类有一个字典是用来保存行列元组和对应位置Cell的成员变量
- Cell类继承于Rectangle类,绘制的方式是绘制一个矩形然后填充下文字
- Rectangle类主要由左下角顶点在坐标系里的坐标,矩形的宽,矩形的高几个成员变量组成
- 每个Cell对象的左下角顶点坐标只有在最后保存图片进行绘制时才会去计算其位置(在执行object_of_cell.draw(renderer)之前)
- 可以通过object_of_cell.draw = MethodType(new_draw_method,object_of_cell)的方式指定object_of_cell这个对象的draw方法是new_draw_method
- Python中的对象可以动态增加成员变量
实现思路
利用技术点6和5,可以在绘制Cell的时候多绘制一个矩形出来作为百分比条,宽度可以通过技术点7来设置
实现步骤(不包含各种读取数据&生成Table对象的逻辑)
- 新写一个方法new_draw(self,renderer)作为绘制格子时的函数的逻辑,绘制原本的方框,利用原本的左下角顶点坐标绘制新的百分比填充的色块,最后填充文本
- 使用数据生成一个Table对象后,遍历其中Cell,对于符合条件的格子增加一个成员变量inner_width,保存百分比小格子的宽度,也就是当前格子宽度*这个格子保存的浮点数,区间[0,1],然后指定这个Cell对象的draw方法是上面新写的new_draw方法
- 最后保存的时候特殊格子调用的draw方法是我们新写的方法,就可以实现想要的功能了
实现代码
- new_draw方法的代码
def draw_processing_bar_cell(self, renderer):
if not self.get_visible():
return
# draw the rectangle
table_lib.Rectangle.draw(self, renderer)
# 绘制一个不完全填充整个格子的矩形,这里可以根据个人需求进行编码
old_width = self.get_width() # 这里需要记录下原来的宽度,等下文本的居中对齐会用这个宽度进行对齐,画完条要进行还原
self.set_width(self.inner_width)
if self.processing_bar_color is None:
self.processing_bar_color = '#FFDAB9'
self.set_facecolor(self.processing_bar_color)
self.set_alpha(0.5)
self.set_edgecolor(None)
patches.Rectangle.draw(self, renderer)
# position the text
self.set_width(old_width) # 还原宽度
self._set_text_position(renderer)
self._text.draw(renderer)
self.stale = False
- 遍历Table对象保存的Cell对象并进行更新的代码
# 遍历获取所有的cell
for key, cell in my_table.get_celld().items():
row, col = key
# 非表头行的最后一列是浮点数,代表进度,也就是要处理的列
if col == len(file.columns) - 1 and row > 0:
# 更新文本 文本本身是很长的浮点数的字符串,格式化成保留2位小数的按百分比显示的字符串
# 因为cell.get_text()的返回值是Text对象,Text对象再次get_text()获得到的才是要显示的文本,所以需要get_text().set_text(xxx)和get_text().get_text()
old_text = cell.get_text().get_text()
new_text = str('{:.2%}'.format(float(old_text)))
cell.get_text().set_text(new_text)
# 为cell添加新的属性inner_width&processing_bar_color,并且指定新的draw方法
cell.inner_width = cell.get_width() * table_vals[row - 1][col]
cell.processing_bar_color = '#FFDAB9'
cell.draw = MethodType(draw_processing_bar_cell, cell)
- 整体的代码
# -*- coding:utf-8 -*-
from types import MethodType
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import matplotlib.table as table_lib
import pandas as pd
def draw_processing_bar_cell(self, renderer):
if not self.get_visible():
return
# 绘制标准的cell
table_lib.Rectangle.draw(self, renderer)
# 按百分比绘制色块,因为等下绘制文本还要用到原本的宽度,所以先记录下原本宽度,等下改回去
old_width = self.get_width()
self.set_width(self.inner_width)
if not hasattr(self, 'processing_bar_color'):
self.processing_bar_color = '#FFAA00'
self.set_facecolor(self.processing_bar_color)
self.set_alpha(0.5)
self.set_edgecolor(None)
patches.Rectangle.draw(self, renderer)
# 绘制文本,先把cell的宽度改回去
self.set_width(old_width)
self._set_text_position(renderer)
self._text.draw(renderer)
self.stale = False
# 读取数据
file = pd.read_excel('/path/to/your/origin_data_file.xlsx')
# 设置字体样式&编码 主要解决中文方框
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 绘图参数
dpi = 720
figure_height = 2
figure_width = 2
# 数据转二维数组并取出表头
column_names = file.columns.tolist()
table_vals = file.values.tolist()
# 创建画布
plt.figure(figsize=(figure_width, figure_height), dpi=dpi)
my_table = plt.table(cellText=table_vals, colLabels=column_names, loc='center', cellLoc='center')
# 遍历获取所有的cell
for key, cell in my_table.get_celld().items():
row, col = key
# 非表头行的最后一列是浮点数,代表进度,也就是要处理的列
if col == len(file.columns) - 1 and row > 0:
# 更新文本 文本本身是很长的浮点数的字符串,格式化成保留2位小数的按百分比显示的字符串
# 因为cell.get_text()的返回值是Text对象,Text对象再次get_text()获得到的才是要显示的文本,所以需要get_text().set_text(xxx)和get_text().get_text()
old_text = cell.get_text().get_text()
new_text = str('{:.2%}'.format(float(old_text)))
cell.get_text().set_text(new_text)
# 为cell添加新的属性inner_width&processing_bar_color,并且指定新的draw方法
cell.inner_width = cell.get_width() * table_vals[row - 1][col]
cell.processing_bar_color = '#FFDAB9'
cell.draw = MethodType(draw_processing_bar_cell, cell)
plt.axis('off')
# 保存图片时内部会调用到各个对象的draw的逻辑,特殊的Cell对象的新的draw逻辑会被调用到
plt.savefig('/path/to/your/out_result_figure.jpg', dpi=dpi)
显示样式
最后
以上就是健壮枫叶为你收集整理的[Python]使用matplotlib库实现在Cell中不完全填充颜色的全部内容,希望文章能够帮你解决[Python]使用matplotlib库实现在Cell中不完全填充颜色所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复