Przeglądaj źródła

修改为每台机组输出一个json

wenjia Li 4 miesięcy temu
rodzic
commit
9085b5d719

+ 51 - 54
dataAnalysisBusiness/algorithm/minPitchAnalyst.py

@@ -26,7 +26,7 @@ class MinPitchAnalyst(AnalystWithGoodBadPoint):
         dataFrameMerge = self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
         return self.drawTrendGraph(dataFrameMerge,turbineInfos, outputAnalysisDir, conf)
 
-    def drawTrendGraph(self, dataFrameMerge: pd.DataFrame,  turbineModelInfo: pd.Series,outputAnalysisDir, conf: Contract):
+    def drawTrendGraph(self, dataFrameMerge: pd.DataFrame, turbineModelInfo: pd.Series,outputAnalysisDir, conf: Contract):
         """
         Generates pitch angle distribution scatter plots for turbines in a wind farm using plotly.
 
@@ -91,19 +91,6 @@ class MinPitchAnalyst(AnalystWithGoodBadPoint):
             # df[pitchAngleRate] = (df['count'] / df['total_count']).apply(lambda x: x ** 0.5)*100
             df[pitchAngleRate] = (df['count'] / df['total_count']) * 100
             
-            # 提取数据
-            turbine_data = {
-                "engineName": name[0],
-                "engineCode": name[1],
-                "title":f' {name[0]}的最小桨距角分布',
-                "xData": df[Field_YearMonthDay].dt.strftime('%Y-%m-%d').tolist(),
-                "yData": df[fieldPitchAngleBin].tolist(),
-                "colorbar": df[pitchAngleRate].tolist(),
-                "colorbartitle": "百分比(%)"
-                
-            }
-
-            turbine_data_list.append(turbine_data)
             # Plotting using plotly
             fig = px.scatter(df,
                              x=Field_YearMonthDay,
@@ -139,20 +126,53 @@ class MinPitchAnalyst(AnalystWithGoodBadPoint):
             # Set marker size if fixed size is needed
             # Fixed size for all points
             fig.update_traces(marker=dict(size=3, opacity=0.9))
-
+                         # 确保从 Series 中提取的是具体的值
+            engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+            if isinstance(engineTypeCode, pd.Series):
+                engineTypeCode = engineTypeCode.iloc[0]
+    
+            engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+            if isinstance(engineTypeName, pd.Series):
+                engineTypeName = engineTypeName.iloc[0]
+            # 构建最终的JSON对象
+            json_output = {
+                "analysisTypeCode": "最小桨距角分析",
+                "engineCode":  engineTypeCode,    
+                "engineTypeName": engineTypeName, 
+                "xaixs": "时间",
+                "yaixs": "桨距角(度)",
+                "data": [{
+                "engineName": name[0],
+                "engineCode": name[1],
+                "title":f' {name[0]}的最小桨距角分布',
+                "xData": df[Field_YearMonthDay].dt.strftime('%Y-%m-%d').tolist(),
+                "yData": df[fieldPitchAngleBin].tolist(),
+                "colorbar": df[pitchAngleRate].tolist(),
+                "colorbartitle": "百分比(%)"
+                
+            }]
+            }
+            
             # Save plot
             filePathOfImage = os.path.join(outputAnalysisDir, f"{name[0]}.png")
             fig.write_image(filePathOfImage, scale=3)
-            filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
-            fig.write_html(filePathOfHtml)
+            # filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
+            # fig.write_html(filePathOfHtml)
+
+            # 将JSON对象保存到文件
+            output_json_path = os.path.join(outputAnalysisDir, f"min_pitch{name[0]}.json")
+            with open(output_json_path, 'w', encoding='utf-8') as f:
+                import json
+                json.dump(json_output, f, ensure_ascii=False, indent=4)
 
+            # 如果需要返回DataFrame,可以包含文件路径
             result_rows.append({
                 Field_Return_TypeAnalyst: self.typeAnalyst(),
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
                 Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
                 Field_CodeOfTurbine: name[1],
-                Field_Return_FilePath: filePathOfImage,
-                Field_Return_IsSaveDatabase: False
+                Field_Return_FilePath: output_json_path,
+                Field_Return_IsSaveDatabase: True
             })
 
             result_rows.append({
@@ -160,42 +180,19 @@ class MinPitchAnalyst(AnalystWithGoodBadPoint):
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
                 Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
                 Field_CodeOfTurbine: name[1],
-                Field_Return_FilePath: filePathOfHtml,
-                Field_Return_IsSaveDatabase: True
+                Field_Return_FilePath: filePathOfImage,
+                Field_Return_IsSaveDatabase: False
             })
-        # 确保从 Series 中提取的是具体的值
-        engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
-        if isinstance(engineTypeCode, pd.Series):
-            engineTypeCode = engineTypeCode.iloc[0]
-
-        engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
-        if isinstance(engineTypeName, pd.Series):
-            engineTypeName = engineTypeName.iloc[0]
-        # 构建最终的JSON对象
-        json_output = {
-            "analysisTypeCode": "最小桨距角分析",
-            "engineCode":  engineTypeCode,    
-            "engineTypeName": engineTypeName, 
-            "xaixs": "时间",
-            "yaixs": "桨距角(度)",
-            "data": turbine_data_list
-        }
-
-        # 将JSON对象保存到文件
-        output_json_path = os.path.join(outputAnalysisDir, "min_pitch_analysis.json")
-        with open(output_json_path, 'w', encoding='utf-8') as f:
-            import json
-            json.dump(json_output, f, ensure_ascii=False, indent=4)
-
-        # 如果需要返回DataFrame,可以包含文件路径
-        result_rows.append({
-            Field_Return_TypeAnalyst: self.typeAnalyst(),
-            Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
-            Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
-            Field_CodeOfTurbine: Const_Output_Total,
-            Field_Return_FilePath: output_json_path,
-            Field_Return_IsSaveDatabase: True
-        })
+
+            # result_rows.append({
+            #     Field_Return_TypeAnalyst: self.typeAnalyst(),
+            #     Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
+            #     Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
+            #     Field_CodeOfTurbine: name[1],
+            #     Field_Return_FilePath: filePathOfHtml,
+            #     Field_Return_IsSaveDatabase: True
+            # })
+       
         result_df = pd.DataFrame(result_rows)
 
         return result_df

+ 44 - 47
dataAnalysisBusiness/algorithm/pitchTSRCpAnalyst.py

@@ -39,7 +39,6 @@ class PitchTSRCpAnalyst(AnalystWithGoodPoint):
         # grouped = dataFrameMerge.groupby([Field_NameOfTurbine, Field_CodeOfTurbine])
 
         result_rows = []
-        turbine_data_list=[]
 
         ## 分图
         dataFrameMerge['PitchAngleBin'] = pd.cut(dataFrameMerge[Field_PitchAngel1], bins=[-1, 1, 3, 5, 7, 9], right=True, labels=['[-1,1]', '(1,3]', '(3,5]', '(5,7]', '(7,9]'])
@@ -65,18 +64,6 @@ class PitchTSRCpAnalyst(AnalystWithGoodPoint):
                     )
                     # name=f'Pitch: {name}'
                 ))
-                # 提取数据
-                turbine_data = {
-                    "engineName": turbine_name,
-                    "engineCode": turbine_code,
-                    "title":f' 风能利用系数 vs. 叶尖速比-{turbine_name}',
-                    "xData": group[Field_TSR].tolist(),
-                    "yData":group[Field_Cp].tolist(),
-                    "colorbar": pitch_bin,
-                    "colorbartitle": "桨距角"
-
-                }
-                turbine_data_list.append(turbine_data)
 
             # 更新布局
             fig.update_layout(
@@ -103,13 +90,55 @@ class PitchTSRCpAnalyst(AnalystWithGoodPoint):
                 #     y=-0.2
                 # )
             )
-
+                        # 确保从 Series 中提取的是具体的值
+            engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+            if isinstance(engineTypeCode, pd.Series):
+                engineTypeCode = engineTypeCode.iloc[0]
+
+            engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+            if isinstance(engineTypeName, pd.Series):
+                engineTypeName = engineTypeName.iloc[0]
+            # 构建最终的JSON对象
+            json_output = {
+                "analysisTypeCode": "变桨和叶尖速比及风能利用系数分析",
+                "engineCode":  engineTypeCode,    
+                "engineTypeName": engineTypeName, 
+                "xaixs": "叶尖速比",
+                "yaixs": "风能利用系数",
+                "data": [{
+                        "engineName": turbine_name,
+                        "engineCode": turbine_code,
+                        "title":f' 风能利用系数 vs. 叶尖速比-{turbine_name}',
+                        "xData": group[Field_TSR].tolist(),
+                        "yData":group[Field_Cp].tolist(),
+                        "colorbar": pitch_bin,
+                        "colorbartitle": "桨距角"
+                        }]
+            }
+            
+            
             # 保存html
             filePathOfPng = os.path.join(outputAnalysisDir, f"{turbine_name}.png")
             fig.write_image(filePathOfPng)
             filePathOfHtml = os.path.join(outputAnalysisDir, f"{turbine_name}.html")
             fig.write_html(filePathOfHtml)
 
+
+            # 将JSON对象保存到文件
+            output_json_path = os.path.join(outputAnalysisDir, f"pitch_TSR_cp{turbine_name}.json")
+            with open(output_json_path, 'w', encoding='utf-8') as f:
+                import json
+                json.dump(json_output, f, ensure_ascii=False, indent=4)
+
+            # 如果需要返回DataFrame,可以包含文件路径
+            result_rows.append({
+                Field_Return_TypeAnalyst: self.typeAnalyst(),
+                Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
+                Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
+                Field_CodeOfTurbine: turbine_code,
+                Field_Return_FilePath: output_json_path,
+                Field_Return_IsSaveDatabase: True
+            })
             result_rows.append({
                 Field_Return_TypeAnalyst: self.typeAnalyst(),
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
@@ -126,39 +155,7 @@ class PitchTSRCpAnalyst(AnalystWithGoodPoint):
                 Field_Return_FilePath: filePathOfHtml,
                 Field_Return_IsSaveDatabase: True
             })
-        # 确保从 Series 中提取的是具体的值
-        engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
-        if isinstance(engineTypeCode, pd.Series):
-            engineTypeCode = engineTypeCode.iloc[0]
-
-        engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
-        if isinstance(engineTypeName, pd.Series):
-            engineTypeName = engineTypeName.iloc[0]
-        # 构建最终的JSON对象
-        json_output = {
-            "analysisTypeCode": "变桨和叶尖速比及风能利用系数分析",
-            "engineCode":  engineTypeCode,    
-            "engineTypeName": engineTypeName, 
-            "xaixs": "叶尖速比",
-            "yaixs": "风能利用系数",
-            "data": turbine_data_list
-        }
-
-        # 将JSON对象保存到文件
-        output_json_path = os.path.join(outputAnalysisDir, "pitch_TSR_cp.json")
-        with open(output_json_path, 'w', encoding='utf-8') as f:
-            import json
-            json.dump(json_output, f, ensure_ascii=False, indent=4)
-
-        # 如果需要返回DataFrame,可以包含文件路径
-        result_rows.append({
-            Field_Return_TypeAnalyst: self.typeAnalyst(),
-            Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
-            Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
-            Field_CodeOfTurbine: Const_Output_Total,
-            Field_Return_FilePath: output_json_path,
-            Field_Return_IsSaveDatabase: True
-        })
+
 
         result_df = pd.DataFrame(result_rows)
 

+ 63 - 66
dataAnalysisBusiness/algorithm/powerScatter2DAnalyst.py

@@ -29,6 +29,7 @@ class PowerScatter2DAnalyst(AnalystWithGoodBadPoint):
     def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
         dictionary = self.processTurbineData(turbineCodes, conf, self.selectColumns())
         dataFrame = self.userDataFrame(dictionary, conf.dataContract.configAnalysis, self)
+        turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes, self.turbineInfo)
         if len(dataFrame) <= 0:
             print("After screening for blade pitch angle less than the configured value, plot power curve scatter points without data")
             return
@@ -37,9 +38,9 @@ class PowerScatter2DAnalyst(AnalystWithGoodBadPoint):
 
         for groupByKey, contractPowerCurveOfMillType in grouped:
             break
-        return self.drawOfPowerCurveScatter(dataFrame, outputAnalysisDir, conf, contractPowerCurveOfMillType)
+        return self.drawOfPowerCurveScatter(dataFrame, turbineInfos,outputAnalysisDir, conf, contractPowerCurveOfMillType)
 
-    def drawOfPowerCurveScatter(self, dataFrame: pd.DataFrame,  outputAnalysisDir, conf: Contract, dataFrameGuaranteePowerCurve: pd.DataFrame):
+    def drawOfPowerCurveScatter(self, dataFrame: pd.DataFrame,  turbineModelInfo: pd.Series, outputAnalysisDir, conf: Contract, dataFrameGuaranteePowerCurve: pd.DataFrame):
         """
         绘制风速-功率分布图并保存为文件。
 
