Kaynağa Gözat

调整模型训练和模型选择的样式,为模型选择提供新的评分参数,散点图调整为动态更新

DIng 2 ay önce
ebeveyn
işleme
739ec3277e

+ 2 - 1
api/app/__init__.py

@@ -3,7 +3,7 @@ import sqlite3
 
 from flask import Flask
 from flask_cors import CORS
-from . import config, frontend
+from . import config
 from flask_sqlalchemy import SQLAlchemy
 from flask_migrate import Migrate
 import logging
@@ -49,6 +49,7 @@ def create_app():
 
     # 导入路由
     from . import routes
+    from . import frontend
     app.register_blueprint(routes.bp)
     app.register_blueprint(frontend.bp)
     return app

+ 1 - 1
api/app/frontend.py

@@ -10,7 +10,7 @@ from sqlalchemy import text, select, MetaData, Table
 from sqlalchemy.orm import sessionmaker
 from werkzeug.security import check_password_hash, generate_password_hash
 from werkzeug.utils import secure_filename
-
+from app import db
 from .database_models import Models
 
 # 配置日志

+ 68 - 1
api/app/routes.py

@@ -1,8 +1,10 @@
+import pickle
 import sqlite3
 
 from flask import Blueprint, request, jsonify,current_app
 from werkzeug.security import generate_password_hash
 
+from sklearn.metrics import r2_score
 from .model import predict, train_and_save_model, calculate_model_score
 import pandas as pd
 from . import db  # 从 app 包导入 db 实例
@@ -1027,7 +1029,9 @@ def get_models():
                 'DatasetID': model.DatasetID,
                 'ModelFilePath': model.ModelFilePath,
                 'DataType': model.Data_type,
-                'PerformanceScore': model.Performance_score
+                'PerformanceScore': model.Performance_score,
+                'MAE': model.MAE,
+                'RMSE': model.RMSE
             }
             for model in models
         ]
@@ -1074,4 +1078,67 @@ def get_table():
         return jsonify({'error': str(e)}), 400
     finally:
         # 关闭 session
+        session.close()
+
+
+@bp.route('/model-scatter-data/<int:model_id>', methods=['GET'])
+def get_model_scatter_data(model_id):
+    """
+    获取指定模型的散点图数据(真实值vs预测值)
+
+    @param model_id: 模型ID
+    @return: JSON响应,包含散点图数据
+    """
+    Session = sessionmaker(bind=db.engine)
+    session = Session()
+
+    try:
+        # 查询模型信息
+        model = session.query(Models).filter_by(ModelID=model_id).first()
+        if not model:
+            return jsonify({'error': '未找到指定模型'}), 404
+
+        # 加载模型
+        with open(model.ModelFilePath, 'rb') as f:
+            ML_model = pickle.load(f)
+
+        # 根据数据类型加载测试数据
+        if model.Data_type == 'reflux':
+            X_test = pd.read_csv('uploads/data/X_test_reflux.csv')
+            Y_test = pd.read_csv('uploads/data/Y_test_reflux.csv')
+        elif model.Data_type == 'reduce':
+            X_test = pd.read_csv('uploads/data/X_test_reduce.csv')
+            Y_test = pd.read_csv('uploads/data/Y_test_reduce.csv')
+        else:
+            return jsonify({'error': '不支持的数据类型'}), 400
+
+        # 获取预测值
+        y_pred = ML_model.predict(X_test)
+
+        # 生成散点图数据
+        scatter_data = [
+            [float(true), float(pred)]
+            for true, pred in zip(Y_test.iloc[:, 0], y_pred)
+        ]
+
+        # 计算R²分数
+        r2 = r2_score(Y_test, y_pred)
+
+        # 获取数据范围,用于绘制对角线
+        y_min = min(min(Y_test.iloc[:, 0]), min(y_pred))
+        y_max = max(max(Y_test.iloc[:, 0]), max(y_pred))
+
+        return jsonify({
+            'scatter_data': scatter_data,
+            'r2_score': float(r2),
+            'y_range': [float(y_min), float(y_max)],
+            'model_name': model.Model_name,
+            'model_type': model.Model_type
+        }), 200
+
+    except Exception as e:
+        logger.error(f'获取模型散点图数据失败: {str(e)}', exc_info=True)
+        return jsonify({'error': f'获取数据失败: {str(e)}'}), 500
+
+    finally:
         session.close()

+ 17 - 0
api/package-lock.json

