pitchPowerAnalyst.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import os
  2. import pandas as pd
  3. import numpy as np
  4. import plotly.graph_objects as go
  5. from plotly.subplots import make_subplots
  6. import seaborn as sns
  7. import matplotlib.pyplot as plt
  8. from matplotlib.ticker import MultipleLocator
  9. from behavior.analyst import Analyst
  10. from utils.directoryUtil import DirectoryUtil as dir
  11. from algorithmContract.confBusiness import *
  12. class PitchPowerAnalyst(Analyst):
  13. """
  14. 风电机组变桨-功率分析
  15. """
  16. def typeAnalyst(self):
  17. return "pitch_power"
  18. def turbinesAnalysis(self, dataFrameMerge, outputAnalysisDir, confData: ConfBusiness):
  19. self.plot_power_pitch_angle(
  20. dataFrameMerge, outputAnalysisDir, confData)
  21. self.drawScatterGraph(dataFrameMerge, outputAnalysisDir, confData)
  22. def plot_power_pitch_angle(self, dataFrameMerge, outputAnalysisDir, confData: ConfBusiness):
  23. x_name = 'power'
  24. y_name = 'pitch_angle'
  25. # 按设备名分组数据
  26. grouped = dataFrameMerge.groupby(Field_NameOfTurbine)
  27. print("self.ratedPower {}".format(confData.rated_power))
  28. # 遍历每个设备并绘制散点图
  29. for name, group in grouped:
  30. # sns.lmplot函数参数scatter_kws: 设置为{"s": 5}时,会出现颜色丢失问题;
  31. g = sns.lmplot(x=confData.field_power, y=confData.field_pitch_angle1, data=group,
  32. fit_reg=False, scatter_kws={"s": 5, "color": "b"}, legend=False, height=6, aspect=1.2)
  33. # g = sns.lmplot(x=confData.field_power, y=confData.field_pitch_angle1, data=group,
  34. # fit_reg=False, scatter_kws={"s": 5}, legend=False, height=6, aspect=1.2)
  35. # 设置x轴和y轴的刻度
  36. for ax in g.axes.flat:
  37. ax.xaxis.set_major_locator(MultipleLocator(confData.graphSets["activePower"]["step"] if not self.common.isNone(
  38. confData.graphSets["activePower"]) and not self.common.isNone(
  39. confData.graphSets["activePower"]["step"]) else 250))
  40. ax.set_xlim(confData.graphSets["activePower"]["min"] if not self.common.isNone(
  41. confData.graphSets["activePower"]["min"]) else 0, confData.graphSets["activePower"]["max"] if not self.common.isNone(confData.graphSets["activePower"]["max"]) else confData.rated_power*1.2)
  42. ax.yaxis.set_major_locator(MultipleLocator(confData.graphSets["pitchAngle"]["step"] if not self.common.isNone(
  43. confData.graphSets["pitchAngle"]["step"]) else 2))
  44. ax.set_ylim(confData.graphSets["pitchAngle"]["min"] if not self.common.isNone(
  45. confData.graphSets["pitchAngle"]["min"]) else -2, confData.graphSets["pitchAngle"]["max"] if not self.common.isNone(confData.graphSets["pitchAngle"]["max"]) else 28)
  46. ax.set_xlabel(x_name)
  47. ax.set_ylabel(y_name)
  48. # 设置x轴刻度值旋转角度为45度
  49. plt.tick_params(axis='x', rotation=45)
  50. # 调整布局和设置标题
  51. plt.tight_layout()
  52. plt.title(f'{Field_NameOfTurbine}={name}')
  53. # 保存图像并关闭绘图窗口
  54. output_file = os.path.join(outputAnalysisDir, f"{name}.png")
  55. plt.savefig(output_file, bbox_inches='tight', dpi=120)
  56. plt.close()
  57. def drawScatterGraph(self, dataFrame: pd.DataFrame, outputAnalysisDir, confData: ConfBusiness):
  58. """
  59. 绘制变桨-功率分布图并保存为文件。
  60. 参数:
  61. dataFrameMerge (pd.DataFrame): 包含数据的DataFrame,需要包含设备名、风速和功率列。
  62. outputAnalysisDir (str): 分析输出目录。
  63. confData (ConfBusiness): 配置
  64. """
  65. # 按设备名分组数据
  66. colorsList = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd',
  67. '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf', '#aec7e8', '#ffbb78']
  68. grouped = dataFrame.groupby(Field_NameOfTurbine)
  69. # 遍历每个设备的数据
  70. for name, group in grouped:
  71. # 创建颜色映射,将每个年月映射到一个唯一的颜色
  72. unique_months = group[Field_YearMonth].unique()
  73. colors = [
  74. colorsList[i % 12] for i in range(len(unique_months))]
  75. color_map = dict(zip(unique_months, colors))
  76. # 使用go.Scatter3d创建3D散点图
  77. trace = go.Scatter3d(
  78. x=group[confData.field_pitch_angle1],
  79. y=group[Field_YearMonth],
  80. z=group[confData.field_power],
  81. mode='markers',
  82. marker=dict(
  83. color=[color_map[month]
  84. for month in group[Field_YearMonth]],
  85. size=1.5,
  86. line=dict(
  87. color='rgba(0, 0, 0, 0)', # 设置边框颜色为透明,以去掉白色边框
  88. width=0 # 设置边框宽度为0,进一步确保没有边框
  89. ),
  90. opacity=0.8 # 调整散点的透明度,增加透视效果
  91. )
  92. )
  93. # 创建图形
  94. fig = go.Figure(data=[trace])
  95. # 更新图形的布局
  96. fig.update_layout(
  97. title={
  98. "text": f'Monthly pitch to power 3D scatter plot {name}',
  99. "x": 0.5
  100. },
  101. scene=dict(
  102. xaxis=dict(
  103. title='Pitch Angle',
  104. dtick=confData.graphSets["pitchAngle"]["step"] if not self.common.isNone(
  105. confData.graphSets["pitchAngle"]["step"]) else 2, # 设置y轴刻度间隔为0.1
  106. range=[confData.graphSets["pitchAngle"]["min"] if not self.common.isNone(
  107. confData.graphSets["pitchAngle"]["min"]) else -2, confData.graphSets["pitchAngle"]["max"] if not self.common.isNone(confData.graphSets["pitchAngle"]["max"]) else 28], # 设置y轴的范围从0到1
  108. showgrid=True, # 显示网格线
  109. ),
  110. yaxis=dict(
  111. title='Time',
  112. tickmode='array',
  113. tickvals=unique_months,
  114. ticktext=unique_months,
  115. showgrid=True, # 显示网格线
  116. categoryorder='category ascending'
  117. ),
  118. zaxis=dict(
  119. title='Power',
  120. dtick=confData.graphSets["activePower"]["step"] if not self.common.isNone(
  121. confData.graphSets["activePower"]) and not self.common.isNone(
  122. confData.graphSets["activePower"]["step"]) else 250,
  123. range=[confData.graphSets["activePower"]["min"] if not self.common.isNone(
  124. confData.graphSets["activePower"]["min"]) else 0, confData.graphSets["activePower"]["max"] if not self.common.isNone(confData.graphSets["activePower"]["max"]) else confData.rated_power*1.2],
  125. )
  126. ),
  127. scene_camera=dict(
  128. up=dict(x=0, y=0, z=1), # 保持相机向上方向不变
  129. center=dict(x=0, y=0, z=0), # 保持相机中心位置不变
  130. eye=dict(x=-1.8, y=-1.8, z=1.2) # 调整eye属性以实现水平旋转180°
  131. ),
  132. margin=dict(t=50, b=10) # t为顶部(top)间距,b为底部(bottom)间距
  133. )
  134. # 保存图像
  135. outputFileHtml = os.path.join(
  136. outputAnalysisDir, "{}.html".format(name))
  137. fig.write_html(outputFileHtml)