@@ -59,70 +60,6 @@ class PowerScatter2DAnalyst(AnalystWithGoodBadPoint):
         #     cut_in_ws = dataFrame[Field_CutInWS].min() - 1
         # else:
         #     cut_in_ws = 2
-        '''
-        # 按设备名分组数据
-        grouped = dataFrame.groupby([Field_NameOfTurbine, Field_CodeOfTurbine])
-        result_rows = []
-        # 定义固定的颜色映射列表
-        fixed_colors =[
-            'rgb(255, 0, 0)',    # 红色
-            'rgb(0, 255, 0)',    # 绿色
-            'rgb(0, 0, 255)',    # 蓝色
-            'rgb(255, 255, 0)',  # 黄色
-            'rgb(255, 0, 255)',  # 紫色
-            'rgb(0, 255, 255)'   # 青色
-        ]
-        # 遍历每个设备的数据
-        for name, group in grouped:
-            fig = make_subplots()
-            # 提取月份
-            group['month'] = group['monthIntTime'].apply(lambda x: datetime.fromtimestamp(x).month)
-            unique_months = group['month'].unique()
-        
-            # 计算时间跨度
-            time_span_months = len(unique_months)
-        
-            if time_span_months >= 6:
-                # 绘制散点图(时间跨度大于等于6个月)
-                scatter = go.Scatter(x=group[Field_WindSpeed],
-                                     y=group[Field_ActiverPower],
-                                     mode='markers',
-                                     marker=dict(
-                                         color=group['monthIntTime'],
-                                         colorscale='Rainbow',
-                                         size=3,
-                                         opacity=0.7,
-                                         colorbar=dict(
-                                             tickvals=np.linspace(
-                                                 group['monthIntTime'].min(), group['monthIntTime'].max(), 6),
-                                             ticktext=[datetime.fromtimestamp(ts).strftime(
-                                                 '%Y-%m') for ts in np.linspace(group['monthIntTime'].min(), group['monthIntTime'].max(), 6)],
-                                             thickness=18,
-                                             len=1,  # 设置颜色条的长度,使其占据整个图的高度
-                                             outlinecolor='rgba(255,255,255,0)'
-                                         ),
-                                         showscale=True
-                                     ),
-                                     showlegend=False)  # 不显示散点图的legend,用colorbar代替
-                fig.add_trace(scatter)
-            else:
-                # 绘制散点图(时间跨度小于6个月)
-                for i,month in enumerate(unique_months):
-                    month_data = group[group['month'] == month]
-                    # 使用固定的颜色列表
-                    color = fixed_colors[i % len(fixed_colors)]
-                    scatter = go.Scatter(x=month_data[Field_WindSpeed],
-                                         y=month_data[Field_ActiverPower],
-                                         mode='markers',
-                                         marker=dict(
-                                             color=color,
-                                             size=3,
-                                             opacity=0.7
-                                         ),
-                                         name=f'{datetime.fromtimestamp(month_data["monthIntTime"].iloc[0]).strftime("%Y-%m")}',
-                                         showlegend=True)
-                    fig.add_trace(scatter)
-        '''
         
         # 按设备名分组数据
         grouped = dataFrame.groupby([Field_NameOfTurbine, Field_CodeOfTurbine])
