Soil Acid Reduction Iterative Evolution.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. import * as echarts from '../../components/ec-canvas/echarts';
  2. Page({
  3. data: {
  4. initScatterData : [],
  5. ecLine: {
  6. onInit: function (canvas, width, height, dpr) {
  7. const lineChart = echarts.init(canvas, null, {
  8. width: width,
  9. height: height,
  10. devicePixelRatio: dpr // new
  11. });
  12. canvas.setChart(lineChart);
  13. lineChart.setOption(getLineOption());
  14. return lineChart;
  15. }
  16. },
  17. ecInitScatter: {
  18. onInit: function (canvas, width, height, dpr) {
  19. const initScatter = echarts.init(canvas, null, {
  20. width: width,
  21. height: height,
  22. devicePixelRatio: dpr
  23. });
  24. canvas.setChart(initScatter);
  25. getInitScatterOption().then(option => {
  26. initScatter.setOption(option)
  27. });
  28. return initScatter;
  29. }
  30. },
  31. ecMidScatter: {
  32. onInit: function (canvas, width, height, dpr) {
  33. const midScatter = echarts.init(canvas, null, {
  34. width: width,
  35. height: height,
  36. devicePixelRatio: dpr // new
  37. });
  38. canvas.setChart(midScatter);
  39. getMidScatterOption().then(option => {
  40. midScatter.setOption(option)
  41. });
  42. return midScatter;
  43. }
  44. },
  45. ecFinalScatter: {
  46. onInit: function (canvas, width, height, dpr) {
  47. const finalScatter = echarts.init(canvas, null, {
  48. width: width,
  49. height: height,
  50. devicePixelRatio: dpr // new
  51. });
  52. canvas.setChart(finalScatter);
  53. getFinalScatterOption().then(option => {
  54. finalScatter.setOption(option)
  55. });
  56. return finalScatter;
  57. }
  58. },
  59. },
  60. onReady() {
  61. // You can add any additional logic here if needed
  62. }
  63. });
  64. function getInitScatterOption() {
  65. const fetchScatterData = () => {
  66. return new Promise((resolve, reject) => {
  67. wx.request({
  68. url: 'https://soilgd.com:5000/model-scatter-data/7',
  69. method: 'GET',
  70. timeout: 5000,
  71. success: (res) => {
  72. console.log('接口响应:', res);
  73. // 校验状态码
  74. if (res.statusCode !== 200) {
  75. reject(new Error(`请求失败,状态码: ${res.statusCode}`));
  76. return;
  77. }
  78. // 校验数据结构
  79. if (!res.data?.scatter_data || !Array.isArray(res.data.scatter_data)) {
  80. reject(new Error('接口数据格式错误'));
  81. return;
  82. }
  83. resolve(res.data.scatter_data);
  84. },
  85. fail: (err) => {
  86. reject(new Error(`网络错误: ${err.errMsg}`));
  87. }
  88. });
  89. });
  90. };
  91. // 核心计算逻辑
  92. const calculateChartOptions = (scatterData) => {
  93. const calculateDataRange = (data) => {
  94. const xValues = data.map(item => item[0]);
  95. const yValues = data.map(item => item[1]);
  96. return {
  97. xMin: Math.min(...xValues),
  98. xMax: Math.max(...xValues),
  99. yMin: Math.min(...yValues),
  100. yMax: Math.max(...yValues)
  101. };
  102. };
  103. const range = calculateDataRange(scatterData);
  104. console.log(scatterData)
  105. const padding = 0.1;
  106. const xMin = range.xMin - Math.abs(range.xMin * padding);
  107. const xMax = range.xMax + Math.abs(range.xMax * padding);
  108. const yMin = range.yMin - Math.abs(range.yMin * padding);
  109. const yMax = range.yMax + Math.abs(range.yMax * padding);
  110. const axisMin = Math.min(xMin, yMin);
  111. const axisMax = Math.max(xMax, yMax);
  112. return {
  113. tooltip: {
  114. trigger: 'axis',
  115. axisPointer: { type: 'cross' }
  116. },
  117. grid: {
  118. left: '3%',
  119. right: '22%',
  120. bottom: '3%',
  121. containLabel: true
  122. },
  123. xAxis: {
  124. name: 'True Values',
  125. type: 'value',
  126. min: axisMin,
  127. max: axisMax,
  128. axisLabel: {
  129. formatter: value => parseFloat(value).toFixed(2)
  130. }
  131. },
  132. yAxis: {
  133. name: 'Predicted Values',
  134. type: 'value',
  135. min: parseFloat(axisMin).toFixed(2),
  136. max: parseFloat(axisMax).toFixed(2)
  137. },
  138. series: [
  139. {
  140. name: 'True vs Predicted',
  141. type: 'scatter',
  142. data: scatterData,
  143. symbolSize: 10,
  144. itemStyle: {
  145. color: '#1f77b4',
  146. opacity: 0.7,
  147. borderColor: '#fff',
  148. borderWidth: 0.5
  149. },
  150. },
  151. {
  152. name: 'Trendline',
  153. type: 'line',
  154. data: [[axisMin, axisMin], [axisMax, axisMax]],
  155. lineStyle: {
  156. type: 'dashed',
  157. color: '#ff7f0e',
  158. width: 2
  159. }
  160. }
  161. ]
  162. };
  163. };
  164. return new Promise(async (resolve) => {
  165. let retryCount = 0;
  166. const maxRetries = 2;
  167. while (retryCount <= maxRetries) {
  168. try {
  169. const scatterData = await fetchScatterData();
  170. resolve(calculateChartOptions(scatterData));
  171. return;
  172. } catch (error) {
  173. console.error(`第 ${retryCount + 1} 次尝试失败:`, error);
  174. if (retryCount === maxRetries) {
  175. resolve({
  176. xAxis: { show: false },
  177. yAxis: { show: false },
  178. series: [{
  179. type: 'scatter',
  180. data: [],
  181. silent: true
  182. }],
  183. graphic: {
  184. type: 'text',
  185. text: '数据加载失败',
  186. }
  187. })
  188. }
  189. retryCount++;
  190. await new Promise(r => setTimeout(r, 1000)); // 1秒后重试
  191. }
  192. }
  193. });
  194. }
  195. // 反酸模型 中间代 散点图
  196. function getMidScatterOption() {
  197. /**
  198. * 计算数据的最大最小值
  199. * @param {Array} data - 散点数据数组
  200. * @returns {Object} 包含 xMin, xMax, yMin, yMax 的对象
  201. */
  202. const fetchScatterData = () => {
  203. return new Promise((resolve, reject) => {
  204. wx.request({
  205. url: 'https://soilgd.com:5000/model-scatter-data/6',
  206. method: 'GET',
  207. timeout: 5000,
  208. success: (res) => {
  209. console.log('接口响应:', res);
  210. // 校验状态码
  211. if (res.statusCode !== 200) {
  212. reject(new Error(`请求失败,状态码: ${res.statusCode}`));
  213. return;
  214. }
  215. // 校验数据结构
  216. if (!res.data?.scatter_data || !Array.isArray(res.data.scatter_data)) {
  217. reject(new Error('接口数据格式错误'));
  218. return;
  219. }
  220. resolve(res.data.scatter_data);
  221. },
  222. fail: (err) => {
  223. reject(new Error(`网络错误: ${err.errMsg}`));
  224. }
  225. });
  226. });
  227. };
  228. // 核心计算逻辑
  229. const calculateChartOptions = (scatterData) => {
  230. const calculateDataRange = (data) => {
  231. const xValues = data.map(item => item[0]);
  232. const yValues = data.map(item => item[1]);
  233. return {
  234. xMin: Math.min(...xValues),
  235. xMax: Math.max(...xValues),
  236. yMin: Math.min(...yValues),
  237. yMax: Math.max(...yValues)
  238. };
  239. };
  240. const range = calculateDataRange(scatterData);
  241. console.log(scatterData)
  242. const padding = 0.1;
  243. const xMin = range.xMin - Math.abs(range.xMin * padding);
  244. const xMax = range.xMax + Math.abs(range.xMax * padding);
  245. const yMin = range.yMin - Math.abs(range.yMin * padding);
  246. const yMax = range.yMax + Math.abs(range.yMax * padding);
  247. const axisMin = Math.min(xMin, yMin);
  248. const axisMax = Math.max(xMax, yMax);
  249. return {
  250. tooltip: {
  251. trigger: 'axis',
  252. axisPointer: { type: 'cross' }
  253. },
  254. grid: {
  255. left: '3%',
  256. right: '22%',
  257. bottom: '3%',
  258. containLabel: true
  259. },
  260. xAxis: {
  261. name: 'True Values',
  262. type: 'value',
  263. min: axisMin,
  264. max: axisMax,
  265. axisLabel: {
  266. formatter: value => parseFloat(value).toFixed(2)
  267. }
  268. },
  269. yAxis: {
  270. name: 'Predicted Values',
  271. type: 'value',
  272. min: parseFloat(axisMin).toFixed(2),
  273. max: parseFloat(axisMax).toFixed(2)
  274. },
  275. series: [
  276. {
  277. name: 'True vs Predicted',
  278. type: 'scatter',
  279. data: scatterData,
  280. symbolSize: 10,
  281. itemStyle: {
  282. color: '#1f77b4',
  283. opacity: 0.7,
  284. borderColor: '#fff',
  285. borderWidth: 0.5
  286. },
  287. },
  288. {
  289. name: 'Trendline',
  290. type: 'line',
  291. data: [[axisMin, axisMin], [axisMax, axisMax]],
  292. lineStyle: {
  293. type: 'dashed',
  294. color: '#ff7f0e',
  295. width: 2
  296. }
  297. }
  298. ]
  299. };
  300. };
  301. return new Promise(async (resolve) => {
  302. let retryCount = 0;
  303. const maxRetries = 2;
  304. while (retryCount <= maxRetries) {
  305. try {
  306. const scatterData = await fetchScatterData();
  307. resolve(calculateChartOptions(scatterData));
  308. return;
  309. } catch (error) {
  310. console.error(`第 ${retryCount + 1} 次尝试失败:`, error);
  311. if (retryCount === maxRetries) {
  312. resolve({
  313. xAxis: { show: false },
  314. yAxis: { show: false },
  315. series: [{
  316. type: 'scatter',
  317. data: [],
  318. silent: true
  319. }],
  320. graphic: {
  321. type: 'text',
  322. text: '数据加载失败',
  323. }
  324. })
  325. }
  326. retryCount++;
  327. await new Promise(r => setTimeout(r, 1000)); // 1秒后重试
  328. }
  329. }
  330. });
  331. }
  332. // 反酸模型 最终代 散点图
  333. function getFinalScatterOption() {
  334. /**
  335. * 计算数据的最大最小值
  336. * @param {Array} data - 散点数据数组
  337. * @returns {Object} 包含 xMin, xMax, yMin, yMax 的对象
  338. */
  339. const fetchScatterData = () => {
  340. return new Promise((resolve, reject) => {
  341. wx.request({
  342. url: 'https://soilgd.com:5000/model-scatter-data/25',
  343. method: 'GET',
  344. timeout: 5000,
  345. success: (res) => {
  346. console.log('接口响应:', res);
  347. // 校验状态码
  348. if (res.statusCode !== 200) {
  349. reject(new Error(`请求失败,状态码: ${res.statusCode}`));
  350. return;
  351. }
  352. // 校验数据结构
  353. if (!res.data?.scatter_data || !Array.isArray(res.data.scatter_data)) {
  354. reject(new Error('接口数据格式错误'));
  355. return;
  356. }
  357. resolve(res.data.scatter_data);
  358. },
  359. fail: (err) => {
  360. reject(new Error(`网络错误: ${err.errMsg}`));
  361. }
  362. });
  363. });
  364. };
  365. // 核心计算逻辑
  366. const calculateChartOptions = (scatterData) => {
  367. const calculateDataRange = (data) => {
  368. const xValues = data.map(item => item[0]);
  369. const yValues = data.map(item => item[1]);
  370. return {
  371. xMin: Math.min(...xValues),
  372. xMax: Math.max(...xValues),
  373. yMin: Math.min(...yValues),
  374. yMax: Math.max(...yValues)
  375. };
  376. };
  377. const range = calculateDataRange(scatterData);
  378. console.log(scatterData)
  379. const padding = 0.1;
  380. const xMin = range.xMin - Math.abs(range.xMin * padding);
  381. const xMax = range.xMax + Math.abs(range.xMax * padding);
  382. const yMin = range.yMin - Math.abs(range.yMin * padding);
  383. const yMax = range.yMax + Math.abs(range.yMax * padding);
  384. const axisMin = Math.min(xMin, yMin);
  385. const axisMax = Math.max(xMax, yMax);
  386. return {
  387. tooltip: {
  388. trigger: 'axis',
  389. axisPointer: { type: 'cross' }
  390. },
  391. grid: {
  392. left: '3%',
  393. right: '22%',
  394. bottom: '3%',
  395. containLabel: true
  396. },
  397. xAxis: {
  398. name: 'True Values',
  399. type: 'value',
  400. min: axisMin,
  401. max: axisMax,
  402. axisLabel: {
  403. formatter: value => parseFloat(value).toFixed(2)
  404. }
  405. },
  406. yAxis: {
  407. name: 'Predicted Values',
  408. type: 'value',
  409. min: parseFloat(axisMin).toFixed(2),
  410. max: parseFloat(axisMax).toFixed(2)
  411. },
  412. series: [
  413. {
  414. name: 'True vs Predicted',
  415. type: 'scatter',
  416. data: scatterData,
  417. symbolSize: 10,
  418. itemStyle: {
  419. color: '#1f77b4',
  420. opacity: 0.7,
  421. borderColor: '#fff',
  422. borderWidth: 0.5
  423. },
  424. },
  425. {
  426. name: 'Trendline',
  427. type: 'line',
  428. data: [[axisMin, axisMin], [axisMax, axisMax]],
  429. lineStyle: {
  430. type: 'dashed',
  431. color: '#ff7f0e',
  432. width: 2
  433. }
  434. }
  435. ]
  436. };
  437. };
  438. return new Promise(async (resolve) => {
  439. let retryCount = 0;
  440. const maxRetries = 2;
  441. while (retryCount <= maxRetries) {
  442. try {
  443. const scatterData = await fetchScatterData();
  444. resolve(calculateChartOptions(scatterData));
  445. return;
  446. } catch (error) {
  447. console.error(`第 ${retryCount + 1} 次尝试失败:`, error);
  448. if (retryCount === maxRetries) {
  449. resolve({
  450. xAxis: { show: false },
  451. yAxis: { show: false },
  452. series: [{
  453. type: 'scatter',
  454. data: [],
  455. silent: true
  456. }],
  457. graphic: {
  458. type: 'text',
  459. text: '数据加载失败',
  460. }
  461. })
  462. }
  463. retryCount++;
  464. await new Promise(r => setTimeout(r, 1000)); // 1秒后重试
  465. }
  466. }
  467. });
  468. }
  469. function getLineOption() {
  470. return {
  471. tooltip: {
  472. trigger: 'axis'
  473. },
  474. legend: {
  475. data: ['Random Forest', 'XGBoost', 'Gradient Boosting'] // 模型名称
  476. },
  477. grid: {
  478. left: '3%',
  479. right: '17%',
  480. bottom: '3%',
  481. containLabel: true
  482. },
  483. xAxis: {
  484. name: '模型迭代',
  485. type: 'category',
  486. boundaryGap: false,
  487. data: ['1代','2代','3代','4代','5代','6代','7代','8代','9代'] // train_sizes按10%递增
  488. },
  489. yAxis: {
  490. name: 'Score (R^2)',
  491. type: 'value'
  492. },
  493. series: [
  494. {
  495. name: 'Random Forest',
  496. type: 'line',
  497. data: [-0.17101591951095463, -0.556719360354051, -0.04083550751401055, -0.20858221504075436, 0.07297292282221035, 0.19857845644421734, 0.28407131176770184, 0.27979356883596496, 0.36904808817286416, 0.4183018571701477] // 使用您的实际R2分数数据
  498. },
  499. {
  500. name: 'XGBoost',
  501. type: 'line',
  502. data: [-1.1811781145886937, -1.5645641005612534, -0.12619079632263497, 0.03324096120721032, 0.06969290639267578, 0.12375262461601955, 0.5331670468884062, 0.49454793164801647, 0.31904329339597803, 0.2712670704381914]
  503. },
  504. {
  505. name: 'Gradient Boosting',
  506. type: 'line',
  507. data: [-0.8583039298789095, -1.073316171952042, 0.09659300885027666, 0.06097833957434784, 0.191975498544109, 0.3718334600546489, 0.3948098332187753, 0.4398778520728397, 0.452609022210963, 0.41484634172723023]
  508. }
  509. ]
  510. };
  511. }