Files
WQ_GUI/box_plot.py
2025-12-05 10:31:03 +08:00

327 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import os
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
def plot_individual_boxplots(csv_file_path, save_dir="boxplots"):
"""
为每个数据列单独绘制箱型图并保存
参数:
csv_file_path: CSV文件路径
save_dir: 保存图片的目录
"""
try:
# 读取CSV文件
df = pd.read_csv(csv_file_path)
# 获取第五列之后的数据列索引从0开始第五列索引为4
data_columns = df.iloc[:, 4:]
# 检查是否有数据列
if data_columns.empty:
print("错误CSV文件中没有足够的列至少需要5列")
return
# 创建保存目录
if not os.path.exists(save_dir):
os.makedirs(save_dir)
print(f"创建目录: {save_dir}")
# 为每个数据列单独绘制箱型图
for column in data_columns.columns:
# 移除空值
clean_data = data_columns[column].dropna()
if len(clean_data) == 0:
print(f"跳过列 '{column}': 没有有效数据")
continue
# 创建新图形
plt.figure(figsize=(8, 6))
# 绘制箱型图
box_plot = plt.boxplot([clean_data], labels=[column], patch_artist=True,
showfliers=False)
# 美化箱型图
box_plot['boxes'][0].set_facecolor('lightblue')
box_plot['boxes'][0].set_alpha(0.7)
# 添加散点
x_pos = np.random.normal(1, 0.04, size=len(clean_data))
plt.scatter(x_pos, clean_data, alpha=0.6, s=30, color='red',
edgecolors='black', linewidth=0.5, zorder=3)
# 设置标题和标签
plt.title(f'{column} - 箱型图', fontsize=14, fontweight='bold')
plt.xlabel('数据列', fontsize=12)
plt.ylabel('数值', fontsize=12)
# 添加统计信息到图上
stats_text = f'数据点数: {len(clean_data)}\n均值: {clean_data.mean():.2f}\n中位数: {clean_data.median():.2f}\n标准差: {clean_data.std():.2f}'
plt.text(0.02, 0.98, stats_text, transform=plt.gca().transAxes,
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8))
# 添加网格
plt.grid(True, alpha=0.3, linestyle='--')
# 调整布局
plt.tight_layout()
# 保存图片
safe_column_name = column.replace('/', '_').replace('\\', '_').replace(':', '_')
save_path = os.path.join(save_dir, f'{safe_column_name}_boxplot.png')
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"已保存: {save_path}")
# 关闭图形以释放内存
plt.close()
print(f"\n所有箱型图已保存到目录: {save_dir}")
except FileNotFoundError:
print(f"错误:找不到文件 {csv_file_path}")
except Exception as e:
print(f"错误:{str(e)}")
def plot_individual_boxplots_seaborn(csv_file_path, save_dir="boxplots_seaborn"):
"""
使用seaborn为每个数据列单独绘制箱型图并保存
参数:
csv_file_path: CSV文件路径
save_dir: 保存图片的目录
"""
try:
# 读取CSV文件
df = pd.read_csv(csv_file_path)
# 获取第五列之后的数据列
data_columns = df.iloc[:, 4:]
if data_columns.empty:
print("错误CSV文件中没有足够的列至少需要5列")
return
# 创建保存目录
if not os.path.exists(save_dir):
os.makedirs(save_dir)
print(f"创建目录: {save_dir}")
# 为每个数据列单独绘制箱型图
for column in data_columns.columns:
# 移除空值
clean_data = data_columns[column].dropna()
if len(clean_data) == 0:
print(f"跳过列 '{column}': 没有有效数据")
continue
# 创建新图形
plt.figure(figsize=(8, 6))
# 创建数据框用于seaborn
plot_data = pd.DataFrame({
'列名': [column] * len(clean_data),
'数值': clean_data
})
# 使用seaborn绘制箱型图和散点
sns.boxplot(data=plot_data, x='列名', y='数值', palette='Set2')
sns.stripplot(data=plot_data, x='列名', y='数值',
color='red', alpha=0.6, size=5, jitter=True)
# 设置标题和标签
plt.title(f'{column} - 箱型图 (Seaborn)', fontsize=14, fontweight='bold')
plt.xlabel('数据列', fontsize=12)
plt.ylabel('数值', fontsize=12)
# 添加统计信息
stats_text = f'数据点数: {len(clean_data)}\n均值: {clean_data.mean():.2f}\n中位数: {clean_data.median():.2f}\n标准差: {clean_data.std():.2f}'
plt.text(0.02, 0.98, stats_text, transform=plt.gca().transAxes,
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='lightgreen', alpha=0.8))
# 添加网格
plt.grid(True, alpha=0.3, linestyle='--')
# 调整布局
plt.tight_layout()
# 保存图片
safe_column_name = column.replace('/', '_').replace('\\', '_').replace(':', '_')
save_path = os.path.join(save_dir, f'{safe_column_name}_boxplot_seaborn.png')
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"已保存: {save_path}")
# 关闭图形以释放内存
plt.close()
print(f"\n所有箱型图已保存到目录: {save_dir}")
except Exception as e:
print(f"错误:{str(e)}")
def plot_boxplot_with_scatter(csv_file_path):
"""
读取CSV文件并绘制第五列之后数据列的箱型图同时标注散点
参数:
csv_file_path: CSV文件路径
"""
try:
# 读取CSV文件
df = pd.read_csv(csv_file_path)
# 获取第五列之后的数据列索引从0开始第五列索引为4
data_columns = df.iloc[:, 4:] # 从第五列开始的所有列
# 检查是否有数据列
if data_columns.empty:
print("错误CSV文件中没有足够的列至少需要5列")
return
# 设置图形大小
plt.figure(figsize=(12, 8))
# 准备数据用于绘制箱型图
box_data = []
labels = []
for column in data_columns.columns:
# 移除空值
clean_data = data_columns[column].dropna()
if len(clean_data) > 0:
box_data.append(clean_data)
labels.append(column)
# 绘制箱型图
box_plot = plt.boxplot(box_data, labels=labels, patch_artist=True,
showfliers=False) # 不显示异常值点,因为我们要自己绘制散点
# 美化箱型图
colors = plt.cm.Set3(np.linspace(0, 1, len(box_data)))
for patch, color in zip(box_plot['boxes'], colors):
patch.set_facecolor(color)
patch.set_alpha(0.7)
# 在每个箱型图上添加散点
for i, data in enumerate(box_data):
# 为每个数据点添加一些随机的x轴偏移避免重叠
x_pos = np.random.normal(i + 1, 0.04, size=len(data))
# 绘制散点
plt.scatter(x_pos, data, alpha=0.6, s=20, color='red',
edgecolors='black', linewidth=0.5, zorder=3)
# 设置标题和标签
plt.title('数据列箱型图(带散点标注)', fontsize=16, fontweight='bold')
plt.xlabel('数据列', fontsize=12)
plt.ylabel('数值', fontsize=12)
# 旋转x轴标签以避免重叠
plt.xticks(rotation=45, ha='right')
# 添加网格
plt.grid(True, alpha=0.3, linestyle='--')
# 调整布局
plt.tight_layout()
# 显示图形
plt.show()
# 打印统计信息
print(f"成功绘制了 {len(labels)} 个数据列的箱型图")
print("数据列名称:", labels)
# 显示每列的基本统计信息
print("\n各列基本统计信息:")
for column in labels:
data = data_columns[column].dropna()
print(f"{column}: 数据点数={len(data)}, 均值={data.mean():.2f}, 中位数={data.median():.2f}")
except FileNotFoundError:
print(f"错误:找不到文件 {csv_file_path}")
except Exception as e:
print(f"错误:{str(e)}")
def plot_boxplot_with_seaborn(csv_file_path):
"""
使用seaborn绘制更美观的箱型图可选方法
参数:
csv_file_path: CSV文件路径
"""
try:
# 读取CSV文件
df = pd.read_csv(csv_file_path)
# 获取第五列之后的数据列
data_columns = df.iloc[:, 4:]
if data_columns.empty:
print("错误CSV文件中没有足够的列至少需要5列")
return
# 将数据转换为长格式用于seaborn
melted_data = pd.melt(data_columns, var_name='列名', value_name='数值')
melted_data = melted_data.dropna() # 移除空值
# 设置图形大小
plt.figure(figsize=(12, 8))
# 使用seaborn绘制箱型图和散点
sns.boxplot(data=melted_data, x='列名', y='数值', palette='Set3')
sns.stripplot(data=melted_data, x='列名', y='数值',
color='red', alpha=0.6, size=4, jitter=True)
# 设置标题和标签
plt.title('数据列箱型图Seaborn版本', fontsize=16, fontweight='bold')
plt.xlabel('数据列', fontsize=12)
plt.ylabel('数值', fontsize=12)
# 旋转x轴标签
plt.xticks(rotation=45, ha='right')
# 添加网格
plt.grid(True, alpha=0.3, linestyle='--')
# 调整布局
plt.tight_layout()
# 显示图形
plt.show()
except Exception as e:
print(f"错误:{str(e)}")
# 主程序
if __name__ == "__main__":
# 请修改为您的CSV文件路径
csv_file_path = r"E:\code\WQ\yaobao925\output.csv" # 替换为您的CSV文件路径
print("请选择绘图方法:")
print("1. 使用matplotlib绘制所有列在一张图")
print("2. 使用seaborn绘制所有列在一张图")
print("3. 分别绘制每列并保存matplotlib版本")
print("4. 分别绘制每列并保存seaborn版本")
choice = input("请输入选择1-4").strip()
if choice == "1":
plot_boxplot_with_scatter(csv_file_path)
elif choice == "2":
plot_boxplot_with_seaborn(csv_file_path)
elif choice == "3":
plot_individual_boxplots(csv_file_path)
elif choice == "4":
plot_individual_boxplots_seaborn(csv_file_path)
else:
print("默认使用分别绘制并保存seaborn版本...")
plot_individual_boxplots_seaborn(csv_file_path)