@@ -166,6 +103,8 @@ class PowerScatter2DAnalyst(AnalystWithGoodBadPoint):
             "#3E409C"
 
         ]
+        # 新建一个列表存储输出json格式的数据
+        turbine_data_list = []
         # 遍历每个设备的数据
         for name, group in grouped:
             fig = make_subplots()
@@ -241,7 +180,47 @@ class PowerScatter2DAnalyst(AnalystWithGoodBadPoint):
                 legend=dict(yanchor="bottom", y=0, xanchor="right", x=1, font=dict(
                     size=10), bgcolor='rgba(255,255,255,0)')
             )
+            # 确保从 Series 中提取的是具体的值
+            engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+            if isinstance(engineTypeCode, pd.Series):
+                engineTypeCode = engineTypeCode.iloc[0]
+    
+            engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+            if isinstance(engineTypeName, pd.Series):
+                engineTypeName = engineTypeName.iloc[0]
 
+            # 定义要替换的空值类型
+            na_values = {pd.NA, float('nan')}
+            # 构建最终的JSON对象
+            json_output = {
+                "analysisTypeCode": "逐月有功功率散点2D分析",
+                "engineCode":  engineTypeCode,    
+                "engineTypeName": engineTypeName, 
+                "xaixs": "风速(m/s)",
+                "yaixs": "有功功率(kw)",
+                "data": [
+                    {# 提取机组数据
+                    "engineName": name[0],
+                    "engineCode": name[1],
+                    "title":f' 机组: {name[0]}',
+                    "xData": group[Field_WindSpeed].replace(na_values, None).tolist(),
+                    "xrange":[cut_in_ws, 25],
+                    "yData": group[Field_ActiverPower].replace(na_values, None).tolist(),
+                    "yrange":[self.axisLowerLimitActivePower,self.axisUpperLimitActivePower],
+                    "colorbar": group['monthIntTime'].tolist(),
+                    "colorbartitle": "年月",
+                    "mode":"markers"
+                
+                    },
+                    {# 提取合同功率曲线数据
+                        "enginName": "合同功率曲线",
+                        "xData":dataFrameGuaranteePowerCurve[Field_WindSpeed].replace(na_values, None).tolist(),
+                        "yData":dataFrameGuaranteePowerCurve[Field_ActiverPower].replace(na_values, None).tolist(),
+                        "zData": [],
+                        "mode":"lines+markers"
+                    }]
+            }
+            
             # 保存图像
             pngFileName = f"{name[0]}-scatter.png"
             pngFilePath = os.path.join(outputAnalysisDir, pngFileName)
