windDirectionFrequencyAnalyst.py 4.4 KB

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