基于以下代码修改,为什么已经明确要求识别到的行索引为DataName,但还是老识别到DataName的后几行去了,不要识别到行名为DataValue,只识别DataName,并抓取和DataName同一行且名称为Vg列、Id、Ib、Ig和Is列(都是浮点数)这五列数据做后续处理
import os
import pandas as pd
import matplotlib.pyplot as plt
from pptx import Presentation
from pptx.util import Pt, Inches
import re
from io import BytesIO
import logging
import chardet
# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def process_csv_to_ppt(folder_path, output_pptx):
"""
处理文件夹中的所有CSV文件,生成包含图表的PPT
:param folder_path: CSV文件所在文件夹路径
:param output_pptx: 输出的PPT文件路径
:return: 处理是否成功
"""
# 初始化PPT对象
prs = Presentation()
# 获取所有CSV文件
csv_files = [f for f in os.listdir(folder_path) if f.lower().endswith('.csv')]
if not csv_files:
logging.error(f"在目录 {folder_path} 中没有找到CSV文件")
return False
logging.info(f"找到 {len(csv_files)} 个CSV文件")
# 处理每个CSV文件
for file in csv_files:
file_path = os.path.join(folder_path, file)
file_base = os.path.splitext(file)[0] # 获取不带扩展名的文件名
logging.info(f"正在处理文件: {file}")
try:
# 步骤1: 查找包含"DataName"的行索引
header_row = find_dataname_row(file_path)
if header_row is None:
logging.warning(f" 跳过文件 {file}: 未找到'DataName'行")
continue
# 步骤2: 读取数据并提取所需列
df = read_csv_data(file_path, header_row)
if df is None or df.empty:
logging.warning(f" 文件 {file} 中没有有效数据")
continue
# 步骤3: 创建四个图表图像
images = create_plots(df, file_base)
if not images or len(images) != 4:
logging.warning(f" 无法为 {file} 创建4个图表")
continue
# 步骤4: 添加到PPT页面
add_slide_to_ppt(prs, images, file_base)
logging.info(f" 成功添加 {file} 到PPT")
except Exception as e:
logging.error(f" 处理文件 {file} 时出错: {str(e)}")
# 保存PPT文件
prs.save(output_pptx)
logging.info(f"已生成PPT文件: {output_pptx}")
return True
def find_dataname_row(file_path):
"""
查找包含'DataName'的行索引
:param file_path: CSV文件路径
:return: 找到的行索引(1-based),如果未找到返回None
"""
try:
# 检测文件编码
with open(file_path, 'rb') as f:
raw_data = f.read(10000)
result = chardet.detect(raw_data)
encoding = result['encoding'] if result['confidence'] > 0.7 else 'utf-8'
# 读取文件内容
with open(file_path, 'r', encoding=encoding, errors='replace') as f:
lines = []
for i, line in enumerate(f):
if i >= 1000: # 最多检查200行
break
lines.append(line.strip())
# 扫描寻找"DataName"行
for row_idx, line in enumerate(lines, 1): # 1-based索引
if "DataName" in line:
return row_idx
# 尝试不同大小写
for row_idx, line in enumerate(lines, 1):
if "dataname" in line.lower():
return row_idx
return None
except Exception as e:
logging.error(f" 查找'DataName'行出错: {str(e)}")
return None
def read_csv_data(file_path, header_row):
"""
从CSV文件中读取数据,从DataName行开始
:param file_path: CSV文件路径
:param header_row: 'DataName'所在的行索引(1-based)
:return: 包含所需列的DataFrame对象
"""
try:
# 检测文件编码
with open(file_path, 'rb') as f:
raw_data = f.read(100000)
result = chardet.detect(raw_data)
encoding = result['encoding'] if result['confidence'] > 0.7 else 'utf-8'
# 读取CSV文件,跳过DataName行之前的所有行
df = pd.read_csv(
file_path,
header=header_row - 1, # pandas使用0-based索引
encoding=encoding,
engine='python',
on_bad_lines='skip'
)
# 标准化列名:移除特殊字符并转为小写
df.columns = [clean_column_name(col) for col in df.columns]
# 检查所需列是否存在
required_cols = ['vg', 'id', 'ib', 'ig', 'is']
missing_cols = [col for col in required_cols if col not in df.columns]
if missing_cols:
logging.warning(f" 缺少列: {', '.join(missing_cols)}")
logging.info(f" 实际列名: {df.columns.tolist()}")
return None
# 提取所需列并转换为数值类型
df = df[required_cols].copy()
for col in df.columns:
df[col] = pd.to_numeric(df[col], errors='coerce')
# 移除空值和无效行
df.dropna(inplace=True)
# 移除全零行
df = df[(df[required_cols] != 0).any(axis=1)]
# 检查是否有足够的数据点
if len(df) < 3:
logging.warning(f" 有效数据点不足 ({len(df)})")
return None
return df
except Exception as e:
logging.error(f" 读取数据出错: {str(e)}")
return None
def clean_column_name(col):
"""
清理列名:移除非字母数字字符并转为小写
:param col: 原始列名
:return: 清理后的列名
"""
col_str = str(col).strip().lower()
# 移除非字母数字字符(保留下划线)
col_str = re.sub(r'[^a-z0-9_]', '', col_str)
# 移除连续的下划线
col_str = re.sub(r'_+', '_', col_str)
return col_str
def create_plots(df, title_prefix):
"""
为数据创建Vg vs Id、Ib、Ig、Is四个图表
:param df: 包含数据的DataFrame
:param title_prefix: 图表标题前缀(文件名)
:return: 四个图表图像的BytesIO对象列表
"""
images = []
params = ['id', 'ib', 'ig', 'is'] # 需要绘图的四个参数
for param in params:
try:
# 创建图表
fig, ax = plt.subplots(figsize=(8, 5))
# 绘制数据:Vg为X轴,当前参数为Y轴
ax.plot(df['vg'], df[param], 'b-', linewidth=1.5,
marker='o', markersize=4, label=f'{param.upper()} vs Vg')
# 设置图表样式
ax.set_xlabel('Vg (V)', fontsize=12)
ax.set_ylabel(f'{param.upper()} (A)', fontsize=12)
ax.set_title(f'{title_prefix} - {param.upper()} vs Vg', fontsize=14)
ax.grid(True, linestyle='--', alpha=0.6)
ax.legend(loc='best')
# 自动调整Y轴范围
y_min = df[param].min()
y_max = df[param].max()
# 处理全零或单值情况
if y_min == y_max:
if y_min == 0:
ax.set_ylim(-0.1, 0.1)
else:
ax.set_ylim(y_min * 0.9, y_min * 1.1)
else:
margin = (y_max - y_min) * 0.05
ax.set_ylim(y_min - margin, y_max + margin)
# 科学计数法格式化(对于极小数或极大数)
if abs(y_min) < 0.001 or abs(y_max) > 1000:
ax.ticklabel_format(axis='y', style='sci', scilimits=(-3, 3))
# 保存到内存中的字节流
img_bytes = BytesIO()
plt.savefig(img_bytes, format='png', dpi=150, bbox_inches='tight')
img_bytes.seek(0) # 重置指针位置
images.append(img_bytes)
# 清理图表资源
plt.close(fig)
except Exception as e:
logging.error(f" 创建 {param} 图表失败: {str(e)}")
images.append(BytesIO()) # 添加空对象保持位置
plt.close('all') # 确保清理所有图表资源
return images
def add_slide_to_ppt(prs, images, title_text):
"""
将四个图表添加到PPT的一页
:param prs: Presentation对象
:param images: 四个图表图像的BytesIO对象
:param title_text: 幻灯片标题(文件名)
"""
# 添加空白幻灯片
slide = prs.slides.add_slide(prs.slide_layouts[6]) # 使用空白布局
# 添加标题
title = slide.shapes.add_textbox(Inches(0.5), Inches(0.25), Inches(9), Inches(0.5))
title_frame = title.text_frame
p = title_frame.add_paragraph()
p.text = title_text # 使用文件名作为标题
p.font.bold = True
p.font.size = Pt(24)
p.alignment = 1 # 居中
# 定义四个图表的位置 (2x2网格)
positions = [
(Inches(0.5), Inches(1.0)), # 左上
(Inches(5.0), Inches(1.0)), # 右上
(Inches(0.5), Inches(4.0)), # 左下
(Inches(5.0), Inches(4.0)) # 右下
]
# 添加图表到幻灯片
for idx, img in enumerate(images):
if img and img.getbuffer().nbytes > 0: # 检查图像是否有效
try:
slide.shapes.add_picture(
img, positions[idx][0], positions[idx][1],
width=Inches(4.5), height=Inches(3.0)
)
except Exception as e:
logging.error(f" 添加图像到PPT失败: {str(e)}")
else:
logging.warning(f" 图表 {idx + 1} 无效或为空")
if __name__ == "__main__":
# 配置路径
# folder_path = r"C:\Users\x00708\PycharmProjects\mission\practice_from_work_data\zyh-画图\wafer21_npg_425" # 替换为CSV文件夹路径
# output_pptx = r"C:\Users\x00708\PycharmProjects\mission\practice_from_work_data\zyh-画图\result_npg.pptx" # 输出PPT文件路径
folder_path = r"C:\Users\x00708\PycharmProjects\mission\practice_from_work_data\zyh-画图\11.4_425_wafer21" # 替换为CSV文件夹路径
output_pptx = r"C:\Users\x00708\PycharmProjects\mission\practice_from_work_data\zyh-画图\result_11.4.pptx" # 输出PPT文件路径
# 处理文件
success = process_csv_to_ppt(folder_path, output_pptx)
if success:
print(f"处理完成! PPT已保存至: {output_pptx}")
else:
print("处理过程中遇到问题,请检查日志输出")
最新发布