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()