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

# 使用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': '监控值'
}

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']})

# 将数据时间列转换为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['monitor_value']].max().reset_index()

# 计算每日最高峰值的总和并求平均值
daily_max_sum = daily_max.groupby(xls_columns['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()

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

# 设置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)

# 生成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('', fontsize=15)  # TOP10主机每日最高峰值平均值设置为空标签
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('top10_daily_max_avg_bar_with_values.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]
    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('TOP10主机每日最高监控值', 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('top10_daily_max_line.png', bbox_inches='tight')
plt.show()

备注:云主机ID需要调整下

### 如何在柱状图上叠加折线图 为了在同一张图表上同时展示柱状图折线图,可以利用 `matplotlib` 的灵活性来完成这一目标。下面是一个具体的例子,展示了如何在一个图形窗口内既显示柱状图又显示折线图。 #### 创建样本数据集 首先,创建一些用于演示的数据: ```python import numpy as np import pandas as pd data = {'Category': ['A', 'B', 'C', 'D'], 'Values': [3, 7, 5, 9], 'LineData': [10, 20, 15, 25]} df = pd.DataFrame(data) ``` #### 绘制柱状图并添加折线图 接着,在同一坐标轴对象上调用两次绘图方法——一次用来柱子,另一次则用来描绘线条。这里需要注意的是要确保两个不同类型的图表共享相同的X轴以便于比较两者之间的关系[^1]。 ```python import matplotlib.pyplot as plt fig, ax1 = plt.subplots() # 绘制柱状图 ax1.bar(df['Category'], df['Values'], color="skyblue", label='Bar Chart') ax1.set_ylabel('Bar Values') # 添加第二个Y轴给折线图 ax2 = ax1.twinx() ax2.plot(df['Category'], df['LineData'], marker='o', linestyle='-', color="orange", linewidth=2, label='Line Plot') ax2.set_ylabel('Line Data') plt.title("Combination of Bar and Line Charts") lines_labels = [ax.get_lines()[0] for ax in fig.axes] labels = [line.get_label() for line in lines_labels] fig.legend(lines_labels, labels, loc='upper right') plt.show() ``` 这段代码实现了如下效果: - 使用 `twinx()` 方法为折线图创建了一个新的y轴。 - 对同一个 x 轴上的两组 y 数据分别进行了可视化处理;一组作为直方条形表示,另一组则是连续变化的趋势曲线形式呈现出来。 - 图例被统一放置到了右上方位置,并且只包含了实际存在的两类元素标签[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值