python快速绘制走势图对比曲线

一、功能概述

本工具专为实测高频、预测低频 的时序数据对比场景设计,可自动处理 4 组模型输出 Excel 文件,完成数据清洗、时间对齐与趋势可视化。工具能智能识别文件中「实测」「预测」两列数据,过滤空值、字符串等无效内容,解决数据长度不一致问题。基于1 秒实测、1 分钟预测的时间规律,将预测值按分钟精准填充到对应时间区间,实现两类数据完全对齐。

自动批量生成高清对比曲线图,采用蓝色细曲线展示实测高频细节,红色粗曲线突出预测整体趋势,界面简洁美观。支持隐藏拥挤的横轴刻度,保留网格、图例与标题,便于直观观察拟合效果。所有处理结果自动保存至原文件夹,包含对齐后的标准 Excel 数据表与高清趋势图,无需手动调整,一键完成从数据预处理到可视化输出全流程,高效稳定适配 Windows 环境与低版本 Python 库。

python 复制代码
# -*- coding: utf-8 -*-
import os
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import warnings
warnings.filterwarnings('ignore')

# ========== 全局配置 ==========
plt.rcParams['font.sans-serif'] = ['SimHei']  # 中文字体
plt.rcParams['axes.unicode_minus'] = False    # 负号正常显示
FOLDER_PATH = r'C:\Users\wayso\Desktop\ht'    # 文件所在路径
SAMPLING_RATIO = 60  # 1分钟=60秒(实测1秒/个,预测1分钟/个)

# ========== 工具函数:过滤非数值数据 ==========
def filter_numeric_data(series):
    """
    过滤Series中的非数值数据,仅保留数字(处理空字符串/空格/符号)
    :param series: 原始列数据
    :return: 仅包含数值的Series
    """
    # 步骤1:将空字符串、空格转为NaN
    series = series.replace(['', ' ', '-', '无', 'NaN'], np.nan)
    # 步骤2:尝试转换为数值型(无法转换的转为NaN)
    try:
        series = pd.to_numeric(series, errors='coerce')
    except:
        series = np.nan
    # 步骤3:过滤NaN,重置索引
    return series.dropna().reset_index(drop=True)

# ========== 核心函数:兼容低版本pandas的Excel读取 ==========
def read_excel_universal(file_path):
    """万能Excel读取函数(适配pandas<1.3.0)"""
    # 方案1:openpyxl引擎(优先读取.xlsx)
    try:
        return pd.read_excel(
            file_path,
            sheet_name='Sheet1',
            engine='openpyxl',
            header=0,        # 第一行作为列名
            na_filter=False  # 不自动过滤空值,避免解析错误
        )
    except Exception as e1:
        # 方案2:xlrd引擎(兼容旧版.xls/.xlsx)
        try:
            return pd.read_excel(
                file_path,
                sheet_name='Sheet1',
                engine='xlrd',
                header=0,
                na_filter=False
            )
        except Exception as e2:
            # 方案3:终极兜底(忽略列名,手动处理)
            try:
                df = pd.read_excel(
                    file_path,
                    sheet_name='Sheet1',
                    engine='openpyxl',
                    header=None  # 不指定列名,避免列名解析错误
                )
                # 手动设置列名(适配实测/预测列)
                if len(df.columns) >= 2:
                    df.columns = ['实测', '预测']  # 强制设置列名
                else:
                    print(f"⚠️ 文件{file_path}列数异常:{len(df.columns)}列")
                return df
            except Exception as e3:
                raise Exception(f"读取失败:{str(e3)}(openpyxl/xlrd均失败)")