@@ -252,6 +231,23 @@ class PowerScatter2DAnalyst(AnalystWithGoodBadPoint):
             htmlFilePath = os.path.join(outputAnalysisDir, htmlFileName)
             fig.write_html(htmlFilePath)
 
+
+            # 将JSON对象保存到文件
+            output_json_path = os.path.join(outputAnalysisDir, f"{name[0]}-scatter.json")
+            with open(output_json_path, 'w', encoding='utf-8') as f:
+                import json
+                json.dump(json_output, f, ensure_ascii=False, indent=4)
+
+            # 如果需要返回DataFrame,可以包含文件路径
+            result_rows.append({
+                Field_Return_TypeAnalyst: self.typeAnalyst(),
+                Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
+                Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
+                Field_CodeOfTurbine: name[1],
+                Field_Return_FilePath: output_json_path,
+                Field_Return_IsSaveDatabase: True
+            })
+
             result_rows.append({
                 Field_Return_TypeAnalyst: self.typeAnalyst(),
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
@@ -269,6 +265,7 @@ class PowerScatter2DAnalyst(AnalystWithGoodBadPoint):
                 Field_Return_FilePath: htmlFilePath,
                 Field_Return_IsSaveDatabase: True
             })
+       
 
         result_df = pd.DataFrame(result_rows)
         return result_df