@@ -0,0 +1,17 @@
+{
+  "name": "api",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "ec-canvas": "^1.0.0"
+      }
+    },
+    "node_modules/ec-canvas": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/ec-canvas/-/ec-canvas-1.0.0.tgz",
+      "integrity": "sha512-iG/4yLcJMK8HL5xt/9alfMXg8zlDy5p9VPoX/MLbgFPJMH7THYkSfbk8HXzsTZbTTZFiOfvXHolDn/W2BLy/tg=="
+    }
+  }
+}

+ 5 - 0
api/package.json

@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "ec-canvas": "^1.0.0"
+  }
+}

BIN
assets/taddar/W020241210635035429857_ORIGIN.jpg


+ 17 - 0
package-lock.json

@@ -0,0 +1,17 @@
+{
+  "name": "AcidModel",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "ec-canvas": "^1.0.0"
+      }
+    },
+    "node_modules/ec-canvas": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/ec-canvas/-/ec-canvas-1.0.0.tgz",
+      "integrity": "sha512-iG/4yLcJMK8HL5xt/9alfMXg8zlDy5p9VPoX/MLbgFPJMH7THYkSfbk8HXzsTZbTTZFiOfvXHolDn/W2BLy/tg=="
+    }
+  }
+}

+ 5 - 0
package.json

@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "ec-canvas": "^1.0.0"
+  }
+}

+ 0 - 57
pages/Regular/Regular.js

@@ -12,48 +12,8 @@ Page({
     });
   },
 
-<<<<<<< HEAD:pages/b/b.js
   // 输入密码
   inputPassword: function (e) {
-=======
-  // 取消登录弹窗
-  potNo() {
-    this.setData({
-      isHidden: true
-    });
-  },
-
-  // 确认登录弹窗
-  popYes() {
-    const { avatarUrl, nickName } = this.data;
-    if (!avatarUrl || !nickName) {
-      wx.showToast({
-        icon: 'error',
-        title: '请获取头像和昵称',
-      });
-      return;
-    }
-
-    this.setData({
-      isLogin: true,
-      isHidden: true,
-    });
-
-    // 登录成功后跳转到指定页面
-    wx.switchTab({
-      url: '/pages/Regular User/Home/Home',
-    });
-  },
-
-  // 用户名密码登录
-  inputUsername(e) {
-    this.setData({
-      username: e.detail.value
-    });
-  },
-
-  inputPassword(e) {
->>>>>>> origin/soligd:pages/Regular/Regular.js
     this.setData({
       password: e.detail.value
     });
@@ -102,7 +62,6 @@ Page({
               errorMessage: ''
             });
 
-<<<<<<< HEAD:pages/b/b.js
             // 跳转到登录页面
             wx.switchTab({
               url: '/pages/Home/Home' 
@@ -125,22 +84,6 @@ Page({
           console.error('注册失败:', err);
         }
       });
-=======
-        // 登录成功后跳转到指定页面
-        wx.switchTab({
-          url: '/pages/Regular User/Home/Home',
-        });
-      } else {
-        this.setData({
-          errorMessage: '用户名或密码错误'
-        });
-        wx.showToast({
-          title: '用户名或密码错误',
-          icon: 'none',
-          duration: 2000
-        });
-      }
->>>>>>> origin/soligd:pages/Regular/Regular.js
     }, 1500);
   },
 });

+ 4 - 1
shoping/Model Selection/Model Selection.js