# ========== 数据对齐函数(按时间维度) ==========
def align_data_by_time(actual_series, predict_series):
    """
    对齐实测(1秒)和预测(1分钟)数据:
    - 过滤非数值数据
    - 实测数据保留1秒粒度
    - 预测数据按分钟填充到对应60行
    """
    # 核心修复:过滤非数值数据(空字符串/符号/中文)
    actual_clean = filter_numeric_data(actual_series)
    predict_clean = filter_numeric_data(predict_series)
    
    # 检查过滤后是否有数据
    if len(actual_clean) == 0:
        raise Exception("实测列无有效数值数据")
    if len(predict_clean) == 0:
        raise Exception("预测列无有效数值数据")
    
    # 获取实测数据总长度(总秒数)
    total_seconds = len(actual_clean)
    # 初始化预测数据为NaN(浮点型,避免类型错误)
    predict_aligned = np.full(total_seconds, np.nan, dtype=np.float64)
    
    # 按分钟填充预测值(1个预测值对应60个实测值)
    for i in range(len(predict_clean)):
        start_pos = i * SAMPLING_RATIO
        if start_pos < total_seconds:
            end_pos = min((i+1)*SAMPLING_RATIO, total_seconds)
            # 确保赋值的是浮点数
            predict_value = float(predict_clean.iloc[i])
            predict_aligned[start_pos:end_pos] = predict_value
    
    # 实测数据对齐(保持原样,长度一致)
    actual_aligned = actual_clean.reindex(range(total_seconds))
    return actual_aligned, predict_aligned

# ========== 绘图函数(实测vs预测对比) ==========
def plot_comparison(actual, predict, file_name, save_path):
    """绘制高清对比走势图(隐藏横轴刻度)"""
    plt.figure(figsize=(15, 8))
    
    # 绘制实测曲线(蓝色细线条,体现1秒粒度细节)
    plt.plot(actual.index, actual.values, 'b-', label='实测值(1秒/个)', linewidth=0.8, alpha=0.8)
    # 绘制预测曲线(橙色粗线条,突出1分钟粒度趋势)
    plt.plot(predict.index, predict.values, 'r-', label='预测值(1分钟/个)', linewidth=2, alpha=0.9)
    
    # 图表美化
    plt.title(f'{file_name}\n实测(1秒粒度)vs 预测(1分钟粒度)对比', fontsize=16, pad=20)
    plt.xlabel('时间(秒)', fontsize=12)
    plt.ylabel('数值', fontsize=12)
    plt.legend(fontsize=12, loc='best')
    plt.grid(True, alpha=0.3, linestyle='--')
    
    # ========== 核心修改:隐藏横轴刻度和标签 ==========
    ax = plt.gca()  # 获取当前坐标轴对象
    ax.set_xticks([])  # 隐藏横轴刻度标签
    ax.xaxis.set_ticks_position('none')  # 隐藏横轴刻度线
    
    # 保存高清图片
    plt.tight_layout()  # 自适应布局,避免标签被截断
    plt.savefig(save_path, dpi=300, bbox_inches='tight')
    plt.close()
    print(f'✅ 对比图已保存:{save_path}')

