import os import pandas as pd import numpy as np import plotly.graph_objects as go from plotly.subplots import make_subplots from behavior.analyst import Analyst from utils.directoryUtil import DirectoryUtil as dir from algorithmContract.confBusiness import * import plotly.offline as offline class PitchTSRCpAnalyst(Analyst): def typeAnalyst(self): return "pitch_tsr_cp" def turbinesAnalysis(self, dataFrameMerge, outputAnalysisDir, confData: ConfBusiness): self.windRoseAnalysis(dataFrameMerge, outputAnalysisDir, confData) def windRoseAnalysis(self, dataFrameMerge: pd.DataFrame, outputAnalysisDir, confData: ConfBusiness): """ 绘制3D曲面图。 参数: df: pandas.DataFrame, 必须包含confData.field_pitch_angle1, Field_TSR, 和 Field_Cp这三个字段。 返回: 一个Plotly图形对象。 """ # 检查所需列是否存在 required_columns = {confData.field_pitch_angle1, Field_TSR, Field_Cp} if not required_columns.issubset(dataFrameMerge.columns): raise ValueError(f"DataFrame缺少必要的列。需要的列有: {required_columns}") # 按设备名分组数据 grouped = dataFrameMerge.groupby(Field_NameOfTurbine) for name, group in grouped: layout = go.Layout( title={ "text": f'3D scatter plot: Cp vs. Pitch Angle vs. TSR {name}', "x": 0.5 }, scene=dict( xaxis=dict( title='Pitch Angle', dtick=confData.graphSets["pitchAngle"]["step"] if not self.common.isNone( confData.graphSets["pitchAngle"]["step"]) else 2, # 设置y轴刻度间隔为0.1 range=[confData.graphSets["pitchAngle"]["min"] if not self.common.isNone( confData.graphSets["pitchAngle"]["min"]) else -2, confData.graphSets["pitchAngle"]["max"] if not self.common.isNone(confData.graphSets["pitchAngle"]["max"]) else 28], # 设置y轴的范围从0到1 ), yaxis=dict( title='TSR', dtick=confData.graphSets["tsr"]["step"] if not self.common.isNone( confData.graphSets["tsr"]["step"]) else 5, # 设置y轴刻度间隔为0.1 range=[confData.graphSets["tsr"]["min"] if not self.common.isNone( confData.graphSets["tsr"]["min"]) else 0, confData.graphSets["tsr"]["max"] if not self.common.isNone(confData.graphSets["tsr"]["max"]) else 20], # 设置y轴的范围从0到1 ), zaxis=dict( title='Cp', dtick=confData.graphSets["cp"]["step"] if not self.common.isNone( confData.graphSets["cp"]["step"]) else 0.5, # 设置y轴刻度间隔为0.1 range=[confData.graphSets["cp"]["min"] if not self.common.isNone( confData.graphSets["cp"]["min"]) else 0, confData.graphSets["cp"]["max"] if not self.common.isNone(confData.graphSets["cp"]["max"]) else 2], # 设置y轴的范围从0到1 ) ), margin=dict(t=50, b=10) # t为顶部(top)间距,b为底部(bottom)间距 ) # 创建 3D 散点图 fig = go.Figure(data=[go.Scatter3d( x=group[confData.field_pitch_angle1], y=group[Field_TSR], z=group[Field_Cp], mode='markers', # 设置模式为 markers,表示绘制散点图 marker=dict( size=1, # 设置散点的大小 # 你还可以设置其他属性,如颜色、透明度等 # color='blue', # opacity=0.8 ) )], layout=layout) # 假设 layout 已经定义好了 # 保存html outputFileHtml = os.path.join(outputAnalysisDir, f"{name}.html") fig.write_html(outputFileHtml) # 保存图表为HTML文件 # offline.plot(fig, filename=outputFileHtml, auto_open=False) # 保存图像 # output_file = os.path.join(outputAnalysisDir, f"{name}.png") # fig.write_image(output_file)