最近在微信公众号做了一个自动回复的程序,主要功能是cpu性能查询与对比,数据有限,只能对比个跑分,但是对有些人来说也是有点用的,生成的对比图可以直观的看到两个cpu的大概性能差距。其中生成的cpu对比图就是本文要介绍的代码。
下面分享实现这个功能的代码,以及相关介绍,之所以想到要生成对比图,主要是考虑回复的文字太多,大家不一定愿意看,而且格式也不好调整,生成图片简单直观。希望我做的功能对大家有用。
首先展示下效果图:
生成的图片由三部分组成,标题、柱状对比图、表格,数据是从数据库中查询的,也可以使用测试数据来测试学习怎么生成。
其中的水印是用另一个程序生成的,参考另一篇文章:技术分享-Python简单几行代码实现给图片增加水印-nankle个人博客
代码实现:
import os
import matplotlib.pyplot as plt
from matplotlib import font_manager as fm
from matplotlib.table import Table
# 定义全局常量
IMAGE_DIR = '/tmp' # 将路径写死为 /tmp
def generate_cpu_comparison_chart(data):
"""
根据提供的数据生成CPU性能对比图。
"""
if not data:
return None
# 使用固定文件名
image_filename = 'cpu_comparison.png'
image_path = os.path.join(IMAGE_DIR, image_filename)
# 提取标签和值
labels = list(data.keys())
values = [float(item['mark'].replace(',', '')) for item in data.values()]
# 寻找最大值
max_value = max(values)
# 将所有的值转换为相对于最大值的百分比
normalized_values = [v / max_value * 100 for v in values]
# 设置颜色
bar_color = 'green'
# 创建一个新的figure,并设置尺寸
fig = plt.figure(figsize=(14, 7))
# 使用GridSpec布局 hspace 柱状图与表格间距
gs = plt.GridSpec(2, 1, height_ratios=[1.2, 2], hspace=0.1)
# 创建主图
ax = fig.add_subplot(gs[0, :])
# 绘制条形图
ax.barh(labels, normalized_values, color=bar_color, height=0.7)
# 移除边框
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
# 检查图例是否存在并移除
if ax.legend_ is not None:
ax.legend_.remove()
# 加载字体
fontprop = fm.FontProperties(fname='/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf')
# 设置 Matplotlib 使用的字体为 DejaVu Sans
plt.rcParams['font.family'] = 'DejaVu Sans'
plt.rcParams['font.sans-serif'] = ['DejaVu Sans']
# 设置正常显示符号
plt.rcParams['axes.unicode_minus'] = False
# 添加标题和轴标签
plt.title('CPU性能对比', fontproperties=fontprop, fontsize=40, fontweight='bold') # 设置字体大小和加粗
# 设置x轴刻度最小值为0,最大值为100
plt.xlim(0, 100)
# 调整y轴的范围,使其更加扁平
plt.ylim(-0.6, len(labels) - 0.3)
# 去除x轴的刻度
ax.set_xticks([])
# 去除y轴的刻度
ax.set_yticks([])
# 手动设置y轴标签的位置,并向右平移一点
ytick_positions = [i for i in range(len(labels))]
for i, label in enumerate(labels):
ax.text(+1, ytick_positions[i], label, va='center', ha='left', fontsize=16, fontweight='bold')
# 添加文本到每个条形的上方,并始终放置在x轴的最大值处
for i, value in enumerate(normalized_values):
ax.text(100+5, i, f'{int(value)}%', va='center', ha='right', fontsize=16, fontweight='bold')
# 创建信息图
info_ax = fig.add_subplot(gs[1, :])
info_ax.axis('off')
# 动态构建表格行数据
num_cpus = len(labels)
columns = ['属性'] + labels
# 构建表格行数据
attributes = ['名称', '分数', '功耗', '封装', '核心', '类型']
attribute_map = {'名称': 'name2', '分数': 'mark', '功耗': 'tdp', '封装': 'socket', '核心': 'cores', '类型': 'category'}
rows = []
for attr in attributes:
attr_key = attribute_map.get(attr, attr.lower())
row_data = [attr] + [str(data[key].get(attr_key, '')) for key in labels]
rows.append(row_data)
# 创建表格
info_table = Table(info_ax, bbox=[0, 0, 1, 1])
# 设置列宽比例
col_widths = [1] + [4] * num_cpus
total_width = sum(col_widths)
normalized_col_widths = [w / total_width for w in col_widths]
# 计算单元格宽度和高度
num_cols = len(columns)
num_rows = len(rows)
cell_height = 1 / num_rows
# 添加表格内容
for row_index, row in enumerate(rows):
for col_index, cell in enumerate(row):
# 计算当前列的宽度
cell_width = normalized_col_widths[col_index]
# 创建单元格
cell_obj = info_table.add_cell(row_index, col_index,
width=cell_width,
height=cell_height,
text=str(cell),
loc='center',
facecolor='lightgrey' if col_index == 0 else 'white')
# 设置单元格内的文本样式
cell_obj.get_text().set_fontsize(12)
cell_obj.get_text().set_fontweight('bold' if col_index == 0 else 'normal')
cell_obj.get_text().set_color('black')
# 设置表格样式
info_table.auto_set_font_size(False)
info_table.set_fontsize(14)
info_table.scale(1, 1.5)
# 将表格添加到轴
info_ax.add_table(info_table)
# 调整图表的边距
plt.subplots_adjust(left=0.05, right=0.93, top=0.9, bottom=0.05)
# 保存图像
if not os.path.exists(IMAGE_DIR):
os.makedirs(IMAGE_DIR)
plt.savefig(image_path, dpi=200, bbox_inches='tight')
plt.close(fig)
return image_path
# 测试数据
test_data = {
'Intel Core i7-10700K': {'name2': 'Intel Core i7-10700K', 'mark': '50000', 'tdp': '125W', 'socket': 'LGA 1200', 'cores': '8', 'category': 'Desktop'},
'AMD Ryzen 7 5800X': {'name2': 'AMD Ryzen 7 5800X', 'mark': '35000', 'tdp': '105W', 'socket': 'AM4', 'cores': '8', 'category': 'Desktop'}
}
# 调用测试方法
generate_cpu_comparison_chart(test_data)
上面的代码可以直接运行,运行此代码后,会在 /tmp
目录下生成名为 cpu_comparison.png
的图片
需要注意的点
中文字体问题:
fontprop = fm.FontProperties(fname='/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf')
这段代码设置了字体,如果本地没有这个字体就会乱码,可以自行下载中文字体并替换该路径。
保存的路径:
上面演示的代码路径写死,需要使用时根据情况调整。
如何本地测试:
要在本地运行上述Python代码进行测试,你需要确保你的环境中已经安装了必要的库,并且环境支持Matplotlib绘图。下面是详细的步骤:
安装依赖:
确保你已经安装了matplotlib
库。如果没有安装,可以通过pip来安装它:
pip install matplotlib
准备环境:
确保你的Python环境可以正确地创建和显示图像。如果你是在没有图形界面(如服务器环境)上运行,则可能需要安装无头后端(例如Agg后端)来生成图像文件而不是尝试显示它们:
pip install matplotlib[aagg]
并且在脚本开始的地方添加以下代码:
import matplotlib
matplotlib.use('Agg') # 在没有GUI的环境中使用非交互式后端
运行代码:
把提供的代码保存成一个.py
文件,比如叫cpu_comparison.py
。
执行脚本:
在命令行中运行这个脚本:
python cpu_comparison.py
这将会生成一张名为cpu_comparison.png
的图片,并保存在/tmp
目录下(如果你的操作系统允许的话)。如果你想要改变保存的路径,可以在代码中修改IMAGE_DIR
变量的值。
查看结果:
图片生成后,你可以手动打开/tmp
目录查看图片,或者通过其他方式展示它
如果你是在一个有图形界面的环境中(如windows),那么生成的图片会直接保存在指定路径,你可以直接打开查看。如果你是在服务器或者其他没有图形界面的环境中,你需要手动检查路径来确认图片是否成功生成。
评论区