+ 59 - 9
dataAnalysisBusiness/algorithm/tsrTrendAnalyst.py

@@ -23,9 +23,10 @@ class TSRTrendAnalyst(AnalystWithGoodPoint):
     def turbinesAnalysis(self,  outputAnalysisDir, conf: Contract, turbineCodes):
         dictionary = self.processTurbineData(turbineCodes,conf,self.selectColumns())
         dataFrameMerge = self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
-        return self.drawTSRTrend(dataFrameMerge, outputAnalysisDir, conf)
+        turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes, self.turbineInfo)
+        return self.drawTSRTrend(dataFrameMerge,turbineInfos, outputAnalysisDir, conf)
 
-    def drawTSRTrend(self,dataFrameMerge:pd.DataFrame, outputAnalysisDir, conf: Contract):
+    def drawTSRTrend(self,dataFrameMerge:pd.DataFrame, turbineModelInfo: pd.Series,outputAnalysisDir, conf: Contract):
         # 检查所需列是否存在
         required_columns = {Field_TSR, Field_YearMonthDay}
         if not required_columns.issubset(dataFrameMerge.columns):
@@ -101,19 +102,59 @@ class TSRTrendAnalyst(AnalystWithGoodPoint):
                 margin=dict(t=50, b=10)  # t为顶部(top)间距,b为底部(bottom)间距
             )
 
