python 画出柱状图和折线图

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.ticker import FuncFormatter
from tkinter import Tk, filedialog, messagebox
import re

# 使用Tkinter创建文件选择对话框并显示提示信息
def select_file(file_type):
    root = Tk()
    root.withdraw()  # 隐藏主窗口
    if file_type == 'csv':
        messagebox.showinfo("选择CSV文件", "请选择监控数据的CSV文件")
        file_path = filedialog.askopenfilename(title="选择CSV文件", filetypes=[("CSV files", "*.csv")])
    elif file_type == 'excel':
        messagebox.showinfo("选择Excel文件", "请选择主机数据的Excel文件")
        file_path = filedialog.askopenfilename(title="选择Excel文件", filetypes=[("Excel files", "*.xls *.xlsx")])
    root.destroy()
    return file_path

# 选择文件路径
csv_file_path = select_file('csv')
xls_file_path = select_file('excel')

# 文件列名变量
csv_columns = {
    'datetime': '数据时间',
    'instance_id': '实例ID',
    'monitor_value': '监控值',
    'metric_name': '指标名'
}

xls_columns = {
    'name': '名称',
    'instance_id': '云主机ID'
}

# 读取CSV文件,尝试不同的编码
try:
    data = pd.read_csv(csv_file_path, encoding='utf-8')
except UnicodeDecodeError:
    data = pd.read_csv(csv_file_path, encoding='gbk')

# 读取Excel主机列表文件,并重命名列名以匹配
host_list = pd.read_excel(xls_file_path, usecols=[xls_columns['name'], xls_columns['instance_id']])
host_list = host_list.rename(columns={xls_columns['instance_id']: csv_columns['instance_id']})

# 提取实际的实例ID部分
data[csv_columns['instance_id']] = data[csv_columns['instance_id']].apply(lambda x: re.split('[:]', x)[0])

# 将数据时间列转换为datetime格式
data[csv_columns['datetime']] = pd.to_datetime(data[csv_columns['datetime']])

# 提取日期部分
data['日期'] = data[csv_columns['datetime']].dt.date

# 与主机列表合并,以获取主机名称
data = data.merge(host_list, on=csv_columns['instance_id'], how='left')

# 计算每日最高监控值
daily_max = data.groupby([xls_columns['name'], '日期', csv_columns['metric_name']])[csv_columns['monitor_value']].max().reset_index()

# 计算每日最高峰值的总和并求平均值
daily_max_sum = daily_max.groupby([xls_columns['name'], csv_columns['metric_name']])[csv_columns['monitor_value']].sum().reset_index()
daily_max_avg = daily_max_sum.copy()
daily_max_avg[csv_columns['monitor_value']] = daily_max_sum[csv_columns['monitor_value']] / daily_max['日期'].nunique()

# 设置Seaborn样式
sns.set(style="whitegrid")

# 自定义颜色
custom_color = (51 / 255, 152 / 255, 219 / 255)

# 设置字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用黑体显示中文
plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号

# 修改figsize以减小图像尺寸
smaller_figsize = (10, 5)

# 分别处理CPU使用率和内存使用率
for metric in data[csv_columns['metric_name']].unique():
    metric_data = daily_max_avg[daily_max_avg[csv_columns['metric_name']] == metric]

    # 找出TOP10的主机
    top10_hosts = metric_data.nlargest(10, csv_columns['monitor_value'])

    # 生成TOP10主机的每日最高峰值平均值柱状图
    plt.figure(figsize=smaller_figsize)
    bars = sns.barplot(x=xls_columns['name'], y=csv_columns['monitor_value'], data=top10_hosts, color=custom_color, width=0.5)
    plt.xlabel('', fontsize=12)  # 主机名称设置为空标签
    plt.ylabel('', fontsize=12)  # 平均监控值设置为空标签
    plt.title(f'TOP10主机每日最高峰值平均值 - {metric}', fontsize=15)
    plt.xticks(rotation=45)

    # 在每个柱子上显示数值
    for bar in bars.patches:
        height = bar.get_height()
        plt.text(bar.get_x() + bar.get_width() / 2.,
                 height,
                 f'{height:.2f}',
                 ha='center', va='bottom',
                 fontsize=10)  # 这里设置字体大小

    # 自定义Y轴刻度标签为百分比格式
    def percent_formatter(x, pos):
        return f'{x:.0f}%'

    ax = plt.gca()
    ax.yaxis.set_major_formatter(FuncFormatter(percent_formatter))

    # 设置Y轴范围为0到100
    ax.set_ylim(0, 100)

    # 取消柱状图的边框
    for spine in ax.spines.values():
        spine.set_visible(False)

    # 取消竖线
    ax.xaxis.grid(False)

    plt.tight_layout()
    plt.savefig(f'top10_daily_max_avg_bar_with_values_{metric}.png', bbox_inches='tight')
    plt.show()

    # 计算每日最高监控值并绘图
    fig = plt.figure(figsize=smaller_figsize)  # 这里调整线形图的尺寸
    ax = fig.add_subplot(1, 1, 1)

    for host in top10_hosts[xls_columns['name']]:
        host_data = daily_max[(daily_max[xls_columns['name']] == host) & (daily_max[csv_columns['metric_name']] == metric)]
        sns.lineplot(x='日期', y=csv_columns['monitor_value'], data=host_data, marker='o', label=host, ax=ax)

    plt.xlabel('', fontsize=12)  # 日期标签设置为空
    plt.ylabel('', fontsize=12)  # 最高监控值标签设置为空
    #plt.title(f'TOP10主机每日最高监控值 - {metric}', fontsize=15) #设置为空
    plt.title(f'', fontsize=15)  # 设置为空

    # 隐藏图形的边框
    for spine in ax.spines.values():
        spine.set_visible(False)

    # 设置x轴范围为数据的最小和最大日期
    min_date = daily_max['日期'].min()
    max_date = daily_max['日期'].max()
    ax.set_xlim([min_date, max_date])

    # 自定义Y轴刻度标签为百分比格式
    ax.yaxis.set_major_formatter(FuncFormatter(percent_formatter))

    # 设置Y轴范围为0到100
    ax.set_ylim(0, 100)

    # 取消竖线
    ax.xaxis.grid(False)
    # 显示x轴的下边框
    ax.spines['bottom'].set_visible(True)

    # 正确处理图例位置,将其移到图像上方,并设置frameon=False使其透明
    handles, labels = ax.get_legend_handles_labels()
    ax.legend(handles, labels, loc='lower center', bbox_to_anchor=(0.5, 1.02), fancybox=True, shadow=False, ncol=5, frameon=False)

    plt.xticks(rotation=45)
    plt.tight_layout(rect=[0, 0, 1, 0.95])  # 调整布局以适应图例
    plt.savefig(f'top10_daily_max_line_{metric}.png', bbox_inches='tight')
    plt.show()
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值