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

184 lines
7.5 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 numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from pathlib import Path
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
def load_and_plot_spectrum_by_parameters():
"""
加载数据并为每个水质参数绘制光谱曲线图
"""
try:
# 数据文件路径
data_file = Path(r"E:\code\WQ\yaobao925\spectral.csv")
if not data_file.exists():
print(f"错误:数据文件不存在 - {data_file}")
return
# 读取数据
print("正在加载数据...")
data = pd.read_csv(data_file)
print(f"数据形状: {data.shape}")
print(f"列名: {list(data.columns[:15])}...") # 显示前15个列名
# 找到光谱数据的起始列(通常是数字列名)
spectrum_start_idx = None
for i, col in enumerate(data.columns):
try:
float(col)
spectrum_start_idx = i
break
except ValueError:
continue
if spectrum_start_idx is None:
print("错误:未找到光谱数据列")
return
print(f"光谱数据从第 {spectrum_start_idx + 1} 列开始")
# 分离水质参数和光谱数据
water_quality_data = data.iloc[:, :spectrum_start_idx]
spectrum_data = data.iloc[:, spectrum_start_idx:]
# 获取波长信息
try:
# 尝试直接转换为浮点数
wavelengths = spectrum_data.columns.astype(float)
except ValueError:
# 如果包含字母,提取数字部分
import re
wavelengths = []
for col in spectrum_data.columns:
# 提取数字部分
numbers = re.findall(r'\d+\.?\d*', str(col))
if numbers:
wavelengths.append(float(numbers[0]))
else:
# 如果没有数字,使用列索引
wavelengths.append(float(len(wavelengths)))
wavelengths = np.array(wavelengths)
print(f"波长范围: {wavelengths.min():.1f} - {wavelengths.max():.1f} nm")
print(f"光谱数据形状: {spectrum_data.shape}")
print(f"水质参数: {list(water_quality_data.columns)}")
# 过滤波长范围到374-1011nm
wavelength_mask = (wavelengths >= 374) & (wavelengths <= 1011)
filtered_wavelengths = wavelengths[wavelength_mask]
filtered_spectrum_data = spectrum_data.iloc[:, wavelength_mask]
print(f"过滤后波长范围: {filtered_wavelengths.min():.1f} - {filtered_wavelengths.max():.1f} nm")
print(f"过滤后光谱数据形状: {filtered_spectrum_data.shape}")
# 创建输出目录
output_dir = Path(r'E:\code\WQ\yaobao925\plot')
output_dir.mkdir(exist_ok=True)
# 为每个水质参数绘制光谱图
for param_idx, parameter_name in enumerate(water_quality_data.columns):
print(f"\n[{param_idx+1}/{len(water_quality_data.columns)}] 处理参数: {parameter_name}")
# 获取当前参数的数据
parameter_values = water_quality_data[parameter_name]
# 过滤掉空值
valid_mask = ~parameter_values.isna()
if valid_mask.sum() == 0:
print(f"参数 '{parameter_name}' 没有有效数据,跳过")
continue
valid_param_values = parameter_values[valid_mask]
valid_spectrum_data = filtered_spectrum_data[valid_mask]
print(f"有效样本数: {len(valid_param_values)}")
# 创建图形和轴
fig, ax = plt.subplots(figsize=(12, 8))
# 归一化参数值到[0,1]范围,用于颜色映射
param_min = valid_param_values.min()
param_max = valid_param_values.max()
if param_max == param_min:
# 如果所有值相同,使用中等颜色
normalized_values = np.full(len(valid_param_values), 0.5)
else:
normalized_values = ((valid_param_values - param_min) / (param_max - param_min)).values
# 创建蓝红颜色映射(蓝色到红色)
colormap = plt.cm.coolwarm # 蓝色(低值)到红色(高值)
# 绘制每条光谱曲线
for i, (idx, spectrum) in enumerate(valid_spectrum_data.iterrows()):
# 处理光谱数据中的空值
spectrum_values = pd.Series(spectrum.values).fillna(0).values
# 根据参数值确定颜色
color = colormap(normalized_values[i])
alpha = 0.6 if len(valid_param_values) > 50 else 0.8 # 样本多时降低透明度
ax.plot(filtered_wavelengths, spectrum_values, color=color, alpha=alpha, linewidth=0.8)
# 设置图形属性
ax.set_xlabel('波长 (nm)', fontsize=12)
ax.set_ylabel('光谱强度', fontsize=12)
ax.set_title(f'{parameter_name} 光谱曲线图\n参数范围: {param_min:.4f} - {param_max:.4f}',
fontsize=14, fontweight='bold')
# 设置坐标轴范围限制在374-1011nm
ax.set_xlim(374, 1011)
# 添加网格
ax.grid(True, alpha=0.3)
# 创建颜色条
sm = plt.cm.ScalarMappable(cmap=colormap,
norm=plt.Normalize(vmin=param_min, vmax=param_max))
sm.set_array([])
cbar = plt.colorbar(sm, ax=ax, shrink=0.8)
cbar.set_label(f'{parameter_name} 数值', rotation=270, labelpad=20, fontsize=12)
# 添加统计信息文本框
stats_text = f'样本数: {len(valid_param_values)}\n'
stats_text += f'均值: {valid_param_values.mean():.4f}\n'
stats_text += f'标准差: {valid_param_values.std():.4f}'
ax.text(0.02, 0.98, stats_text, transform=ax.transAxes,
verticalalignment='top', bbox=dict(boxstyle='round',
facecolor='wheat', alpha=0.8), fontsize=10)
# 优化布局
plt.tight_layout()
# 保存图片
# 清理参数名称,用于文件名
safe_param_name = "".join(c for c in parameter_name if c.isalnum() or c in ('-', '_', '.')).rstrip()
output_file = output_dir / f"{safe_param_name}_spectrum.png"
plt.savefig(output_file, dpi=300, bbox_inches='tight')
plt.close() # 关闭图形释放内存
print(f"图片已保存到: {output_file}")
print(f"\n{'='*80}")
print(f"所有光谱图绘制完成!")
print(f"输出目录: {output_dir}")
print(f"{'='*80}")
except Exception as e:
print(f"处理过程中出现错误: {str(e)}")
import traceback
traceback.print_exc()
def main():
"""主函数"""
load_and_plot_spectrum_by_parameters()
if __name__ == "__main__":
main()