+            # 确保从 Series 中提取的是具体的值
+            engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+            if isinstance(engineTypeCode, pd.Series):
+                engineTypeCode = engineTypeCode.iloc[0]
+
+            engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+            if isinstance(engineTypeName, pd.Series):
+                engineTypeName = engineTypeName.iloc[0]
+            # 构建最终的JSON对象
+            json_output = {
+                "analysisTypeCode": "叶尖速比时序分析",
+                "engineCode":  engineTypeCode,    
+                "engineTypeName": engineTypeName, 
+                "xaixs": "时间",
+                "yaixs": "叶尖速比",
+                "data": [{
+                        "engineName": name[0],
+                        "engineCode": name[1],
+                        "title":f'机组-{name[0]}',
+                        "xData": filtered_group[Field_YearMonthDay].tolist(),
+                        "yData": filtered_group[Field_TSR].tolist(),
+                        "color":'lightgray',
+                        "width":2,
+                        "type":"box_plot",
+                        "medians": {
+                                "x": medians.index.tolist(),  # 中位数的 x 轴数据
+                                "y": medians.values.tolist(),  # 中位数的 y 轴数据
+                                "mode":'markers',
+                                "color":'orange', 
+                                "size":3
+                                }
+                        }] 
+            }
+            
             # 保存图像
             filePathOfImage = os.path.join(outputAnalysisDir, f"{name[0]}.png")
             fig.write_image(filePathOfImage, scale=3)
-            filePathOfHtml  = os.path.join(outputAnalysisDir, f"{name[0]}.html")
-            fig.write_html(filePathOfHtml)
-
+            # filePathOfHtml  = os.path.join(outputAnalysisDir, f"{name[0]}.html")
+            # fig.write_html(filePathOfHtml)
+            # 将JSON对象保存到文件
+            output_json_path = os.path.join(outputAnalysisDir, f"{name[0]}.json")
+            with open(output_json_path, 'w', encoding='utf-8') as f:
+                import json
+                json.dump(json_output, f, ensure_ascii=False, indent=4)
+
+            # 如果需要返回DataFrame,可以包含文件路径
             result_rows.append({
                 Field_Return_TypeAnalyst: self.typeAnalyst(),
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
                 Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
                 Field_CodeOfTurbine: name[1],
-                Field_Return_FilePath: filePathOfImage,
-                Field_Return_IsSaveDatabase: False
+                Field_Return_FilePath: output_json_path,
+                Field_Return_IsSaveDatabase: True
             })
 
             result_rows.append({
@@ -121,10 +162,19 @@ class TSRTrendAnalyst(AnalystWithGoodPoint):
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
                 Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
                 Field_CodeOfTurbine: name[1],
-                Field_Return_FilePath: filePathOfHtml,
-                Field_Return_IsSaveDatabase: True
+                Field_Return_FilePath: filePathOfImage,
+                Field_Return_IsSaveDatabase: False
             })
 
+            # result_rows.append({
+            #     Field_Return_TypeAnalyst: self.typeAnalyst(),
+            #     Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
+            #     Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
+            #     Field_CodeOfTurbine: name[1],
+            #     Field_Return_FilePath: filePathOfHtml,
+            #     Field_Return_IsSaveDatabase: True
+            # })
+
         result_df = pd.DataFrame(result_rows)
 
         return result_df

+ 54 - 55
dataAnalysisBusiness/algorithm/yawErrorDensityAnalyst.py

@@ -65,7 +65,7 @@ class YawErrorDensityAnalyst(AnalystWithGoodPoint):
         fixed_colorscale = [
             [i / (len(fixed_colors) - 1), color] for i, color in enumerate(fixed_colors)
         ]
-        turbine_data_list=[]
+        
         for name, group in grouped:
         
             df = self.calculateYawError(group)
@@ -94,20 +94,7 @@ class YawErrorDensityAnalyst(AnalystWithGoodPoint):
                 'min_X':[min_X]
             }
             result = pd.DataFrame(result)
-            print(f'{name[0]}指标:',result)
-             # 提取数据
-            turbine_data = {
-                "engineName": name[0],
-                "engineCode": name[1],
-                "title":f'动态偏航误差分析-{name[0]}',
-                "xData": df["x"].tolist(),
-                "yData": df["y"].tolist(),
-                "colorbar": df["density"].tolist(),
-                "colorbartitle": "密度"
-                
-            }
 
