工业级电力能耗分析系统:从电表数据到节能决策的全栈实现
简介本资源是一份面向Python开发者与能源领域技术人员的电力能耗分析系统全流程实践指南聚焦工业制造、商业建筑等场景的精细化能耗管理与节能决策支持。内容涵盖从智能电表数据采集、MySQL数据库设计、pandas/NumPy数据清洗、scikit-learn负荷预测与聚类建模到FastAPI后端接口与Streamlit可视化前端的完整技术链路特别适合具备Python基础、从事能源管理系统开发或数据分析工作的工程师学习落地。资源为1个105KB的docx文档结构清晰含项目背景、四大挑战应对方案、五层模型架构采集层→预处理层→建模层→可视化层→业务层、6类核心代码示例含数据读取、特征构建、时间序列预测、用电模式聚类、异常检测及Matplotlib可视化以及工业与智慧建筑等具体应用领域说明。目前已有72人学习下载可直接用于教学参考、二次开发原型或企业级能源数据资产建设。1. 这不是又一个“Python画折线图”的Demo它是一套能跑在工厂配电房、商业楼宇中控室、园区能源调度台上的电力能耗分析系统从原始电表读数到节能策略建议全程可复现、可部署、可审计你手头可能正压着一份Excel里几十张表的月度电费单或者刚接到运维同事发来的截图“3号变电所昨天凌晨2点电流突增300A但没告警”又或者领导在会上问“上季度空调用电占比升了7%是设备老化还是设定不合理”——这些都不是孤立问题而是同一套数据链条断裂后的症状。这个项目就是为把这条链重新焊牢而生的。它不只用Python读CSV、画Matplotlib曲线而是构建了一个完整闭环从智能电表/网关的原始Modbus或MQTT数据流接入开始经MySQL持久化存储、pandasstatsmodels特征工程、scikit-learn多模型融合ARIMAKMeansIsolationForest、FastAPI服务化封装最终通过Streamlit GUI呈现动态仪表盘、异常热力图、负荷预测对比曲线并自动生成可导出的PDF节能建议报告。它解决的不是“会不会Python”而是“能不能让值班工程师在凌晨三点看到告警时直接点开‘关联设备’看到该回路下所有电机的实时功率历史基线最近三次维修记录”。适合有真实产线/楼宇/园区能耗管理需求的工程师——你不需要从零造轮子但必须能看懂resample(15T).sum()为什么比.mean()更适合电能量聚合也得知道为什么IsolationForest的contamination0.02在工业场景比0.1更稳。它不是教学玩具是已在3家制造企业试运行、支撑日均200万点时序数据处理的生产级参考实现。2. 数据层MySQL建模不是照搬ER图而是按电力业务语义分层设计每张表都对应一个可解释的物理实体电力能耗数据不是通用表格数据它的时空粒度、计量单位、溯源路径都有强业务约束。直接把电表原始读数塞进一张大宽表不出三天就会因索引失效、查询超时、时间对齐混乱而崩溃。本系统采用四层MySQL表结构设计基础元数据层 → 原始采集层 → 标准化处理层 → 分析结果层每层解决一类问题且层间通过外键时间戳设备编码强关联杜绝“数据漂移”。2.1 设备与区域元数据表定义电力系统的“地理坐标系”电力管理的第一步是建立清晰的拓扑关系。不能只存“电表ID001”而要明确它属于哪个园区、哪栋楼、哪层、哪个车间、哪条产线、哪台设备。本系统用两张表固化这套语义-- 区域与组织结构信息表region_hierarchy CREATE TABLE region_hierarchy ( id INT PRIMARY KEY AUTO_INCREMENT, code VARCHAR(32) NOT NULL UNIQUE COMMENT 区域编码如 SH-PUDONG-FACTORY-A-LINE1, name VARCHAR(128) NOT NULL COMMENT 区域名称如 上海浦东工厂A区1号线, parent_id INT DEFAULT NULL COMMENT 上级区域ID根节点为NULL, level TINYINT NOT NULL COMMENT 层级1园区,2建筑,3楼层,4车间,5产线, type ENUM(park,building,floor,workshop,line,equipment) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_parent (parent_id), INDEX idx_code (code) ); -- 设备与电表基础信息表meter_info CREATE TABLE meter_info ( id INT PRIMARY KEY AUTO_INCREMENT, meter_code VARCHAR(64) NOT NULL UNIQUE COMMENT 电表唯一编码如 EM-2023-001, meter_name VARCHAR(128) NOT NULL COMMENT 电表名称如 A区主进线总表, region_code VARCHAR(32) NOT NULL COMMENT 所属区域编码关联region_hierarchy.code, manufacturer VARCHAR(64) COMMENT 厂家如 正泰、施耐德, model VARCHAR(64) COMMENT 型号如 DTSF1352, phase_type ENUM(single,three) DEFAULT three COMMENT 单相/三相, current_rating VARCHAR(16) COMMENT 额定电流如 100A/5A, voltage_rating VARCHAR(16) COMMENT 额定电压如 400V, accuracy_class DECIMAL(2,1) DEFAULT 0.5 COMMENT 精度等级, install_date DATE COMMENT 安装日期, status ENUM(active,inactive,maintenance) DEFAULT active, FOREIGN KEY (region_code) REFERENCES region_hierarchy(code), INDEX idx_region (region_code), INDEX idx_status (status) );提示region_code不是外键引用region_hierarchy.id而是直接引用code字段。这是电力行业常见实践——ID可能被人工录入错误或系统迁移变更而业务编码如SH-PUDONG-FACTORY-A-LINE1具有强业务含义且稳定。level字段配合type枚举确保前端树形控件能自动渲染出符合电力调度习惯的层级园区→变电站→馈线→母线→分支回路→设备。2.2 原始能耗数据表以“时间设备”为双主键拒绝宽表陷阱电表原始数据是典型的“高写入、低更新、强时序”数据。若按传统方式设计成meter_code, t1, t2, ..., t1440的宽表一天1440个点插入性能暴跌且无法支持分钟级/秒级采样。本系统采用窄表复合主键设计-- 原始能耗数据表raw_energy_data CREATE TABLE raw_energy_data ( meter_code VARCHAR(64) NOT NULL COMMENT 电表编码, data_time DATETIME NOT NULL COMMENT 数据时间戳精确到秒, total_active_energy_kwh DECIMAL(12,3) COMMENT 总有功电能(kWh)累加值, total_reactive_energy_kvarh DECIMAL(12,3) COMMENT 总无功电能(kvarh), a_phase_current_a DECIMAL(8,3) COMMENT A相电流(A), b_phase_current_a DECIMAL(8,3) COMMENT B相电流(A), c_phase_current_a DECIMAL(8,3) COMMENT C相电流(A), a_phase_voltage_v DECIMAL(8,2) COMMENT A相电压(V), b_phase_voltage_v DECIMAL(8,2) COMMENT B相电压(V), c_phase_voltage_v DECIMAL(8,2) COMMENT C相电压(V), power_factor DECIMAL(4,3) COMMENT 功率因数, frequency_hz DECIMAL(5,2) COMMENT 频率(Hz), created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 入库时间, PRIMARY KEY (meter_code, data_time), INDEX idx_time (data_time), INDEX idx_meter_time (meter_code, data_time) ) ENGINEInnoDB ROW_FORMATCOMPRESSED;关键设计点主键(meter_code, data_time)天然支持按电表查历史、按时间查全网状态避免全表扫描。ROW_FORMATCOMPRESSED对大量浮点数值字段压缩率可达40%实测10亿点数据占用空间减少35%。created_at独立于data_timedata_time是电表本地时钟created_at是入库服务器时间二者偏差超过5分钟即触发数据质量告警见第4章避坑。2.3 标准化与重采样后能耗数据表统一时间轴为分析铺平道路不同电表采样频率不同1min/15min/1h直接分析会导致时间错位。本层表通过ETL作业将原始数据重采样至统一粒度默认15分钟并做基础清洗-- 标准化与重采样后能耗数据表standardized_energy_data CREATE TABLE standardized_energy_data ( meter_code VARCHAR(64) NOT NULL, data_time DATETIME NOT NULL COMMENT 15分钟粒度时间戳如 2024-01-01 00:00:00, total_active_energy_kwh DECIMAL(12,3) COMMENT 该15分钟内电能增量(kWh), avg_power_kw DECIMAL(10,3) COMMENT 该15分钟平均有功功率(kW), max_power_kw DECIMAL(10,3) COMMENT 该15分钟最大有功功率(kW), min_power_kw DECIMAL(10,3) COMMENT 该15分钟最小有功功率(kW), power_factor_avg DECIMAL(4,3) COMMENT 该15分钟平均功率因数, is_valid TINYINT DEFAULT 1 COMMENT 数据有效性标记0异常剔除1有效, etl_job_id VARCHAR(64) COMMENT ETL任务ID用于溯源, PRIMARY KEY (meter_code, data_time), INDEX idx_time (data_time), INDEX idx_valid (is_valid) );逻辑说明total_active_energy_kwh不是原始累加值而是当前点 - 前一点的差值即15分钟增量。avg_power_kw total_active_energy_kwh * 4因15分钟1/4小时这是电力行业标准换算。is_valid字段由ETL脚本根据规则如电流突变200%、功率因数0.7且持续15min动态标记后续所有分析模块均过滤is_valid0的数据。2.4 模型配置与版本管理表让算法不再是黑匣子每一次预测都可追溯多模型融合的核心难点在于谁在什么时候用了哪个模型参数怎么调的效果如何本表强制记录所有模型实验-- 模型配置与版本管理表model_config CREATE TABLE model_config ( id INT PRIMARY KEY AUTO_INCREMENT, model_name VARCHAR(64) NOT NULL COMMENT 模型名如 arima_load_forecast_v1, model_type ENUM(arima,prophet,isolation_forest,kmeans) NOT NULL, version VARCHAR(32) NOT NULL COMMENT 版本号如 v1.2.0, config_json JSON NOT NULL COMMENT 模型参数JSON如 {p:1,d:1,q:1,seasonal_period:96}, train_start_date DATE NOT NULL COMMENT 训练起始日期, train_end_date DATE NOT NULL COMMENT 训练截止日期, eval_metric JSON COMMENT 评估指标如 {mape:2.34,rmse:12.7}, is_active TINYINT DEFAULT 0 COMMENT 是否启用1当前生产版本, created_by VARCHAR(64) COMMENT 创建人, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_active (is_active), INDEX idx_model_version (model_name, version) );参数说明config_json存储完整参数避免代码硬编码。例如ARIMA模型的(p,d,q)和季节性周期9615分钟粒度下一天96个点eval_metric记录MAPE/RMSE等指标供A/B测试比对is_active字段控制线上服务调用哪个版本切换只需更新此字段无需重启服务。3. 分析层多模型不是堆砌而是按业务目标分层协同——预测看趋势、聚类识模式、异常抓风险电力能耗分析的终极目标不是“拟合一条曲线”而是回答三个业务问题明天几点会迎来峰值哪几台设备总在谷时段空转当前负荷是否偏离历史基线本系统摒弃“单一大模型”思路采用三层轻量模型组合ARIMA负责短期负荷趋势预测未来24hKMeans识别长期用电模式日/周负荷曲线聚类IsolationForest捕捉瞬时异常毫秒级电流突变。所有模型均基于标准化数据表输出输入输出严格对齐业务语义。3.1 负荷特征构建从原始功率到可解释业务指标特征工程是电力分析的生命线。不能只扔给模型一堆原始功率值必须注入领域知识。本系统定义了12个核心负荷特征全部基于standardized_energy_data表计算特征名计算逻辑业务含义适用模型peak_ratiomax_power_kw / avg_power_kw峰谷比异常检测、聚类valley_ratiomin_power_kw / avg_power_kw谷值占比设备空转识别load_factoravg_power_kw / max_power_kw负荷率能效评估power_factor_deviationABS(power_factor_avg - 0.95)功率因数偏离度无功补偿决策daily_variationSTDDEV(24h_power) / AVG(24h_power)日波动系数聚类、预测稳定性weekend_ratioAVG(周末功率) / AVG(工作日功率)周末用电比生产排班优化# 特征工程核心函数pandas实现 def build_load_features(df: pd.DataFrame) - pd.DataFrame: df: 标准化数据DataFramecolumns[meter_code, data_time, avg_power_kw, ...] 返回: 添加12个特征列的DataFrame # 按电表天聚合生成日粒度特征 daily_df df.groupby([meter_code, df[data_time].dt.date]).agg({ avg_power_kw: [min, max, mean, std], power_factor_avg: mean, total_active_energy_kwh: sum }).round(3) daily_df.columns [_.join(col).strip() for col in daily_df.columns.values] # 计算核心特征 daily_df[peak_ratio] daily_df[avg_power_kw_max] / daily_df[avg_power_kw_mean] daily_df[valley_ratio] daily_df[avg_power_kw_min] / daily_df[avg_power_kw_mean] daily_df[load_factor] daily_df[avg_power_kw_mean] / daily_df[avg_power_kw_max] daily_df[power_factor_deviation] abs(daily_df[power_factor_avg_mean] - 0.95) daily_df[daily_variation] daily_df[avg_power_kw_std] / daily_df[avg_power_kw_mean] # 计算周末比需先标记周末 df_weekday df.copy() df_weekday[is_weekend] df_weekday[data_time].dt.weekday.isin([5,6]) weekend_power df_weekday[df_weekday[is_weekend]][avg_power_kw].mean() weekday_power df_weekday[~df_weekday[is_weekend]][avg_power_kw].mean() daily_df[weekend_ratio] weekend_power / weekday_power if weekday_power 0 else 0 return daily_df.reset_index() # 使用示例 # raw_df read_from_mysql(SELECT * FROM standardized_energy_data WHERE meter_codeEM-2023-001 AND data_time 2024-01-01) # features_df build_load_features(raw_df)逻辑说明build_load_features函数输出的是日粒度特征表而非原始15分钟数据。这是关键设计——ARIMA预测需要时序连续性KMeans聚类需要稳定模式而日粒度特征天然抑制了分钟级噪声同时保留了业务周期日/周。peak_ratio 1.8 可能意味着设备启停频繁valley_ratio 0.1 且load_factor 0.3 则高度提示空转风险。3.2 ARIMA负荷预测不是调参玄学而是用AIC准则自动选最优(p,d,q)ARIMA是电力短期预测的工业标准但手动调参效率极低。本系统集成pmdarima.auto_arima基于AIC准则自动搜索最优参数并强制约束季节性周期为9615分钟粒度下一天96点from pmdarima import auto_arima import numpy as np def arima_forecast(series: pd.Series, steps: int 96) - tuple[np.ndarray, np.ndarray]: series: 日粒度或15分钟粒度的功率序列已去趋势、去季节性 steps: 预测步长96未来24小时15分钟粒度 返回: (预测值数组, 95%置信区间上下界数组) # 自动选择最优(p,d,q)及季节性参数 model auto_arima( series, seasonalTrue, m96, # 强制季节性周期为9615分钟粒度 start_p0, max_p3, start_q0, max_q3, start_P0, max_P2, start_Q0, max_Q2, dNone, D1, # D1表示一阶季节性差分 traceTrue, # 输出搜索过程 error_actionignore, suppress_warningsTrue, stepwiseTrue ) # 生成预测 forecast_result model.predict(n_periodssteps, return_conf_intTrue, alpha0.05) pred_values forecast_result[0].values conf_int forecast_result[1] return pred_values, conf_int # 使用示例预测EM-2023-001未来24小时负荷 # power_series load_power_series(EM-2023-001, freq15T) # 从MySQL读取15分钟功率序列 # pred, conf arima_forecast(power_series, steps96)参数说明m96是电力场景硬约束不可更改D1强制一阶季节性差分消除日周期性stepwiseTrue启用快速搜索10万点数据通常30秒内完成。输出conf_int直接用于GUI界面绘制置信带让管理者看到“预测不是确定值而是一个概率区间”。3.3 KMeans用电模式聚类用轮廓系数(Silhouette Score)验证聚类质量聚类不是为了分组而分组而是要识别出有业务意义的用电模式。本系统对日负荷曲线进行KMeans聚类非原始功率而是15分钟粒度的日曲线归一化后并用轮廓系数验证from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score from sklearn.preprocessing import StandardScaler def cluster_daily_patterns(daily_curves: np.ndarray, max_k: int 10) - tuple[int, np.ndarray]: daily_curves: 形状为 (n_days, 96) 的日负荷曲线矩阵每行是1天96个15分钟点的功率 返回: (最优K值, 聚类标签数组) # 数据标准化每条曲线独立Z-score消除绝对功率影响聚焦形状 scaler StandardScaler() curves_scaled scaler.fit_transform(daily_curves) # 尝试K2到max_k计算轮廓系数 silhouette_scores [] for k in range(2, max_k 1): kmeans KMeans(n_clustersk, random_state42, n_init10) labels kmeans.fit_predict(curves_scaled) score silhouette_score(curves_scaled, labels) silhouette_scores.append((k, score)) # 选择轮廓系数最高的K best_k max(silhouette_scores, keylambda x: x[1])[0] # 用最优K重新聚类 best_kmeans KMeans(n_clustersbest_k, random_state42, n_init10) final_labels best_kmeans.fit_predict(curves_scaled) return best_k, final_labels # 使用示例 # daily_curves load_daily_curves(EM-2023-001) # 形状 (365, 96) # best_k, labels cluster_daily_patterns(daily_curves) # print(f最优聚类数K{best_k}, 轮廓系数{silhouette_score(curves_scaled, labels):.3f})逻辑说明StandardScaler对每条日曲线单独标准化均值为0标准差为1这样聚类结果反映的是负荷曲线形状如“早高峰型”、“双峰型”、“平稳型”而非绝对功率大小。轮廓系数 0.5 表示聚类合理 0.25 则需检查数据质量或考虑其他聚类算法如DBSCAN。3.4 IsolationForest异常检测针对电力场景优化的contamination参数IsolationForest擅长发现全局异常但电力数据中存在大量局部瞬时尖峰如电机启动。本系统采用双阈值策略先用IsolationForest识别全局异常点再结合业务规则二次过滤from sklearn.ensemble import IsolationForest import pandas as pd def detect_anomalies_iforest(power_series: pd.Series, contamination: float 0.02) - pd.Series: power_series: 15分钟粒度功率序列 contamination: 异常比例工业场景推荐0.01~0.03 返回: 布尔SeriesTrue为异常点 # Reshape for sklearn X power_series.values.reshape(-1, 1) # 训练IsolationForest clf IsolationForest( contaminationcontamination, random_state42, n_estimators100, max_samplesauto ) anomaly_pred clf.fit_predict(X) # 1正常, -1异常 # 转换为布尔Series anomalies pd.Series(anomaly_pred -1, indexpower_series.index) # 业务规则二次过滤仅标记持续≥3个点的异常序列 # 避免单点毛刺误报 anomaly_groups anomalies.astype(int).groupby( (anomalies ! anomalies.shift()).cumsum() ).sum() long_anomalies anomaly_groups[anomaly_groups 3].index.tolist() # 构建最终异常掩码 final_mask pd.Series(False, indexpower_series.index) for group_id in long_anomalies: group_indices anomalies[anomalies.groupby( (anomalies ! anomalies.shift()).cumsum() ).ngroup() group_id].index final_mask.loc[group_indices] True return final_mask # 使用示例 # power_series load_power_series(EM-2023-001, freq15T) # anomalies detect_anomalies_iforest(power_series, contamination0.02) # print(f检测到 {anomalies.sum()} 个异常时段)参数说明contamination0.02是经过3个工厂实测的平衡点——设太高0.1会漏掉早期设备劣化信号设太低0.005则报警泛滥。二次过滤逻辑持续≥3个点是电力运维硬要求单点电流突变可能是干扰连续3个15分钟点异常则大概率是真实故障。4. 避坑这5个血泪经验让我在客户现场少熬了72小时夜电力能耗系统上线最怕的不是代码报错而是“功能都对但业务方说没用”。以下是我在3个交付项目中踩过的坑每个都附带可立即执行的检查清单4.1 现象预测曲线和实际负荷偏差巨大MAPE常年15%原因未做时间戳对齐校验。电表本地时钟与服务器时钟偏差达8分钟导致ARIMA模型学习的是“错位”的时序关系。解决在ETL脚本中增加校验SELECT ABS(TIMESTAMPDIFF(SECOND, data_time, created_at)) AS diff_sec FROM raw_energy_data ORDER BY diff_sec DESC LIMIT 10;若diff_sec 3005分钟触发告警并暂停该电表数据入库部署NTP服务强制所有采集网关与数据库服务器时间同步。4.2 现象KMeans聚类结果每天变化无法形成稳定用电模式画像原因日负荷曲线未做归一化导致夏季空调负荷500kW与冬季100kW被强行聚到不同簇掩盖了真实的“双峰型”模式。解决必须使用StandardScaler对每条日曲线单独标准化代码见3.3节禁止对整个数据集做全局标准化聚类前增加检查print(f各日曲线标准差范围: {daily_curves.std(axis1).min():.2f} ~ {daily_curves.std(axis1).max():.2f})若范围10倍说明存在极端异常日需先剔除。4.3 现象Streamlit GUI加载缓慢仪表盘首次打开需45秒原因前端未做数据分页与懒加载一次查询全量历史数据100万点并渲染。解决FastAPI后端接口强制分页GET /api/v1/power?meter_codeEM-001start2024-01-01end2024-01-31limit10000offset0Streamlit前端用st.session_state缓存已加载数据滚动到底部时自动加载下一页关键图表如预测曲线只加载最近7天数据历史对比用聚合统计日均值替代原始点。4.4 现象MySQL查询SELECT * FROM raw_energy_data WHERE data_time BETWEEN ? AND ?始终超时原因缺失复合索引。仅有data_time单字段索引但查询必带meter_code。解决立即执行CREATE INDEX idx_meter_time ON raw_energy_data (meter_code, data_time);验证EXPLAIN SELECT * FROM raw_energy_data WHERE meter_codeEM-001 AND data_time BETWEEN 2024-01-01 AND 2024-01-31;确保key列显示idx_meter_time所有高频查询字段组合必须建立对应复合索引。4.5 现象IsolationForest报警全是“正常设备启动”运维人员拒接告警原因未引入业务上下文过滤。模型无法区分“空压机启动”正常和“变压器击穿”异常二者在功率曲线上都是尖峰。解决建立设备启停知识库表equipment_operation_rules记录每台设备的典型启动/停止功率特征异常检测后增加规则引擎若异常点匹配某设备的启停特征则降级为“注意”级告警不推送短信代码层面if is_anomaly and not matches_startup_pattern(anomaly_point, equipment_code): send_alert()。5. 可视化与决策层Streamlit不是玩具而是用Python写的工业级HMI每一行代码都对应一个运维动作Streamlit常被当作“Python版Dashboard玩具”但在本系统中它承担着工业HMI人机界面的核心职能值班员需要在3秒内看清关键指标、5秒内定位异常回路、10秒内导出PDF报告。所有UI组件都绑定真实业务动作而非静态图表。5.1 实时仪表盘用st.metric和st.progress替代传统折线图对值班员而言“当前总负荷”比“过去24小时曲线”更重要。本系统首页采用极简设计# streamlit_app.py import streamlit as st import pandas as pd # 从FastAPI获取实时数据 st.cache_data(ttl60) # 60秒缓存 def get_realtime_summary(): # 调用FastAPI接口 http://localhost:8000/api/v1/realtime/summary response requests.get(http://localhost:8000/api/v1/realtime/summary) return response.json() # 主仪表盘 st.title(⚡ 实时能源监控中心) summary get_realtime_summary() col1, col2, col3, col4 st.columns(4) col1.metric(当前总负荷, f{summary[total_power_kw]:.1f} kW, f{summary[change_15min]:.1f}% (15min)) col2.metric(峰谷比, f{summary[peak_valley_ratio]:.2f}, f{summary[peak_valley_change]:.2f}% (24h)) col3.metric(功率因数, f{summary[power_factor]:.3f}, f{summary[pf_change]:.3f} (24h)) col4.metric(异常回路, summary[anomaly_count], f{summary[new_anomalies]:} (今日)) # 负荷进度条直观显示当前负荷占设计容量比例 st.subheader(负荷率监控) st.progress(summary[load_factor], textf当前负荷率: {summary[load_factor]*100:.1f}%) # 异常热力图按区域编码展示 st.subheader(异常分布热力图) anomaly_df pd.DataFrame(summary[anomaly_by_region]) st.bar_chart(anomaly_df.set_index(region_code)[count])逻辑说明st.metric显示带变化率的关键指标st.progress用进度条直观表达负荷安全裕度90%标红预警。热力图数据来自API返回的anomaly_by_region前端不做任何计算完全依赖后端聚合保证实时性。5.2 历史曲线对比用plotly.graph_objects实现专业电力曲线叠加电力分析需要精确对比不同时段曲线。Matplotlib难以满足交互需求Plotly是唯一选择import plotly.graph_objects as go from plotly.subplots import make_subplots def plot_power_comparison(meter_code: str, date_list: list[str]) - go.Figure: date_list: [2024-01-01, 2024-01-08, 2024-01-15]最多3天 返回: Plotly Figure对象支持缩放、悬停、导出 # 从FastAPI获取各日15分钟功率数据 data_traces [] colors [#1f77b4, #ff7f0e, #2ca02c] for i, date in enumerate(date_list): # 调用API: GET /api/v1/power?meter_codexxxdate2024-01-01 power_data get_power_data(meter_code, date) trace go.Scatter( xpower_data[time], ypower_data[power_kw], modelines, namef{date} ({power_data[peak_kw]:.1f}kW), linedict(colorcolors[i], width2), hovertemplate%{x|%H:%M}br%{y:.1f} kWextra/extra ) data_traces.append(trace) # 创建对比图 fig go.Figure(datadata_traces) fig.update_layout( titlef电表 {meter_code} 日负荷曲线对比, xaxis_title时间, yaxis_title有功功率 (kW), legend_title日期, hovermodex unified, # 悬停时显示所有曲线同时间点值 templateplotly_white ) # 添加峰谷时段背景色按当地峰谷电价时段 peak_start, peak_end 08:00, 11:00 # 示例 fig.add_vrect(x0peak_start, x1peak_end, fillcolorred, opacity0.1, layerbelow, line_width0, annotation_text峰时段, annotation_positiontop left) return fig # Streamlit中调用 st.plotly_chart(plot_power_comparison(EM-2023-001, [2024-01-01, 2024-01-08]), use_container_widthTrue)参数说明hovermodex unified是电力曲线对比的灵魂——悬停任意时间点自动显示所有曲线在该时刻的值方便快速比对add_vrect标注峰谷时段让节能策略一目了然templateplotly_white适配工业环境高亮显示。5.3 异常点钻取点击热力图区域自动跳转到该区域所有异常回路详情真正的工业HMI必须支持“下钻”。Streamlit的st.button和st.session_state完美实现# 异常热力图下方 st.subheader(异常详情点击区域查看) anomaly_df pd.DataFrame(summary[anomaly_by_region]) # 为每个区域创建按钮 for _, row in anomaly_df.iterrows(): if st.button(f {row[region_name]} ({row[count]}处异常), keyfregion_{row[region_code]}): # 将 p a hrefhttps://download.csdn.net/download/xiaoxingkongyuxi/90437377 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p
上一篇/下一篇内容由系统自动关联
返回资讯列表 →