Python脚本开发文件初始化
This commit is contained in:
9
tempReportProcess/.gitignore
vendored
Normal file
9
tempReportProcess/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/build/*
|
||||
/build
|
||||
/dist/*
|
||||
/dist
|
||||
/source/*
|
||||
/source
|
||||
|
||||
|
||||
tempReportProcess_V2.py
|
||||
248
tempReportProcess/tempReportProcess_V1.py
Normal file
248
tempReportProcess/tempReportProcess_V1.py
Normal file
@@ -0,0 +1,248 @@
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
from datetime import datetime
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog
|
||||
import os
|
||||
import matplotlib.dates as mdates
|
||||
from jinja2 import Template
|
||||
from matplotlib import font_manager, rcParams
|
||||
|
||||
|
||||
class TemperatureDataAnalyzer:
|
||||
def __init__(self):
|
||||
self.data = None
|
||||
self.file_path = None
|
||||
self.timestamps = []
|
||||
self.temperatures = []
|
||||
self.statuses = []
|
||||
self._configure_chinese_font() # 配置中文字体,修复中文字符缺失警告
|
||||
|
||||
def _configure_chinese_font(self):
|
||||
"""
|
||||
配置 Matplotlib 中文字体,避免中文字符缺失的警告。
|
||||
会尝试常见的中文字体并设置 axes.unicode_minus 为 False。
|
||||
"""
|
||||
try:
|
||||
# 常见中文字体候选(跨平台)
|
||||
candidates = [
|
||||
"Microsoft YaHei", "Microsoft YaHei UI", # Windows
|
||||
"SimHei", "SimSun", # Windows(黑体/宋体)
|
||||
"PingFang SC", "Heiti SC", # macOS
|
||||
"Noto Sans CJK SC", "Source Han Sans SC", "WenQuanYi Micro Hei", # Linux
|
||||
"Arial Unicode MS" # 覆盖广的 Unicode 字体
|
||||
]
|
||||
available = {f.name for f in font_manager.fontManager.ttflist}
|
||||
for name in candidates:
|
||||
if name in available:
|
||||
rcParams["font.sans-serif"] = [name]
|
||||
rcParams["axes.unicode_minus"] = False
|
||||
# 可选:打印使用的字体名称
|
||||
# print(f"使用中文字体: {name}")
|
||||
return
|
||||
# 如果没有找到常见中文字体,给出提示
|
||||
rcParams["axes.unicode_minus"] = False
|
||||
print("未检测到常见中文字体,图中中文可能无法正常显示。建议安装 'Noto Sans CJK SC' 或 'Microsoft YaHei'。")
|
||||
except Exception as e:
|
||||
print(f"中文字体配置失败: {e}")
|
||||
|
||||
def select_file(self):
|
||||
"""手动选择CSV文件"""
|
||||
root = tk.Tk()
|
||||
root.withdraw() # 隐藏主窗口
|
||||
|
||||
file_types = [("CSV files", "*.csv"), ("All files", "*.*")]
|
||||
self.file_path = filedialog.askopenfilename(title="选择温度数据CSV文件", filetypes=file_types)
|
||||
|
||||
if not self.file_path:
|
||||
print("未选择文件,程序退出")
|
||||
return False
|
||||
return True
|
||||
|
||||
def load_and_process_data(self):
|
||||
"""加载和处理数据"""
|
||||
try:
|
||||
# 读取CSV文件,无表头
|
||||
self.data = pd.read_csv(self.file_path, header=None)
|
||||
|
||||
# 重命名列以便于引用
|
||||
self.data.columns = ['timestamp', 'temperature', 'status']
|
||||
|
||||
# 转换时间戳格式(文本例如:10/29/2025 2:20:41 PM)
|
||||
self.data['datetime'] = pd.to_datetime(self.data['timestamp'], format='%m/%d/%Y %I:%M:%S %p')
|
||||
|
||||
# 提取处理后的数据
|
||||
self.timestamps = self.data['datetime']
|
||||
self.temperatures = self.data['temperature']
|
||||
self.statuses = self.data['status']
|
||||
|
||||
print(f"成功加载 {len(self.data)} 条记录")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"数据处理错误: {e}")
|
||||
return False
|
||||
|
||||
def create_scatter_plots(self):
|
||||
"""创建散点图"""
|
||||
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))
|
||||
|
||||
# 温度散点图
|
||||
sc1 = ax1.scatter(self.timestamps, self.temperatures, c=self.temperatures,
|
||||
cmap='coolwarm', alpha=0.7, s=20)
|
||||
ax1.set_title('温度随时间变化趋势')
|
||||
ax1.set_ylabel('温度 (°C)')
|
||||
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
|
||||
ax1.grid(True, linestyle='--', alpha=0.7)
|
||||
ax1.tick_params(axis='x', rotation=45)
|
||||
plt.colorbar(sc1, ax=ax1, label="温度(°C)")
|
||||
|
||||
# 状态散点图
|
||||
sc2 = ax2.scatter(self.timestamps, self.statuses, c=self.statuses,
|
||||
cmap='viridis', alpha=0.7, s=20)
|
||||
ax2.set_title('状态随时间变化')
|
||||
ax2.set_xlabel('时间')
|
||||
ax2.set_ylabel('状态值')
|
||||
ax2.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
|
||||
ax2.grid(True, linestyle='--', alpha=0.7)
|
||||
ax2.tick_params(axis='x', rotation=45)
|
||||
plt.colorbar(sc2, ax=ax2, label="状态值")
|
||||
|
||||
plt.tight_layout()
|
||||
return fig
|
||||
|
||||
def generate_statistics_report(self):
|
||||
"""生成统计报告"""
|
||||
stats = {
|
||||
'total_records': len(self.temperatures),
|
||||
'avg_temperature': round(self.temperatures.mean(), 2),
|
||||
'max_temperature': round(self.temperatures.max(), 2),
|
||||
'min_temperature': round(self.temperatures.min(), 2),
|
||||
'std_deviation': round(self.temperatures.std(), 2),
|
||||
'temp_range': round(self.temperatures.max() - self.temperatures.min(), 2),
|
||||
'start_time': self.timestamps.iloc[0].strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'end_time': self.timestamps.iloc[-1].strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'duration_hours': round((self.timestamps.iloc[-1] - self.timestamps.iloc[0]).total_seconds() / 3600, 2)
|
||||
}
|
||||
|
||||
# 状态分布统计
|
||||
status_counts = self.statuses.value_counts().to_dict()
|
||||
stats['status_distribution'] = status_counts
|
||||
|
||||
return stats
|
||||
|
||||
def save_fig_to_html(self, fig, output_path):
|
||||
"""将图形保存为HTML"""
|
||||
import io
|
||||
import base64
|
||||
|
||||
# 将图形转换为base64编码
|
||||
buf = io.BytesIO()
|
||||
fig.savefig(buf, format='png', dpi=150, bbox_inches='tight')
|
||||
buf.seek(0)
|
||||
img_str = base64.b64encode(buf.read()).decode('utf-8')
|
||||
buf.close()
|
||||
|
||||
# HTML模板(修复了多余的 '}')
|
||||
html_template = """
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>温度数据分析报告</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
.header { background-color: #f0f0f0; padding: 15px; border-radius: 5px; }
|
||||
.section { margin-bottom: 30px; }
|
||||
.stats-table { width: 100%; border-collapse: collapse; }
|
||||
.stats-table th, .stats-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
||||
.stats-table th { background-color: #f2f2f2; }
|
||||
.image-container { text-align: center; margin: 20px 0; }
|
||||
h1, h2 { color: #333; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>温度数据分析报告</h1>
|
||||
<p><strong>数据文件:</strong> {{ file_name }}</p>
|
||||
<p><strong>生成时间:</strong> {{ generation_time }}</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>数据概览</h2>
|
||||
<table class="stats-table">
|
||||
<tr><th>项目</th><th>数值</th></tr>
|
||||
{% for key, value in statistics.items() %}
|
||||
{% if key != 'status_distribution' %}
|
||||
<tr><td>{{ key.replace('_', ' ').title() }}</td><td>{{ value }}</td></tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>状态分布</h2>
|
||||
<table class="stats-table">
|
||||
<tr><th>状态值</th><th>出现次数</th></tr>
|
||||
{% for status, count in statistics.status_distribution.items() %}
|
||||
<tr><td>{{ status }}</td><td>{{ count }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>温度与状态时序图</h2>
|
||||
<div class="image-container">
|
||||
<img src="data:image/png;base64,{{ image_data }}" alt="温度与状态时序图">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
template = Template(html_template)
|
||||
rendered_html = template.render(
|
||||
file_name=self.file_path,
|
||||
generation_time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
statistics=self.generate_statistics_report(),
|
||||
image_data=img_str
|
||||
)
|
||||
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write(rendered_html)
|
||||
|
||||
def run_analysis(self):
|
||||
"""运行完整分析流程"""
|
||||
if not self.select_file():
|
||||
return
|
||||
|
||||
if not self.load_and_process_data():
|
||||
return
|
||||
|
||||
# 创建图形
|
||||
fig = self.create_scatter_plots()
|
||||
|
||||
# 生成输出文件名(保存到选择的文件所在文件夹)
|
||||
base_filename = os.path.splitext(os.path.basename(self.file_path))[0]
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
output_filename = f"{base_filename}_{timestamp}.html"
|
||||
output_dir = os.path.dirname(self.file_path)
|
||||
output_path = os.path.join(output_dir, output_filename)
|
||||
|
||||
# 保存HTML报告到同一文件夹
|
||||
self.save_fig_to_html(fig, output_path)
|
||||
|
||||
print(f"分析完成!报告已保存至: {output_path}")
|
||||
|
||||
# 显示统计摘要
|
||||
stats = self.generate_statistics_report()
|
||||
print("\n=== 数据统计摘要 ===")
|
||||
for key, value in stats.items():
|
||||
if key != 'status_distribution':
|
||||
print(f"{key.replace('_', ' ').title()}: {value}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
analyzer = TemperatureDataAnalyzer()
|
||||
analyzer.run_analysis()
|
||||
Reference in New Issue
Block a user