|
|
@@ -3,7 +3,6 @@ import fs from "fs-extra";
|
|
|
import path from "path";
|
|
|
import FormData from "form-data";
|
|
|
import axios from "axios"; // 导入 axios
|
|
|
-import { colorSchemes } from "../colors.js";
|
|
|
|
|
|
export const getFaultUnitCharts = async (
|
|
|
data,
|
|
|
@@ -22,88 +21,78 @@ export const getFaultUnitCharts = async (
|
|
|
);
|
|
|
const plotlyContent = await fs.readFile(plotlyPath, "utf-8");
|
|
|
|
|
|
- // 提取故障机组、故障次数和故障时长
|
|
|
- const faultTypes = data.map((item) => item.wind_turbine_name);
|
|
|
- const faultCounts = data.map((item) => item.count);
|
|
|
- const faultDurations = data.map((item) => item.fault_time);
|
|
|
- console.log();
|
|
|
- // 故障次数的散点图数据(左侧 Y 轴)
|
|
|
- const scatterFaultCounts = {
|
|
|
- x: faultTypes.slice(0, 10),
|
|
|
- y: faultCounts.slice(0, 10),
|
|
|
- mode: "markers", // 散点图
|
|
|
- marker: { color: "#64ADC2", size: 10 }, // 蓝色散点
|
|
|
- name: "故障次数",
|
|
|
- hovertemplate: `机组: %{x} <br> 故障次数: %{y} 次<br>`,
|
|
|
- };
|
|
|
+ // 步骤 1:预处理
|
|
|
+ const combined = data.map((item) => ({
|
|
|
+ name: item.wind_turbine_name,
|
|
|
+ count: item.count,
|
|
|
+ durationHour: (item.fault_time / 3600).toFixed(2), // 秒转小时
|
|
|
+ }));
|
|
|
|
|
|
- // 故障时长的散点图数据(右侧 Y 轴)
|
|
|
- const scatterFaultDurations = {
|
|
|
- x: faultTypes.slice(0, 10),
|
|
|
- y: faultDurations.slice(0, 10),
|
|
|
- mode: "markers", // 散点图
|
|
|
- marker: { color: "#1A295D", size: 10 }, // 红色散点
|
|
|
- name: "故障时长",
|
|
|
- yaxis: "y2", // 使用第二个 Y 轴(右侧)
|
|
|
- hovertemplate: `机组: %{x} <br> 故障时长: %{y} 秒<br>`,
|
|
|
- };
|
|
|
+ // 步骤 2:按 name 排序(字典序)
|
|
|
+ combined.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
+
|
|
|
+ // 步骤 3:归一化 count 用于 size
|
|
|
+ const rawSizes = combined.map((d) => d.count);
|
|
|
+ const minSize = 8;
|
|
|
+ const maxSize = 30;
|
|
|
+ const sizeRange = maxSize - minSize;
|
|
|
+ const minValue = Math.min(...rawSizes);
|
|
|
+ const maxValue = Math.max(...rawSizes);
|
|
|
+ const normalizedSizes = rawSizes.map((val) => {
|
|
|
+ if (maxValue === minValue) return (minSize + maxSize) / 2;
|
|
|
+ return ((val - minValue) / (maxValue - minValue)) * sizeRange + minSize;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 步骤 4:生成 plotly 数据
|
|
|
+ const bubbleData = combined.map((d, i) => ({
|
|
|
+ x: [d.name],
|
|
|
+ y: [d.durationHour],
|
|
|
+ mode: "markers",
|
|
|
+ type: "scatter",
|
|
|
+ name: d.name,
|
|
|
+ marker: {
|
|
|
+ size: normalizedSizes[i],
|
|
|
+ sizemode: "area",
|
|
|
+ sizeref: 1,
|
|
|
+ sizemin: 4,
|
|
|
+ showscale: false,
|
|
|
+ },
|
|
|
+ hovertemplate: `机组: ${d.name}<br>故障时长: ${d.durationHour} 小时<br>故障次数: ${d.count} 次<extra></extra>`,
|
|
|
+ }));
|
|
|
|
|
|
- // 布局配置,设置双 Y 轴
|
|
|
const layout = {
|
|
|
title: {
|
|
|
- text: "机组故障次数与时长分析Top10",
|
|
|
- font: {
|
|
|
- size: 16,
|
|
|
- weight: "bold",
|
|
|
- },
|
|
|
+ text: "机组故障时长与故障次数分析",
|
|
|
+ font: { size: 16, weight: "bold" },
|
|
|
},
|
|
|
xaxis: {
|
|
|
- title: {
|
|
|
- text: "故障机组",
|
|
|
- },
|
|
|
+ title: "故障机组",
|
|
|
+ type: "category",
|
|
|
tickangle: 30,
|
|
|
- tickmode: "array",
|
|
|
- tickvals: faultTypes.slice(0, 10), // 保证这里是字符串数组
|
|
|
- ticktext: faultTypes.slice(0, 10), // 确保 ticktext 使用相同的标签
|
|
|
tickfont: { size: 12 },
|
|
|
- type: "category", // 让 Y 轴按类别均匀分布
|
|
|
gridcolor: "rgb(255,255,255)",
|
|
|
tickcolor: "rgb(255,255,255)",
|
|
|
backgroundcolor: "#e5ecf6",
|
|
|
+ showbackground: true,
|
|
|
},
|
|
|
yaxis: {
|
|
|
- title: {
|
|
|
- text: "故障次数",
|
|
|
- },
|
|
|
- titlefont: { color: "#64ADC2" },
|
|
|
- tickfont: { color: "#64ADC2" },
|
|
|
- side: "left", // 左侧的 Y 轴
|
|
|
- showline: true,
|
|
|
- linecolor: "#64ADC2",
|
|
|
+ title: "故障时长(小时)",
|
|
|
+ tickfont: { size: 12 },
|
|
|
gridcolor: "rgb(255,255,255)",
|
|
|
tickcolor: "rgb(255,255,255)",
|
|
|
backgroundcolor: "#e5ecf6",
|
|
|
- },
|
|
|
- yaxis2: {
|
|
|
- title: {
|
|
|
- text: "故障时长(秒)",
|
|
|
- },
|
|
|
- titlefont: { color: "#1A295D" },
|
|
|
- tickfont: { color: "#1A295D" },
|
|
|
- showgrid: false, // 隐藏 Y 轴网格线
|
|
|
- overlaying: "y", // 在第一个 Y 轴上方绘制
|
|
|
- side: "right", // 右侧的 Y 轴
|
|
|
- position: 1, // 调整右侧轴的位置
|
|
|
- showline: true,
|
|
|
- linecolor: "#1A295D", // 设置右侧轴线颜色
|
|
|
+ showbackground: true,
|
|
|
},
|
|
|
plot_bgcolor: "#e5ecf6",
|
|
|
gridcolor: "#fff",
|
|
|
- bgcolor: "#e5ecf6", // 设置背景颜色
|
|
|
- showlegend: false, // 显示图例
|
|
|
- margin: {
|
|
|
- t: 80, // 上边距
|
|
|
- b: 150, // 下边距,给 X 轴标签更多空间
|
|
|
+ margin: { t: 80, b: 120 },
|
|
|
+ showlegend: true,
|
|
|
+ legendgroup: "same",
|
|
|
+ legend: {
|
|
|
+ itemsizing: "constant",
|
|
|
+ font: {
|
|
|
+ size: 12,
|
|
|
+ },
|
|
|
},
|
|
|
};
|
|
|
|
|
|
@@ -139,11 +128,9 @@ export const getFaultUnitCharts = async (
|
|
|
<div id="chart"></div>
|
|
|
<script>
|
|
|
window.onload = function() {
|
|
|
- Plotly.newPlot('chart', [${JSON.stringify(
|
|
|
- scatterFaultCounts
|
|
|
- )}, ${JSON.stringify(scatterFaultDurations)}], ${JSON.stringify(
|
|
|
- layout
|
|
|
- )}).then(() => {
|
|
|
+ Plotly.newPlot('chart', ${JSON.stringify(
|
|
|
+ bubbleData
|
|
|
+ )}, ${JSON.stringify(layout)}).then(() => {
|
|
|
window.chartRendered = true;
|
|
|
});
|
|
|
};
|