# ========== 主程序:批量处理所有Excel文件 ==========
if __name__ == '__main__':
    # 遍历文件夹中的Excel文件(兼容.xlsx/.xls)
    file_list = [
        f for f in os.listdir(FOLDER_PATH) 
        if f.endswith(('.xlsx', '.xls')) and '创建时间' in f
    ]
    
    # 检查文件数量
    if not file_list:
        print('❌ 未找到目标Excel文件!请检查路径:', FOLDER_PATH)
    else:
        print(f'✅ 找到{len(file_list)}个目标文件,开始处理...\n')
    
    # 逐个处理文件
    for file_name in file_list:
        file_path = os.path.join(FOLDER_PATH, file_name)
        print(f'----------------------------------------')
        print(f'正在处理:{file_name}')
        
        # 1. 读取Excel文件(兼容低版本pandas)
        try:
            df = read_excel_universal(file_path)
        except Exception as e:
            print(f'❌ 读取文件失败:{e}')
            continue
        
        # 2. 检查并匹配「实测」「预测」列(兼容列名变体)
        actual_col, predict_col = None, None
        for col in df.columns:
            col_str = str(col).strip()  # 去除空格,兼容列名含空格的情况
            if '实测' in col_str:
                actual_col = col
            elif '预测' in col_str:
                predict_col = col
        
        if not actual_col or not predict_col:
            print(f'❌ 文件缺少「实测」或「预测」列,列名列表:{df.columns.tolist()}')
            continue
        
        # 3. 按时间维度对齐数据(包含非数值过滤)
        try:
            actual_aligned, predict_aligned = align_data_by_time(df[actual_col], df[predict_col])
        except Exception as e:
            print(f'❌ 数据对齐失败:{e}')
            continue
        
        # 4. 保存对齐后的数据(Excel)
        aligned_df = pd.DataFrame({
            '时间(秒)': range(len(actual_aligned)),
            '实测值': actual_aligned,
            '预测值': predict_aligned
        })
        excel_save_path = os.path.join(FOLDER_PATH, f'对齐后_{file_name}')
        aligned_df.to_excel(excel_save_path, index=False, engine='openpyxl')
        print(f'✅ 对齐后数据已保存:{excel_save_path}')
        
        # 5. 绘制并保存对比图
        img_save_path = os.path.join(FOLDER_PATH, f'{os.path.splitext(file_name)[0]}_对比图.png')
        try:
            plot_comparison(
                actual=pd.Series(actual_aligned),
                predict=pd.Series(predict_aligned),
                file_name=file_name,
                save_path=img_save_path
            )
        except Exception as e:
            print(f'❌ 绘图失败:{e}')
            continue
    
    # 处理完成提示
    print('\n========================================')
    print('🎉 所有文件处理完成!结果文件已保存到原文件夹。')

二、关键修改说明

表格

代码行 作用
ax = plt.gca() 获取当前图表的坐标轴对象,用于精细控制样式
ax.set_xticks([]) 清空横轴的刻度标签(比如 "0 分""1 分" 等文字)
ax.xaxis.set_ticks_position('none') 隐藏横轴的刻度线(底部的小短线)
注释掉原有plt.xticks代码 彻底移除原有的刻度生成逻辑,避免冲突

三、进阶可选:仅隐藏刻度线,保留 x 轴标签

如果你想保留 "时间(秒)" 这个 x 轴标题,只隐藏刻度(当前代码已保留标题);如果想连 x 轴标题也隐藏,只需添加:

python

运行

复制代码
ax.set_xlabel('')  # 隐藏x轴标题

总结

  1. 核心实现 :通过set_xticks([])set_ticks_position('none')完全隐藏横轴的刻度标签和刻度线;
  2. 视觉效果:图表仅保留曲线、图例、标题和 y 轴,整体更简洁美观,无横轴刻度干扰;
  3. 兼容性:修改仅针对绘图样式,不影响数据读取和对齐逻辑,原有功能完全保留。

运行修改后的代码,生成的对比图将不再显示横轴底部的任何刻度信息,完美满足你的美观需求。

相关推荐
寻寻觅觅☆5 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
YJlio5 小时前
1.7 通过 Sysinternals Live 在线运行工具:不下载也能用的“云端工具箱”
c语言·网络·python·数码相机·ios·django·iphone
l1t5 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
赶路人儿6 小时前
Jsoniter(java版本)使用介绍
java·开发语言
ceclar1236 小时前
C++使用format
开发语言·c++·算法
山塘小鱼儿6 小时前
本地Ollama+Agent+LangGraph+LangSmith运行
python·langchain·ollama·langgraph·langsimth
Gofarlic_OMS7 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
星空下的月光影子7 小时前
易语言开发从入门到精通:补充篇·网络爬虫与自动化采集分析系统深度实战·HTTP/HTTPS请求·HTML/JSON解析·反爬策略·电商价格监控·新闻资讯采集
开发语言