minPitchAnalyst.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import os
  2. import pandas as pd
  3. import numpy as np
  4. import matplotlib.pyplot as plt
  5. import matplotlib.cm as cm
  6. import matplotlib.ticker as ticker
  7. import plotly.express as px
  8. import math
  9. from behavior.analyst import Analyst
  10. from utils.directoryUtil import DirectoryUtil as dir
  11. from algorithmContract.confBusiness import *
  12. class MinPitchAnalyst(Analyst):
  13. """
  14. 风电机组最小桨距角分析
  15. """
  16. def typeAnalyst(self):
  17. return "min_pitch"
  18. def turbinesAnalysis(self, dataFrameMerge: pd.DataFrame, outputAnalysisDir, confData: ConfBusiness):
  19. self.drawTrendGraph(dataFrameMerge, outputAnalysisDir, confData)
  20. def drawTrendGraph(self, dataFrameMerge: pd.DataFrame, outputAnalysisDir, confData: ConfBusiness):
  21. """
  22. Generates pitch angle distribution scatter plots for turbines in a wind farm using plotly.
  23. Parameters:
  24. - dataFrameMerge: pd.DataFrame, DataFrame containing turbine data.
  25. - outputAnalysisDir: str, path to save the output plots.
  26. - confData: ConfBusiness, configuration object containing field names.
  27. """
  28. # 检查所需列是否存在
  29. required_columns = {Field_YearMonthDay, confData.field_pitch_angle1}
  30. if not required_columns.issubset(dataFrameMerge.columns):
  31. raise ValueError(f"DataFrame缺少必要的列。需要的列有: {required_columns}")
  32. pitchAngleRate = 'pitch_angle_rate'
  33. fieldPitchAngleBin = 'pitch_angle_bin'
  34. # Custom color scale: Blue (high pitch_angle_rate) to Light Grey (low pitch_angle_rate)
  35. custom_color_scale = [
  36. (0.0, "rgb(240, 240, 240)"), # Light grey for the lowest values
  37. # (0.25, "rgb(240, 240, 240)"), # Light grey for the lowest values
  38. (0.5, "rgba(55.0, 135.0, 192.33333333333334, 1.0)"), # Medium blue-grey
  39. # (0.75, "rgba(55.0, 135.0, 192.33333333333334, 1.0)"), # Medium blue-grey
  40. # Dark blue for the highest values
  41. (1.0, "rgba(55.0, 135.0, 192.33333333333334, 1.0)")
  42. ]
  43. # Group data by turbine identifier
  44. grouped = dataFrameMerge.groupby(Field_NameOfTurbine)
  45. for name, group in grouped:
  46. # Convert the date column to datetime type
  47. group[Field_YearMonthDay] = pd.to_datetime(
  48. group[Field_YearMonthDay])
  49. # Creating bins of 0.2 intervals for pitch angles
  50. bins = pd.interval_range(start=group[confData.field_pitch_angle1].min(),
  51. end=group[confData.field_pitch_angle1].max(
  52. ) + 0.2,
  53. freq=0.2, closed='right')
  54. group[fieldPitchAngleBin] = pd.cut(
  55. group[confData.field_pitch_angle1], bins=bins)
  56. group[fieldPitchAngleBin] = group[fieldPitchAngleBin].apply(
  57. lambda x: x.left) # 提取每个区间的左端点作为值
  58. # Calculate the pitch angle rate within each day
  59. df = group.groupby([Field_YearMonthDay, confData.field_pitch_angle1]
  60. ).size().reset_index(name='count')
  61. # df = group.groupby([Field_YearMonthDay, fieldPitchAngleBin]
  62. # ).size().reset_index(name='count')
  63. total_counts = group.groupby(
  64. Field_YearMonthDay).size().reset_index(name='total_count')
  65. df = df.merge(total_counts, on=Field_YearMonthDay)
  66. df[pitchAngleRate] = df['count'] / df['total_count'] * 100
  67. # df[pitchAngleRate] = (df['count'] / df['total_count']).apply(lambda x: x ** 0.5)*100
  68. # Plotting using plotly
  69. fig = px.scatter(df,
  70. x=Field_YearMonthDay,
  71. y=confData.field_pitch_angle1, # 桨距角不分仓方式
  72. # y=fieldPitchAngleBin, # 桨距角分仓方式
  73. size='count',
  74. color=pitchAngleRate,
  75. # color_continuous_scale='Blues',
  76. color_continuous_scale=custom_color_scale
  77. )
  78. # Set date format on x-axis
  79. fig.update_xaxes(
  80. title='Time', tickformat='%Y-%m-%d', tickangle=-45)
  81. fig.update_yaxes(title='Pitch Angle',
  82. dtick=confData.graphSets["pitchAngle"]["step"] if not self.common.isNone(
  83. confData.graphSets["pitchAngle"]["step"]) else 2, # 设置y轴刻度间隔为0.1
  84. range=[confData.graphSets["pitchAngle"]["min"] if not self.common.isNone(
  85. confData.graphSets["pitchAngle"]["min"]) else -2, confData.graphSets["pitchAngle"]["max"] if not self.common.isNone(confData.graphSets["pitchAngle"]["max"]) else 28], # 设置y轴的范围从0到1
  86. )
  87. # Customizing legend
  88. fig.update_layout(
  89. title={
  90. "text": f'Pitch Angle Distribution for {name}',
  91. "x": 0.5
  92. },
  93. coloraxis_colorbar=dict(title='Rate'),
  94. margin=dict(t=50, b=10), # t为顶部(top)间距,b为底部(bottom)间距
  95. # plot_bgcolor='rgb(240, 240, 240)'
  96. )
  97. # Set marker size if fixed size is needed
  98. # Fixed size for all points
  99. fig.update_traces(marker=dict(size=3, opacity=0.5))
  100. # Save plot
  101. filePathOfImage = os.path.join(outputAnalysisDir, f"{name}.png")
  102. fig.write_image(filePathOfImage, scale=2)
  103. filePathOfHtml = os.path.join(outputAnalysisDir, f"{name}.html")
  104. fig.write_html(filePathOfHtml)