windDirectionFrequencyAnalyst.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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. from behavior.analystNotFilter import AnalystNotFilter
  7. from utils.directoryUtil import DirectoryUtil as dir
  8. import matplotlib.pyplot as plt
  9. from algorithmContract.confBusiness import *
  10. from algorithmContract.contract import Contract
  11. class WindDirectionFrequencyAnalyst(AnalystNotFilter):
  12. def typeAnalyst(self):
  13. return "wind_direction_frequency"
  14. def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
  15. dictionary=self.processTurbineData(turbineCodes,conf,[Field_DeviceCode,Field_Time,Field_WindDirection,Field_WindSpeed,Field_ActiverPower])
  16. dataFrameMerge=self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
  17. return self.windRoseAnalysis(dataFrameMerge, outputAnalysisDir, conf)
  18. def windRoseAnalysis(self, dataFrameMerge: pd.DataFrame, outputAnalysisDir, conf: Contract):
  19. # 检查所需列是否存在
  20. required_columns = {Field_WindDirection, Field_WindSpeed}
  21. if not required_columns.issubset(dataFrameMerge.columns) or dataFrameMerge[Field_WindDirection].isna().all() or dataFrameMerge[Field_WindSpeed].isna().all():
  22. msg=f"DataFrame缺少必要的列及值。涉及的列有: {required_columns}"
  23. # raise ValueError(msg)
  24. self.logger.warning(msg)
  25. return pd.DataFrame()
  26. # 风速区间
  27. bins = [0, 3, 6, 9, np.inf]
  28. speed_labels = ['[0,3)', '[3,6)', '[6,9)', '>=9']
  29. wind_directions = np.arange(0, 360, 22.5)
  30. colorscale = {
  31. '[0,3)': 'rgba(247.0, 251.0, 255.0, 1.0)',
  32. '[3,6)': 'rgba(171.33333333333334, 207.66666666666666, 229.66666666666669, 1.0)',
  33. '[6,9)': 'rgba(55.0, 135.0, 192.33333333333334, 1.0)',
  34. '>=9': 'rgba(8.0, 48.0, 107.0, 1.0)'
  35. }
  36. # 按设备名分组数据
  37. grouped = dataFrameMerge.groupby([Field_NameOfTurbine, Field_CodeOfTurbine])
  38. result_rows = []
  39. for name, group in grouped:
  40. speed_bins = pd.cut(
  41. group[Field_WindSpeed], bins=bins, labels=speed_labels)
  42. # 调整风向数据以使东方为0度
  43. # adjusted_wind_dir = (group[Field_WindDirection] - 90) % 360
  44. # group['风向分组'] = pd.cut(adjusted_wind_dir, bins=wind_directions, labels=wind_directions[:-1])
  45. group['风向分组'] = pd.cut(
  46. group[Field_WindDirection], bins=wind_directions, labels=wind_directions[:-1])
  47. # 初始化子图,设定为极坐标
  48. fig = make_subplots(rows=1, cols=1, specs=[[{'type': 'polar'}]])
  49. for label in speed_labels:
  50. subset = group[speed_bins == label]
  51. counts = subset['风向分组'].value_counts().reindex(
  52. wind_directions[:-1], fill_value=0)
  53. # 转换为百分比
  54. percentage = (counts / counts.sum()) * 100
  55. # 创建 Barpolar 跟踪,并应用单色渐变
  56. trace = go.Barpolar(
  57. r=percentage.values,
  58. theta=counts.index, # 这里的角度已经适配上北下南左西右东的布局
  59. name=label,
  60. marker_color=colorscale[label], # 应用颜色尺度
  61. marker_showscale=False, # 不显示颜色条
  62. marker_line_color='white', # 设置线条颜色,增加扇区之间的分隔
  63. marker_line_width=1 # 设置线条宽度
  64. )
  65. fig.add_trace(trace)
  66. # 设置图表的一些基本属性
  67. fig.update_layout(
  68. title={
  69. "text": f"机组: {name[0]}",
  70. #"x": 0.5
  71. },
  72. polar=dict(
  73. radialaxis=dict(visible=True),
  74. angularaxis=dict(
  75. tickmode="array",
  76. tickvals=wind_directions,
  77. # 明确标注北、东、南、西等方向,以适应以北为0度的布局
  78. ticktext=['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE',
  79. 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']
  80. # 更新角度标签,以适应以东为0度的布局
  81. # ticktext=['E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N', 'NNE', 'NE', 'ENE']
  82. )
  83. ),
  84. legend_title="风速",
  85. margin=dict(t=50, b=10) # t为顶部(top)间距,b为底部(bottom)间距
  86. )
  87. # 保存图像
  88. filePathOfImage = os.path.join(outputAnalysisDir, f"{name[0]}.png")
  89. fig.write_image(filePathOfImage, scale=3)
  90. filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
  91. fig.write_html(filePathOfHtml)
  92. result_rows.append({
  93. Field_Return_TypeAnalyst: self.typeAnalyst(),
  94. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  95. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  96. Field_CodeOfTurbine: name[1],
  97. Field_Return_FilePath: filePathOfImage,
  98. Field_Return_IsSaveDatabase: False
  99. })
  100. result_rows.append({
  101. Field_Return_TypeAnalyst: self.typeAnalyst(),
  102. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  103. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  104. Field_CodeOfTurbine: name[1],
  105. Field_Return_FilePath: filePathOfHtml,
  106. Field_Return_IsSaveDatabase: True
  107. })
  108. result_df = pd.DataFrame(result_rows)
  109. return result_df