-            turbine_data_list.append(turbine_data)
             # 用密度作为颜色绘制散点图,并限制横坐标范围为 -20 到 20
             fig = go.Figure()
             fig.add_trace(go.Scattergl(
@@ -130,19 +117,56 @@ class YawErrorDensityAnalyst(AnalystWithGoodPoint):
                 xaxis=dict(range=[-20, 20]),  # 限制横坐标范围为 -20 到 20
                 yaxis=dict(range=[0, 25])
             )
+
+            # 确保从 Series 中提取的是具体的值
+            engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+            if isinstance(engineTypeCode, pd.Series):
+                engineTypeCode = engineTypeCode.iloc[0]
+
+            engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+            if isinstance(engineTypeName, pd.Series):
+                engineTypeName = engineTypeName.iloc[0]
+            # 构建最终的JSON对象
+            json_output = {
+                "analysisTypeCode": "动态偏航误差",
+                "engineCode":  engineTypeCode,    
+                "engineTypeName": engineTypeName, 
+                "xaixs": "对风角度(度)",
+                "yaixs": "风速(m/s)",
+                "data": [{
+                "engineName": name[0],
+                "engineCode": name[1],
+                "title":f'动态偏航误差分析-{name[0]}',
+                "xData": df["x"].tolist(),
+                "yData": df["y"].tolist(),
+                "colorbar": df["density"].tolist(),
+                "colorbartitle": "密度"
+                
+            }]
+            }
+
+            
             # Save to file
             filePathOfImage = os.path.join(outputAnalysisDir, f"{name[0]}.png")
             fig.write_image(filePathOfImage, scale=3)
-            filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
-            fig.write_html(filePathOfHtml)
+            # filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
+            # fig.write_html(filePathOfHtml)
+
 
+            # 将JSON对象保存到文件
+            output_json_path = os.path.join(outputAnalysisDir, f"{name[0]}.json")
+            with open(output_json_path, 'w', encoding='utf-8') as f:
+                import json
+                json.dump(json_output, f, ensure_ascii=False, indent=4)
+
+            # 如果需要返回DataFrame,可以包含文件路径
             result_rows.append({
                 Field_Return_TypeAnalyst: self.typeAnalyst(),
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
                 Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
                 Field_CodeOfTurbine: name[1],
-                Field_Return_FilePath: filePathOfImage,
-                Field_Return_IsSaveDatabase: False
+                Field_Return_FilePath: output_json_path,
+                Field_Return_IsSaveDatabase: True
             })
 
             result_rows.append({
@@ -150,45 +174,20 @@ class YawErrorDensityAnalyst(AnalystWithGoodPoint):
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
                 Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
                 Field_CodeOfTurbine: name[1],
-                Field_Return_FilePath: filePathOfHtml,
-                Field_Return_IsSaveDatabase: True
-            
-            
+                Field_Return_FilePath: filePathOfImage,
+                Field_Return_IsSaveDatabase: False
             })
-         # 确保从 Series 中提取的是具体的值
-        engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
-        if isinstance(engineTypeCode, pd.Series):
-            engineTypeCode = engineTypeCode.iloc[0]
-
-        engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
-        if isinstance(engineTypeName, pd.Series):
-            engineTypeName = engineTypeName.iloc[0]
-        # 构建最终的JSON对象
-        json_output = {
-            "analysisTypeCode": "动态偏航误差",
-            "engineCode":  engineTypeCode,    
-            "engineTypeName": engineTypeName, 
-            "xaixs": "对风角度(度)",
-            "yaixs": "风速(m/s)",
-            "data": turbine_data_list
-        }
-
-        # 将JSON对象保存到文件
-        output_json_path = os.path.join(outputAnalysisDir, "yaw_error_density.json")
-        with open(output_json_path, 'w', encoding='utf-8') as f:
-            import json
-            json.dump(json_output, f, ensure_ascii=False, indent=4)
-
-        # 如果需要返回DataFrame,可以包含文件路径
-        result_rows.append({
-            Field_Return_TypeAnalyst: self.typeAnalyst(),
-            Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
-            Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
-            Field_CodeOfTurbine: Const_Output_Total,
-            Field_Return_FilePath: output_json_path,
-            Field_Return_IsSaveDatabase: True
-        })
 
+            # result_rows.append({
+            #     Field_Return_TypeAnalyst: self.typeAnalyst(),
+            #     Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
+            #     Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
+            #     Field_CodeOfTurbine: name[1],
+            #     Field_Return_FilePath: filePathOfHtml,
+            #     Field_Return_IsSaveDatabase: True
+            
+            
+            # })
 
         result_df = pd.DataFrame(result_rows)