@@ -29,7 +29,9 @@ Page({
             ModelType: model.ModelType,
             ModelID: model.ModelID,
             ModelName: model.ModelName, // 包含模型名称
-            PerformanceScore: (Number(model.PerformanceScore) || 0).toFixed(2)
+            PerformanceScore: (Number(model.PerformanceScore) || 0).toFixed(2),
+            MAE: (Number(model.MAE) || 0).toFixed(2),
+            RMSE: (Number(model.RMSE) || 0).toFixed(2)
           }));
 
           this.setData({
@@ -78,6 +80,7 @@ Page({
   // 提交选择
   onSubmitModel: function () {
     const { selectedModelId, selectedModelType } = this.data;
+    console.log(selectedModelId, selectedModelType)
 
     if (!selectedModelId || !selectedModelType) {
       wx.showToast({

+ 33 - 14
shoping/Model Selection/Model Selection.wxml

@@ -6,21 +6,40 @@
     </view>
   </picker>
 
-  <!-- 模型列表展示 -->
-  <view wx:for="{{filteredModelList}}" wx:key="ModelID" class="model-item">
-    <radio-group>
-      <label>
-        <radio
-          value="{{item.ModelID}}"
-          data-model-id="{{item.ModelID}}"
-          checked="{{selectedModelId === item.ModelID}}"
-          bindtap="onModelSelect"
-        />
-        {{item.ModelID}}: {{item.ModelType}}: {{item.PerformanceScore}}
-      </label>
-    </radio-group>
+  <!-- 表格化展示 -->
+  <view class="model-table">
+    <!-- 表头 -->
+    <view class="table-header">
+      <view class="col select-col">选择</view>
+      <view class="col">模型ID</view>
+      <view class="col">模型类型</view>
+      <view class="col">综合评分</view>
+      <view class="col">MAE</view>
+      <view class="col">RMSE</view>
+    </view>
+
+    <!-- 数据行 -->
+    <view class="table-body">
+      <block wx:for="{{filteredModelList}}" wx:key="ModelID">
+        <view class="table-row {{selectedModelId === item.ModelID ? 'selected' : ''}}">
+          <view class="col select-col">
+            <radio 
+              value="{{item.ModelID}}"
+              data-model-id="{{item.ModelID}}"
+              checked="{{selectedModelId === item.ModelID}}"
+              bindtap="onModelSelect"
+            />
+          </view>
+          <view class="col">{{item.ModelID}}</view>
+          <view class="col">{{item.ModelType}}</view>
+          <view class="col">{{item.PerformanceScore}}</view>
+          <view class="col">{{item.MAE}}</view>
+          <view class="col">{{item.RMSE}}</view>
+        </view>
+      </block>
+    </view>
   </view>
 
   <!-- 提交按钮 -->
   <button bindtap="onSubmitModel" class="submit-btn">提交选择</button>
-</view>
+</view>

+ 42 - 41
shoping/Model Selection/Model Selection.wxss

@@ -1,58 +1,59 @@
-.container {
-  display: flex;
-  flex-direction: column;
-  gap: 20px;
-  padding: 20px;
-  background-color: #f5f5f5;
-  margin-top: 60px;
+/* 表格样式 */
+.model-table {
+  width: 100%;
+  margin-top: 20rpx;
+  border: 1rpx solid #eee;
+  border-radius: 8rpx;
+  overflow: hidden;
 }
 
-.card {
-  display: flex; /* 使用 flexbox 布局 */
+.table-header,
+.table-row {
+  display: flex;
+  flex-direction: row;
   align-items: center;
-  width: 90%;
-  background-color: #ffffff;
-  padding: 20px;
-  border-radius: 12px;
-  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
-  transition: transform 0.2s ease;
-  cursor: pointer;
+  padding: 20rpx 10rpx;
 }
 
-.card:hover {
-  transform: scale(1.05);
-}
-
-.card-icon {
-  width: 40px;
-  height: 40px;
-  margin-bottom: 20px;
-  margin-right: 90px; /* 与内容保持间距 */
+.table-header {
+  background-color: #f5f5f5;
+  font-weight: bold;
+  border-bottom: 2rpx solid #ddd;
 }
 
-.card-content {
-  flex: 1; /* 占据剩余空间,保证布局一致 */
-  text-align: center; /* 内容水平居中 */
+.table-row {
+  border-bottom: 1rpx solid #eee;
 }
 
-.card-title {
-  font-size: 18px;
-  font-weight: bold;
-  color: #333;
+.table-row.selected {
+  background-color: #f0f8ff;
 }
 
-.card:nth-child(1) {
-  background-color: #FFDDC1; /* 软件简介卡片颜色 */
+.col {
+  flex: 1;
+  text-align: center;
+  padding: 0 10rpx;
+  word-break: break-all;
 }
 
-.card:nth-child(2) {
-  background-color: #C1E1FF; /* 项目简介卡片颜色 */
+.select-col {
+  flex: 0.5;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 }
 
-.card:nth-child(3) {
-  background-color: #D4F4DD; /* 研究成果卡片颜色 */
+/* 其他样式保持原有 */
+.picker {
+  padding: 20rpx;
+  background-color: #fff;
+  border-radius: 8rpx;
+  margin-bottom: 20rpx;
+  border: 1rpx solid #ddd;
 }
 
-.card:nth-child(4) {
-  background-color: #FFD700; /* 团队信息卡片颜色 */
-}
+.submit-btn {
+  margin-top: 40rpx;
+  background-color: #07c160;
+  color: white;
+}

+ 85 - 107
shoping/ModelTrain/ModelTrain.wxss

@@ -1,141 +1,119 @@
-
-/* 表格容器 */
-.table-container {
-  width: 100%;
-  overflow-x: auto; /* 启用横向滚动 */
-  white-space: nowrap; /* 禁止换行 */
-  background-color: #fff;
-  border: 1rpx solid #ddd;
-  margin-top: 10rpx; /* 添加上边距,确保不会和顶部元素重叠 */
-  white-space: nowrap; /* 禁止换行 */
+/* 统一容器样式 */
+.picker-title {
+  font-size: 16px;
+  color: #333;
+  margin: 20rpx 0;
+  padding-left: 20rpx;
 }
 
-/* 表头样式 */
-.table-header {
-  display: flex;
-  background-color: #61E054; /* 表头背景色 */
-  font-weight: bold;
-  text-align: center;
+/* 下拉选择器样式 */
+.picker-container {
+  position: relative;
+  margin: 0 20rpx 20rpx;
+  border: 1rpx solid #ddd;
+  border-radius: 8rpx;
+  padding: 20rpx;
 }
 
-/* 表格单元格样式 */
-.table-cell {
-  flex: none;
-  width: 170rpx; /* 固定宽度 */
-  height: 100rpx;
-  padding: 10rpx;
-  text-align: center;
-  font-size: 28rpx;
-  color: #030803; /* 表头文字颜色 */
-  border-right: 1rpx solid #ddd;
-  white-space: normal;
-  overflow: hidden;
-  word-wrap: break-word;
-  word-break: break-all;
+.picker {
+  color: #666;
 }
 
-/* 表格行样式 */
-.table-row:nth-child(odd) {
-  background-color: #E4FBE5; /* 奇数行背景色 */
+.picker-arrow {
+  position: absolute;
+  right: 20rpx;
+  top: 50%;
+  transform: translateY(-50%);
+  width: 0;
+  height: 0;
+  border-left: 10rpx solid transparent;
+  border-right: 10rpx solid transparent;
+  border-top: 16rpx solid #999;
 }
 
-.table-row:nth-child(even) {
-  background-color: #fff; /* 偶数行背景色 */
+/* 表格容器 */
+.table-container {
+  width: 100%;
+  margin-top: 20rpx;
+  border: 1rpx solid #eee;
+  border-radius: 8rpx;
+  overflow: hidden;
 }
 
-/* 表格内容样式 */
+/* 统一表格样式 */
 .table-body {
-  display: flex;
-  flex-direction: column;
-  width: max-content;
+  width: 100%;
 }
 
+.table-header,
 .table-row {
   display: flex;
   flex-direction: row;
-  border-bottom: 1rpx solid #ddd;
+  align-items: center;
+  padding: 20rpx 10rpx;
 }
 
-/* 单选框样式 */
-.radio {
-  display: inline-block;
-  margin-right: 10px; /* 单选框之间的间隔 */
+.table-header {
+  background-color: #f5f5f5;
+  font-weight: bold;
+  border-bottom: 2rpx solid #ddd;
 }
 
-/* 单选框选中时的样式 */
-.radio-checked {
-  color: #1AAD19; /* 微信小程序主题色 */
+.table-row {
+  display: flex;
+  align-items: center;
+  border-bottom: 1rpx solid #eee;
+  padding: 20rpx 0;
 }
 
-/* 单选框未选中时的样式 */
-.radio-unchecked {
-  color: #ccc; /* 灰色表示未选中 */
+.table-row.selected {
+  background-color: #f0f8ff;
 }
 
-/* 按钮通用样式 */
-.button-container button {
-  width: 50%; /* 按钮宽度100%,占满容器宽度 */
-  height: 50px; /* 按钮高度 */
-  line-height: 50px; /* 行高与按钮高度一致,使文本垂直居中 */
-  background-color: #1AAD19; /* 微信绿 */
-  color: white; /* 文字颜色为白色 */
-  border-radius: 5px; /* 圆角边框 */
-  font-size: 16px; /* 字体大小 */
-  margin-top: 20px;
+.table-cell {
+  flex: 1;
+  min-width: 160rpx;
+  text-align: center;
+  padding: 0 10rpx;
+  word-break: break-all;
 }
 
-/* 按钮点击效果 */
-.button-container button:active {
-  background-color: #179B16; /* 点击时背景颜色变深 */
+/* 调整单选框列 */
+.table-cell:first-child {
+  flex: 0.5;
+  display: flex;
+  justify-content: center;
 }
 
+/* 统一按钮样式 */
+.button-container {
+  margin: 40rpx 20rpx 0;
+}
 
-/* 下拉框容器样式 */
-.picker-container {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  font-size: 16px; /* 字体大小 */
-  color: #333; /* 字体颜色 */
-  padding: 8px 12px; /* 内边距 */
-  background-color: #fff; /* 背景颜色 */
-  border: 1px solid #ddd; /* 边框 */
-  border-radius: 4px; /* 圆角边框 */
-  width: 200px; /* 固定宽度 */
-  margin-left: auto; /* 自动左边距 */
-  margin-right: auto; /* 自动右边距 */
-  box-sizing: border-box; /* 确保边框和内边距包含在宽度内 */
-}
-
-/* 下拉框样式 */
-.picker {
-  flex-grow: 1; /* 使下拉框占据剩余空间 */
-  text-align: left; /* 文字左对齐 */
+.button-container button {
+  width: 100%;
+  background-color: #07c160;
+  color: white;
+  border-radius: 8rpx;
+  font-size: 16px;
 }
 
-/* 三角形样式 */
-.picker-arrow {
-  width: 0;
-  height: 0;
-  border-left: 5px solid transparent;
-  border-right: 5px solid transparent;
-  border-top: 5px solid #333; /* 三角形颜色 */
-  margin-left: 10px; /* 与下拉框文本的间隔 */
+/* 状态提示样式 */
+.loading,
+.no-data {
+  text-align: center;
+  padding: 40rpx;
+  color: #999;
+  font-size: 14px;
 }
 
-/* 下拉框标题样式 */
-.picker-title {
-  font-size: 16px; /* 字体大小 */
-  font-weight: bold; /* 字体加粗 */
-  color: #333; /* 字体颜色 */
-  margin-bottom: 10px; /* 与下拉框之间的间隔 */
-  text-align: center; /* 文字居中 */
-  padding: 8px 0; /* 上下内边距 */
-  background-color: #f0f0f0; /* 背景颜色 */
-  border: 1px solid #ddd; /* 边框 */
-  border-radius: 4px; /* 圆角边框 */
-  width: 200px; /* 固定宽度 */
-  margin-left: auto; /* 自动左边距 */
-  margin-right: auto; /* 自动右边距 */
-  box-sizing: border-box; /* 确保边框和内边距包含在宽度内 */
+/* 保持单选框样式一致 */
+radio .wx-radio-input {
+  width: 20px;
+  height: 20px;
+}
+
+.radio-checked .wx-radio-input {
+  border-color: #07c160 !important;
+  background-color: #07c160 !important;
 }

+ 430 - 236
shoping/Soil Acid Reduction Iterative Evolution/Soil Acid Reduction Iterative Evolution.js

@@ -2,6 +2,7 @@ import * as echarts from '../../components/ec-canvas/echarts';
 
 Page({
   data: {
+    initScatterData : [],
     ecLine: {
       onInit: function (canvas, width, height, dpr) {
         const lineChart = echarts.init(canvas, null, {
@@ -20,10 +21,12 @@ Page({
         const initScatter = echarts.init(canvas, null, {
           width: width,
           height: height,
-          devicePixelRatio: dpr // new
+          devicePixelRatio: dpr
         });
         canvas.setChart(initScatter);
-        initScatter.setOption(getInitScatterOption());
+        getInitScatterOption().then(option => {
+          initScatter.setOption(option)
+        });
 
         return initScatter;
       }
@@ -36,7 +39,9 @@ Page({
         devicePixelRatio: dpr // new
       });
       canvas.setChart(midScatter);
-      midScatter.setOption(getMidScatterOption());
+      getMidScatterOption().then(option => {
+        midScatter.setOption(option)
+      });
 
       return midScatter;
     }
@@ -49,7 +54,9 @@ Page({
           devicePixelRatio: dpr // new
         });
         canvas.setChart(finalScatter);
-        finalScatter.setOption(getFinalScatterOption());
+        getFinalScatterOption().then(option => {
+          finalScatter.setOption(option)
+        });
 
         return finalScatter;
       }
@@ -61,253 +68,440 @@ Page({
   }
 });
 
-// 降酸模型  初代  散点图
+
 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() {
   return {
     tooltip: {
@@ -336,18 +530,18 @@ function getLineOption() {
       {
         name: 'Random Forest',
         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',
         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',
         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]
       }
     ]
   };
-}
+}

+ 139 - 81
shoping/Soil Acidification Iterative Evolution/Soil Acidification Iterative Evolution.js

@@ -2,6 +2,7 @@ import * as echarts from '../../components/ec-canvas/echarts';
 
 Page({
   data: {
+    initScatterData : [],
     ecLine: {
       onInit: function (canvas, width, height, dpr) {
         const lineChart = echarts.init(canvas, null, {
@@ -20,10 +21,12 @@ Page({
         const initScatter = echarts.init(canvas, null, {
           width: width,
           height: height,
-          devicePixelRatio: dpr // new
+          devicePixelRatio: dpr
         });
         canvas.setChart(initScatter);
-        initScatter.setOption(getInitScatterOption());
+        getInitScatterOption().then(option => {
+          initScatter.setOption(option)
+        });
 
         return initScatter;
       }
@@ -61,92 +64,147 @@ Page({
   }
 });
 
-// 反酸模型  初代  散点图
+
 function getInitScatterOption() {
-  /**
-   * 计算数据的最大最小值
-   * @param {Array} data - 散点数据数组
-   * @returns {Object} 包含 xMin, xMax, yMin, yMax 的对象
-   */
-  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/24',
+        method: 'GET',
+        timeout: 5000,
+        success: (res) => {
+          console.log('接口响应:', res);
+          // 校验状态码
+          if (res.statusCode !== 200) {
+            reject(new Error(`请求失败,状态码: ${res.statusCode}`));
+            return;
+          }
 
-  const scatterData = [[-0.003333333333333854, -0.4181333333333324], [-0.1733333333333329, -0.26733333333333265], [-0.6233333333333331, -0.3718666666666661], [-0.7088888888888892, -0.3854666666666661], [-0.3366666666666669, -0.3998666666666657], [-0.8888888888888887, -0.36439999999999934], [-0.5633333333333326, -0.6207999999999997], [-0.7333333333333325, -0.36026666666666607], [-0.3366666666666663, -0.29213333333333275], [-1.176666666666666, -0.6095999999999993], [-0.7122222222222225, -0.3807999999999989], [-0.7699999999999996, -0.3718666666666661]];
+          // 校验数据结构
+          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)
+          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;
 
-  return {
-    tooltip: {
-      trigger: 'axis',
-      axisPointer: {
-        type: 'cross'
-      }
-    },
-    legend: {
-      data: ['True vs Predicted']
-    },
-    grid: {
-      left: '3%',
-      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() {
   /**

+ 1 - 10
shoping/Soil Acidification Iterative Evolution/Soil Acidification Iterative Evolution.wxml

@@ -2,17 +2,8 @@
   <view class="chart-container">
     <ec-canvas id="lineChart" canvas-id="lineChart" ec="{{ecLine}}"></ec-canvas>
   </view>
-  <text class="sub-title">初代散点图</text>
+  <text class="sub-title">散点图</text>
   <view class="chart-container">
     <ec-canvas id="scatterChart" canvas-id="initScatter" ec="{{ecInitScatter}}"></ec-canvas>
   </view>
-  
-  <text class="sub-title">中间代散点图</text>
-  <view class="chart-container">
-    <ec-canvas id="scatterChart" canvas-id="midScatter" ec="{{ecMidScatter}}"></ec-canvas>
-  </view>
-  <text class="sub-title">最终代散点图</text>
-  <view class="chart-container">
-    <ec-canvas id="scatterChart" canvas-id="finalScatter" ec="{{ecFinalScatter}}"></ec-canvas>
-  </view>
 </view>

+ 0 - 12
shoping/Staffl/Staff.wxss

@@ -1,14 +1,3 @@
-.log-list {
-  display: flex;
-  flex-direction: column;
-  padding: 40rpx;
-}
-.log-item {
-  margin: 10rpx;
-}
-<<<<<<< HEAD:pages/logs/logs.wxss
-=======
-
 .logo-hover {
   opacity: 0.8;
 }
@@ -105,4 +94,3 @@
   margin-left: 10rpx; /* 设置箭头和文本之间的间距 */
   object-fit: contain; /* 保证图片不被拉伸 */
 }
->>>>>>> origin/soligd:shoping/Staffl/Staff.wxss