|
@@ -2,6 +2,7 @@ import * as echarts from '../../components/ec-canvas/echarts';
|
|
|
|
|
|
Page({
|
|
Page({
|
|
data: {
|
|
data: {
|
|
|
|
+ initScatterData : [],
|
|
ecLine: {
|
|
ecLine: {
|
|
onInit: function (canvas, width, height, dpr) {
|
|
onInit: function (canvas, width, height, dpr) {
|
|
const lineChart = echarts.init(canvas, null, {
|
|
const lineChart = echarts.init(canvas, null, {
|
|
@@ -20,10 +21,12 @@ Page({
|
|
const initScatter = echarts.init(canvas, null, {
|
|
const initScatter = echarts.init(canvas, null, {
|
|
width: width,
|
|
width: width,
|
|
height: height,
|
|
height: height,
|
|
- devicePixelRatio: dpr // new
|
|
|
|
|
|
+ devicePixelRatio: dpr
|
|
});
|
|
});
|
|
canvas.setChart(initScatter);
|
|
canvas.setChart(initScatter);
|
|
- initScatter.setOption(getInitScatterOption());
|
|
|
|
|
|
+ getInitScatterOption().then(option => {
|
|
|
|
+ initScatter.setOption(option)
|
|
|
|
+ });
|
|
|
|
|
|
return initScatter;
|
|
return initScatter;
|
|
}
|
|
}
|
|
@@ -36,7 +39,9 @@ Page({
|
|
devicePixelRatio: dpr // new
|
|
devicePixelRatio: dpr // new
|
|
});
|
|
});
|
|
canvas.setChart(midScatter);
|
|
canvas.setChart(midScatter);
|
|
- midScatter.setOption(getMidScatterOption());
|
|
|
|
|
|
+ getMidScatterOption().then(option => {
|
|
|
|
+ midScatter.setOption(option)
|
|
|
|
+ });
|
|
|
|
|
|
return midScatter;
|
|
return midScatter;
|
|
}
|
|
}
|
|
@@ -49,7 +54,9 @@ Page({
|
|
devicePixelRatio: dpr // new
|
|
devicePixelRatio: dpr // new
|
|
});
|
|
});
|
|
canvas.setChart(finalScatter);
|
|
canvas.setChart(finalScatter);
|
|
- finalScatter.setOption(getFinalScatterOption());
|
|
|
|
|
|
+ getFinalScatterOption().then(option => {
|
|
|
|
+ finalScatter.setOption(option)
|
|
|
|
+ });
|
|
|
|
|
|
return finalScatter;
|
|
return finalScatter;
|
|
}
|
|
}
|
|
@@ -61,253 +68,440 @@ Page({
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
-// 降酸模型 初代 散点图
|
|
|
|
|
|
+
|
|
function getInitScatterOption() {
|
|
function getInitScatterOption() {
|
|
- const calculateDataRange = (data) => {
|
|
|
|
- let xValues = data.map(item => item[0]);
|
|
|
|
- let yValues = data.map(item => item[1]);
|
|
|
|
-
|
|
|
|
- return {
|
|
|
|
- xMin: Math.min(...xValues),
|
|
|
|
- xMax: Math.max(...xValues),
|
|
|
|
- yMin: Math.min(...yValues),
|
|
|
|
- yMax: Math.max(...yValues)
|
|
|
|
- };
|
|
|
|
- };
|
|
|
|
|
|
+ const fetchScatterData = () => {
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
+ wx.request({
|
|
|
|
+ url: 'https://soilgd.com:5000/model-scatter-data/7',
|
|
|
|
+ method: 'GET',
|
|
|
|
+ timeout: 5000,
|
|
|
|
+ success: (res) => {
|
|
|
|
+ console.log('接口响应:', res);
|
|
|
|
+ // 校验状态码
|
|
|
|
+ if (res.statusCode !== 200) {
|
|
|
|
+ reject(new Error(`请求失败,状态码: ${res.statusCode}`));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- const scatterData = [[0.12931, 0.10315928999999999], [0.066298, 0.10226514000000003], [0.057692, 0.10226514000000003], [0.072464, 0.10339078000000003], [0.146414, 0.10000317000000003], [0.087263, 0.09199080000000004], [0.096983, 0.09947644], [0.070505, 0.10142657000000004], [0.052497, 0.09956722000000007], [0.166515, 0.10179712], [0.063291, 0.10339078000000003]];
|
|
|
|
|
|
+ // 校验数据结构
|
|
|
|
+ if (!res.data?.scatter_data || !Array.isArray(res.data.scatter_data)) {
|
|
|
|
+ reject(new Error('接口数据格式错误'));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- const range = calculateDataRange(scatterData);
|
|
|
|
- const padding = 0.1;
|
|
|
|
- const xMin = range.xMin - Math.abs(range.xMin * padding);
|
|
|
|
- const xMax = range.xMax + Math.abs(range.xMax * padding);
|
|
|
|
- const yMin = range.yMin - Math.abs(range.yMin * padding);
|
|
|
|
- const yMax = range.yMax + Math.abs(range.yMax * padding);
|
|
|
|
- const min = Math.min(xMin, yMin)
|
|
|
|
- const max = Math.max(xMax, yMax)
|
|
|
|
- return {
|
|
|
|
- tooltip: {
|
|
|
|
- trigger: 'axis',
|
|
|
|
- axisPointer: {
|
|
|
|
- type: 'cross'
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- legend: {
|
|
|
|
- data: ['True vs Predicted']
|
|
|
|
- },
|
|
|
|
- grid: {
|
|
|
|
- left: '4%',
|
|
|
|
- right: '22%',
|
|
|
|
- bottom: '3%',
|
|
|
|
- containLabel: true
|
|
|
|
- },
|
|
|
|
- xAxis: {
|
|
|
|
- name: 'True Values',
|
|
|
|
- type: 'value',
|
|
|
|
- min: min,
|
|
|
|
- max: max
|
|
|
|
- },
|
|
|
|
- yAxis: {
|
|
|
|
- name: 'Predicted Values',
|
|
|
|
- type: 'value',
|
|
|
|
- min: parseFloat(min).toFixed(2),
|
|
|
|
- max: parseFloat(max).toFixed(2)
|
|
|
|
- },
|
|
|
|
- series: [
|
|
|
|
- {
|
|
|
|
- name: 'True vs Predicted',
|
|
|
|
- type: 'scatter',
|
|
|
|
- data: scatterData,
|
|
|
|
- symbolSize: 10,
|
|
|
|
- itemStyle: {
|
|
|
|
- color: '#1f77b4',
|
|
|
|
- opacity: 0.7
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- name: 'Trendline',
|
|
|
|
- type: 'line',
|
|
|
|
- data: [
|
|
|
|
- [min, min],
|
|
|
|
- [max, max]
|
|
|
|
- ],
|
|
|
|
- lineStyle: {
|
|
|
|
- type: 'dashed',
|
|
|
|
- color: '#ff7f0e',
|
|
|
|
- width: 2
|
|
|
|
|
|
+ resolve(res.data.scatter_data);
|
|
|
|
+ },
|
|
|
|
+ fail: (err) => {
|
|
|
|
+ reject(new Error(`网络错误: ${err.errMsg}`));
|
|
}
|
|
}
|
|
- }
|
|
|
|
- ]
|
|
|
|
|
|
+ });
|
|
|
|
+ });
|
|
};
|
|
};
|
|
-}
|
|
|
|
-
|
|
|
|
-// 降酸模型 中间代 散点图
|
|
|
|
-function getMidScatterOption() {
|
|
|
|
- const calculateDataRange = (data) => {
|
|
|
|
- let xValues = data.map(item => item[0]);
|
|
|
|
- let yValues = data.map(item => item[1]);
|
|
|
|
-
|
|
|
|
- return {
|
|
|
|
- xMin: Math.min(...xValues),
|
|
|
|
- xMax: Math.max(...xValues),
|
|
|
|
- yMin: Math.min(...yValues),
|
|
|
|
- yMax: Math.max(...yValues)
|
|
|
|
|
|
+
|
|
|
|
+ // 核心计算逻辑
|
|
|
|
+ const calculateChartOptions = (scatterData) => {
|
|
|
|
+ const calculateDataRange = (data) => {
|
|
|
|
+ const xValues = data.map(item => item[0]);
|
|
|
|
+ const yValues = data.map(item => item[1]);
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ xMin: Math.min(...xValues),
|
|
|
|
+ xMax: Math.max(...xValues),
|
|
|
|
+ yMin: Math.min(...yValues),
|
|
|
|
+ yMax: Math.max(...yValues)
|
|
|
|
+ };
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const range = calculateDataRange(scatterData);
|
|
|
|
+ console.log(scatterData)
|
|
|
|
+ const padding = 0.1;
|
|
|
|
+ const xMin = range.xMin - Math.abs(range.xMin * padding);
|
|
|
|
+ const xMax = range.xMax + Math.abs(range.xMax * padding);
|
|
|
|
+ const yMin = range.yMin - Math.abs(range.yMin * padding);
|
|
|
|
+ const yMax = range.yMax + Math.abs(range.yMax * padding);
|
|
|
|
+ const axisMin = Math.min(xMin, yMin);
|
|
|
|
+ const axisMax = Math.max(xMax, yMax);
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ tooltip: {
|
|
|
|
+ trigger: 'axis',
|
|
|
|
+ axisPointer: { type: 'cross' }
|
|
|
|
+ },
|
|
|
|
+ grid: {
|
|
|
|
+ left: '3%',
|
|
|
|
+ right: '22%',
|
|
|
|
+ bottom: '3%',
|
|
|
|
+ containLabel: true
|
|
|
|
+ },
|
|
|
|
+ xAxis: {
|
|
|
|
+ name: 'True Values',
|
|
|
|
+ type: 'value',
|
|
|
|
+ min: axisMin,
|
|
|
|
+ max: axisMax,
|
|
|
|
+ axisLabel: {
|
|
|
|
+ formatter: value => parseFloat(value).toFixed(2)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ yAxis: {
|
|
|
|
+ name: 'Predicted Values',
|
|
|
|
+ type: 'value',
|
|
|
|
+ min: parseFloat(axisMin).toFixed(2),
|
|
|
|
+ max: parseFloat(axisMax).toFixed(2)
|
|
|
|
+ },
|
|
|
|
+ series: [
|
|
|
|
+ {
|
|
|
|
+ name: 'True vs Predicted',
|
|
|
|
+ type: 'scatter',
|
|
|
|
+ data: scatterData,
|
|
|
|
+ symbolSize: 10,
|
|
|
|
+ itemStyle: {
|
|
|
|
+ color: '#1f77b4',
|
|
|
|
+ opacity: 0.7,
|
|
|
|
+ borderColor: '#fff',
|
|
|
|
+ borderWidth: 0.5
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: 'Trendline',
|
|
|
|
+ type: 'line',
|
|
|
|
+ data: [[axisMin, axisMin], [axisMax, axisMax]],
|
|
|
|
+ lineStyle: {
|
|
|
|
+ type: 'dashed',
|
|
|
|
+ color: '#ff7f0e',
|
|
|
|
+ width: 2
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ ]
|
|
|
|
+ };
|
|
};
|
|
};
|
|
- };
|
|
|
|
-
|
|
|
|
- const scatterData = [[0.12931, 0.09595878000000002], [0.066298, 0.10344700000000003], [0.057692, 0.10344700000000003], [0.072464, 0.09011803], [0.146414, 0.0853504500000001], [0.087263, 0.07407179000000012], [0.096983, 0.10581049999999995], [0.070505, 0.09876380000000004], [0.052497, 0.08568465000000008], [0.166515, 0.13348440999999997], [0.063291, 0.09011803]];
|
|
|
|
|
|
+
|
|
|
|
+ return new Promise(async (resolve) => {
|
|
|
|
+ let retryCount = 0;
|
|
|
|
+ const maxRetries = 2;
|
|
|
|
|
|
- const range = calculateDataRange(scatterData);
|
|
|
|
- const padding = 0.1;
|
|
|
|
- const xMin = range.xMin - Math.abs(range.xMin * padding);
|
|
|
|
- const xMax = range.xMax + Math.abs(range.xMax * padding);
|
|
|
|
- const yMin = range.yMin - Math.abs(range.yMin * padding);
|
|
|
|
- const yMax = range.yMax + Math.abs(range.yMax * padding);
|
|
|
|
- const min = Math.min(xMin, yMin)
|
|
|
|
- const max = Math.max(xMax, yMax)
|
|
|
|
- return {
|
|
|
|
- tooltip: {
|
|
|
|
- trigger: 'axis',
|
|
|
|
- axisPointer: {
|
|
|
|
- type: 'cross'
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- legend: {
|
|
|
|
- data: ['True vs Predicted']
|
|
|
|
- },
|
|
|
|
- grid: {
|
|
|
|
- left: '4%',
|
|
|
|
- right: '22%',
|
|
|
|
- bottom: '3%',
|
|
|
|
- containLabel: true
|
|
|
|
- },
|
|
|
|
- xAxis: {
|
|
|
|
- name: 'True Values',
|
|
|
|
- type: 'value',
|
|
|
|
- min: min,
|
|
|
|
- max: max
|
|
|
|
- },
|
|
|
|
- yAxis: {
|
|
|
|
- name: 'Predicted Values',
|
|
|
|
- type: 'value',
|
|
|
|
- min: parseFloat(min).toFixed(2),
|
|
|
|
- max: parseFloat(max).toFixed(2)
|
|
|
|
- },
|
|
|
|
- series: [
|
|
|
|
- {
|
|
|
|
- name: 'True vs Predicted',
|
|
|
|
- type: 'scatter',
|
|
|
|
- data: scatterData,
|
|
|
|
- symbolSize: 10,
|
|
|
|
- itemStyle: {
|
|
|
|
- color: '#1f77b4',
|
|
|
|
- opacity: 0.7
|
|
|
|
|
|
+ while (retryCount <= maxRetries) {
|
|
|
|
+ try {
|
|
|
|
+ const scatterData = await fetchScatterData();
|
|
|
|
+ resolve(calculateChartOptions(scatterData));
|
|
|
|
+ return;
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error(`第 ${retryCount + 1} 次尝试失败:`, error);
|
|
|
|
+
|
|
|
|
+ if (retryCount === maxRetries) {
|
|
|
|
+ resolve({
|
|
|
|
+ xAxis: { show: false },
|
|
|
|
+ yAxis: { show: false },
|
|
|
|
+ series: [{
|
|
|
|
+ type: 'scatter',
|
|
|
|
+ data: [],
|
|
|
|
+ silent: true
|
|
|
|
+ }],
|
|
|
|
+ graphic: {
|
|
|
|
+ type: 'text',
|
|
|
|
+ text: '数据加载失败',
|
|
|
|
+ }
|
|
|
|
+ })
|
|
}
|
|
}
|
|
- },
|
|
|
|
- {
|
|
|
|
- name: 'Trendline',
|
|
|
|
- type: 'line',
|
|
|
|
- data: [
|
|
|
|
- [min, min],
|
|
|
|
- [max, max]
|
|
|
|
- ],
|
|
|
|
- lineStyle: {
|
|
|
|
- type: 'dashed',
|
|
|
|
- color: '#ff7f0e',
|
|
|
|
- width: 2
|
|
|
|
|
|
+ retryCount++;
|
|
|
|
+ await new Promise(r => setTimeout(r, 1000)); // 1秒后重试
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- ]
|
|
|
|
- };
|
|
|
|
-}
|
|
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+// 反酸模型 中间代 散点图
|
|
|
|
+function getMidScatterOption() {
|
|
|
|
+ /**
|
|
|
|
+ * 计算数据的最大最小值
|
|
|
|
+ * @param {Array} data - 散点数据数组
|
|
|
|
+ * @returns {Object} 包含 xMin, xMax, yMin, yMax 的对象
|
|
|
|
+ */
|
|
|
|
+ const fetchScatterData = () => {
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
+ wx.request({
|
|
|
|
+ url: 'https://soilgd.com:5000/model-scatter-data/6',
|
|
|
|
+ method: 'GET',
|
|
|
|
+ timeout: 5000,
|
|
|
|
+ success: (res) => {
|
|
|
|
+ console.log('接口响应:', res);
|
|
|
|
+ // 校验状态码
|
|
|
|
+ if (res.statusCode !== 200) {
|
|
|
|
+ reject(new Error(`请求失败,状态码: ${res.statusCode}`));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
-// 降酸模型散点图
|
|
|
|
-function getFinalScatterOption() {
|
|
|
|
- const calculateDataRange = (data) => {
|
|
|
|
- let xValues = data.map(item => item[0]);
|
|
|
|
- let yValues = data.map(item => item[1]);
|
|
|
|
-
|
|
|
|
- return {
|
|
|
|
- xMin: Math.min(...xValues),
|
|
|
|
- xMax: Math.max(...xValues),
|
|
|
|
- yMin: Math.min(...yValues),
|
|
|
|
- yMax: Math.max(...yValues)
|
|
|
|
- };
|
|
|
|
- };
|
|
|
|
|
|
+ // 校验数据结构
|
|
|
|
+ if (!res.data?.scatter_data || !Array.isArray(res.data.scatter_data)) {
|
|
|
|
+ reject(new Error('接口数据格式错误'));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- const scatterData = [[0.12931, 0.1144982841836412], [0.066298, 0.07733075000000009],
|
|
|
|
- [0.057692, 0.07784833000000009], [0.072464, 0.09429906104591025],
|
|
|
|
- [0.146414, 0.11774272000000004], [0.087263, 0.07587641627546172],
|
|
|
|
- [0.096983, 0.12344755999999983], [0.070505, 0.06424743000000006],
|
|
|
|
- [0.052497, 0.07665224568865422], [0.166515, 0.15591779999999988],
|
|
|
|
- [0.063291, 0.09275175104591024]];
|
|
|
|
|
|
+ resolve(res.data.scatter_data);
|
|
|
|
+ },
|
|
|
|
+ fail: (err) => {
|
|
|
|
+ reject(new Error(`网络错误: ${err.errMsg}`));
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // 核心计算逻辑
|
|
|
|
+ const calculateChartOptions = (scatterData) => {
|
|
|
|
+ const calculateDataRange = (data) => {
|
|
|
|
+ const xValues = data.map(item => item[0]);
|
|
|
|
+ const yValues = data.map(item => item[1]);
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ xMin: Math.min(...xValues),
|
|
|
|
+ xMax: Math.max(...xValues),
|
|
|
|
+ yMin: Math.min(...yValues),
|
|
|
|
+ yMax: Math.max(...yValues)
|
|
|
|
+ };
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const range = calculateDataRange(scatterData);
|
|
|
|
+ console.log(scatterData)
|
|
|
|
+ const padding = 0.1;
|
|
|
|
+ const xMin = range.xMin - Math.abs(range.xMin * padding);
|
|
|
|
+ const xMax = range.xMax + Math.abs(range.xMax * padding);
|
|
|
|
+ const yMin = range.yMin - Math.abs(range.yMin * padding);
|
|
|
|
+ const yMax = range.yMax + Math.abs(range.yMax * padding);
|
|
|
|
+ const axisMin = Math.min(xMin, yMin);
|
|
|
|
+ const axisMax = Math.max(xMax, yMax);
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ tooltip: {
|
|
|
|
+ trigger: 'axis',
|
|
|
|
+ axisPointer: { type: 'cross' }
|
|
|
|
+ },
|
|
|
|
+ grid: {
|
|
|
|
+ left: '3%',
|
|
|
|
+ right: '22%',
|
|
|
|
+ bottom: '3%',
|
|
|
|
+ containLabel: true
|
|
|
|
+ },
|
|
|
|
+ xAxis: {
|
|
|
|
+ name: 'True Values',
|
|
|
|
+ type: 'value',
|
|
|
|
+ min: axisMin,
|
|
|
|
+ max: axisMax,
|
|
|
|
+ axisLabel: {
|
|
|
|
+ formatter: value => parseFloat(value).toFixed(2)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ yAxis: {
|
|
|
|
+ name: 'Predicted Values',
|
|
|
|
+ type: 'value',
|
|
|
|
+ min: parseFloat(axisMin).toFixed(2),
|
|
|
|
+ max: parseFloat(axisMax).toFixed(2)
|
|
|
|
+ },
|
|
|
|
+ series: [
|
|
|
|
+ {
|
|
|
|
+ name: 'True vs Predicted',
|
|
|
|
+ type: 'scatter',
|
|
|
|
+ data: scatterData,
|
|
|
|
+ symbolSize: 10,
|
|
|
|
+ itemStyle: {
|
|
|
|
+ color: '#1f77b4',
|
|
|
|
+ opacity: 0.7,
|
|
|
|
+ borderColor: '#fff',
|
|
|
|
+ borderWidth: 0.5
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: 'Trendline',
|
|
|
|
+ type: 'line',
|
|
|
|
+ data: [[axisMin, axisMin], [axisMax, axisMax]],
|
|
|
|
+ lineStyle: {
|
|
|
|
+ type: 'dashed',
|
|
|
|
+ color: '#ff7f0e',
|
|
|
|
+ width: 2
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ ]
|
|
|
|
+ };
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ return new Promise(async (resolve) => {
|
|
|
|
+ let retryCount = 0;
|
|
|
|
+ const maxRetries = 2;
|
|
|
|
|
|
- const range = calculateDataRange(scatterData);
|
|
|
|
- const padding = 0.1;
|
|
|
|
- const xMin = range.xMin - Math.abs(range.xMin * padding);
|
|
|
|
- const xMax = range.xMax + Math.abs(range.xMax * padding);
|
|
|
|
- const yMin = range.yMin - Math.abs(range.yMin * padding);
|
|
|
|
- const yMax = range.yMax + Math.abs(range.yMax * padding);
|
|
|
|
- const min = Math.min(xMin, yMin)
|
|
|
|
- const max = Math.max(xMax, yMax)
|
|
|
|
- return {
|
|
|
|
- tooltip: {
|
|
|
|
- trigger: 'axis',
|
|
|
|
- axisPointer: {
|
|
|
|
- type: 'cross'
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- legend: {
|
|
|
|
- data: ['True vs Predicted']
|
|
|
|
- },
|
|
|
|
- grid: {
|
|
|
|
- left: '4%',
|
|
|
|
- right: '22%',
|
|
|
|
- bottom: '3%',
|
|
|
|
- containLabel: true
|
|
|
|
- },
|
|
|
|
- xAxis: {
|
|
|
|
- name: 'True Values',
|
|
|
|
- type: 'value',
|
|
|
|
- min: min,
|
|
|
|
- max: max
|
|
|
|
- },
|
|
|
|
- yAxis: {
|
|
|
|
- name: 'Predicted Values',
|
|
|
|
- type: 'value',
|
|
|
|
- min: parseFloat(min).toFixed(2),
|
|
|
|
- max: parseFloat(max).toFixed(2)
|
|
|
|
- },
|
|
|
|
- series: [
|
|
|
|
- {
|
|
|
|
- name: 'True vs Predicted',
|
|
|
|
- type: 'scatter',
|
|
|
|
- data: scatterData,
|
|
|
|
- symbolSize: 10,
|
|
|
|
- itemStyle: {
|
|
|
|
- color: '#1f77b4',
|
|
|
|
- opacity: 0.7
|
|
|
|
|
|
+ while (retryCount <= maxRetries) {
|
|
|
|
+ try {
|
|
|
|
+ const scatterData = await fetchScatterData();
|
|
|
|
+ resolve(calculateChartOptions(scatterData));
|
|
|
|
+ return;
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error(`第 ${retryCount + 1} 次尝试失败:`, error);
|
|
|
|
+
|
|
|
|
+ if (retryCount === maxRetries) {
|
|
|
|
+ resolve({
|
|
|
|
+ xAxis: { show: false },
|
|
|
|
+ yAxis: { show: false },
|
|
|
|
+ series: [{
|
|
|
|
+ type: 'scatter',
|
|
|
|
+ data: [],
|
|
|
|
+ silent: true
|
|
|
|
+ }],
|
|
|
|
+ graphic: {
|
|
|
|
+ type: 'text',
|
|
|
|
+ text: '数据加载失败',
|
|
|
|
+ }
|
|
|
|
+ })
|
|
}
|
|
}
|
|
- },
|
|
|
|
- {
|
|
|
|
- name: 'Trendline',
|
|
|
|
- type: 'line',
|
|
|
|
- data: [
|
|
|
|
- [min, min],
|
|
|
|
- [max, max]
|
|
|
|
- ],
|
|
|
|
- lineStyle: {
|
|
|
|
- type: 'dashed',
|
|
|
|
- color: '#ff7f0e',
|
|
|
|
- width: 2
|
|
|
|
|
|
+ retryCount++;
|
|
|
|
+ await new Promise(r => setTimeout(r, 1000)); // 1秒后重试
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- ]
|
|
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+// 反酸模型 最终代 散点图
|
|
|
|
+function getFinalScatterOption() {
|
|
|
|
+ /**
|
|
|
|
+ * 计算数据的最大最小值
|
|
|
|
+ * @param {Array} data - 散点数据数组
|
|
|
|
+ * @returns {Object} 包含 xMin, xMax, yMin, yMax 的对象
|
|
|
|
+ */
|
|
|
|
+ const fetchScatterData = () => {
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
+ wx.request({
|
|
|
|
+ url: 'https://soilgd.com:5000/model-scatter-data/25',
|
|
|
|
+ method: 'GET',
|
|
|
|
+ timeout: 5000,
|
|
|
|
+ success: (res) => {
|
|
|
|
+ console.log('接口响应:', res);
|
|
|
|
+ // 校验状态码
|
|
|
|
+ if (res.statusCode !== 200) {
|
|
|
|
+ reject(new Error(`请求失败,状态码: ${res.statusCode}`));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 校验数据结构
|
|
|
|
+ if (!res.data?.scatter_data || !Array.isArray(res.data.scatter_data)) {
|
|
|
|
+ reject(new Error('接口数据格式错误'));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ resolve(res.data.scatter_data);
|
|
|
|
+ },
|
|
|
|
+ fail: (err) => {
|
|
|
|
+ reject(new Error(`网络错误: ${err.errMsg}`));
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ });
|
|
};
|
|
};
|
|
-}
|
|
|
|
|
|
+
|
|
|
|
+ // 核心计算逻辑
|
|
|
|
+ const calculateChartOptions = (scatterData) => {
|
|
|
|
+ const calculateDataRange = (data) => {
|
|
|
|
+ const xValues = data.map(item => item[0]);
|
|
|
|
+ const yValues = data.map(item => item[1]);
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ xMin: Math.min(...xValues),
|
|
|
|
+ xMax: Math.max(...xValues),
|
|
|
|
+ yMin: Math.min(...yValues),
|
|
|
|
+ yMax: Math.max(...yValues)
|
|
|
|
+ };
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const range = calculateDataRange(scatterData);
|
|
|
|
+ console.log(scatterData)
|
|
|
|
+ const padding = 0.1;
|
|
|
|
+ const xMin = range.xMin - Math.abs(range.xMin * padding);
|
|
|
|
+ const xMax = range.xMax + Math.abs(range.xMax * padding);
|
|
|
|
+ const yMin = range.yMin - Math.abs(range.yMin * padding);
|
|
|
|
+ const yMax = range.yMax + Math.abs(range.yMax * padding);
|
|
|
|
+ const axisMin = Math.min(xMin, yMin);
|
|
|
|
+ const axisMax = Math.max(xMax, yMax);
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ tooltip: {
|
|
|
|
+ trigger: 'axis',
|
|
|
|
+ axisPointer: { type: 'cross' }
|
|
|
|
+ },
|
|
|
|
+ grid: {
|
|
|
|
+ left: '3%',
|
|
|
|
+ right: '22%',
|
|
|
|
+ bottom: '3%',
|
|
|
|
+ containLabel: true
|
|
|
|
+ },
|
|
|
|
+ xAxis: {
|
|
|
|
+ name: 'True Values',
|
|
|
|
+ type: 'value',
|
|
|
|
+ min: axisMin,
|
|
|
|
+ max: axisMax,
|
|
|
|
+ axisLabel: {
|
|
|
|
+ formatter: value => parseFloat(value).toFixed(2)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ yAxis: {
|
|
|
|
+ name: 'Predicted Values',
|
|
|
|
+ type: 'value',
|
|
|
|
+ min: parseFloat(axisMin).toFixed(2),
|
|
|
|
+ max: parseFloat(axisMax).toFixed(2)
|
|
|
|
+ },
|
|
|
|
+ series: [
|
|
|
|
+ {
|
|
|
|
+ name: 'True vs Predicted',
|
|
|
|
+ type: 'scatter',
|
|
|
|
+ data: scatterData,
|
|
|
|
+ symbolSize: 10,
|
|
|
|
+ itemStyle: {
|
|
|
|
+ color: '#1f77b4',
|
|
|
|
+ opacity: 0.7,
|
|
|
|
+ borderColor: '#fff',
|
|
|
|
+ borderWidth: 0.5
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: 'Trendline',
|
|
|
|
+ type: 'line',
|
|
|
|
+ data: [[axisMin, axisMin], [axisMax, axisMax]],
|
|
|
|
+ lineStyle: {
|
|
|
|
+ type: 'dashed',
|
|
|
|
+ color: '#ff7f0e',
|
|
|
|
+ width: 2
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ ]
|
|
|
|
+ };
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ return new Promise(async (resolve) => {
|
|
|
|
+ let retryCount = 0;
|
|
|
|
+ const maxRetries = 2;
|
|
|
|
|
|
|
|
+ while (retryCount <= maxRetries) {
|
|
|
|
+ try {
|
|
|
|
+ const scatterData = await fetchScatterData();
|
|
|
|
+ resolve(calculateChartOptions(scatterData));
|
|
|
|
+ return;
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error(`第 ${retryCount + 1} 次尝试失败:`, error);
|
|
|
|
+
|
|
|
|
+ if (retryCount === maxRetries) {
|
|
|
|
+ resolve({
|
|
|
|
+ xAxis: { show: false },
|
|
|
|
+ yAxis: { show: false },
|
|
|
|
+ series: [{
|
|
|
|
+ type: 'scatter',
|
|
|
|
+ data: [],
|
|
|
|
+ silent: true
|
|
|
|
+ }],
|
|
|
|
+ graphic: {
|
|
|
|
+ type: 'text',
|
|
|
|
+ text: '数据加载失败',
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ retryCount++;
|
|
|
|
+ await new Promise(r => setTimeout(r, 1000)); // 1秒后重试
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
|
|
-// 降酸模型折线图
|
|
|
|
function getLineOption() {
|
|
function getLineOption() {
|
|
return {
|
|
return {
|
|
tooltip: {
|
|
tooltip: {
|
|
@@ -336,18 +530,18 @@ function getLineOption() {
|
|
{
|
|
{
|
|
name: 'Random Forest',
|
|
name: 'Random Forest',
|
|
type: 'line',
|
|
type: 'line',
|
|
- data: [-0.07014332070467688, 0.16174446067644666, 0.45539363923645115, 0.42496898634299696, 0.4538427686692541, 0.418902219699232, 0.3944331740214546, 0.5036773554206873, 0.6231911298905934, 0.7017514238881619]
|
|
|
|
|
|
+ data: [-0.17101591951095463, -0.556719360354051, -0.04083550751401055, -0.20858221504075436, 0.07297292282221035, 0.19857845644421734, 0.28407131176770184, 0.27979356883596496, 0.36904808817286416, 0.4183018571701477] // 使用您的实际R2分数数据
|
|
},
|
|
},
|
|
{
|
|
{
|
|
name: 'XGBoost',
|
|
name: 'XGBoost',
|
|
type: 'line',
|
|
type: 'line',
|
|
- data: [-0.5854699949971149, 0.12632204933742897, 0.5552415957727412, 0.36024885147666674, 0.3983302490476677, 0.11693728875627551, 0.41317321044147026, 0.7833174829404705, 0.6626050730438451, 0.8168196535959388]
|
|
|
|
|
|
+ data: [-1.1811781145886937, -1.5645641005612534, -0.12619079632263497, 0.03324096120721032, 0.06969290639267578, 0.12375262461601955, 0.5331670468884062, 0.49454793164801647, 0.31904329339597803, 0.2712670704381914]
|
|
},
|
|
},
|
|
{
|
|
{
|
|
name: 'Gradient Boosting',
|
|
name: 'Gradient Boosting',
|
|
type: 'line',
|
|
type: 'line',
|
|
- data: [-0.2099996080229254, 0.2604127444757308, 0.5544068626708099, 0.37487088504748367, 0.32309657868722486, 0.24740671740183884, 0.4949107161199925, 0.694806526591159, 0.6719430144475025, 0.7889677514137288]
|
|
|
|
|
|
+ data: [-0.8583039298789095, -1.073316171952042, 0.09659300885027666, 0.06097833957434784, 0.191975498544109, 0.3718334600546489, 0.3948098332187753, 0.4398778520728397, 0.452609022210963, 0.41484634172723023]
|
|
}
|
|
}
|
|
]
|
|
]
|
|
};
|
|
};
|
|
-}
|
|
|
|
|
|
+}
|