演示平台的多指标蜘蛛图

2025-12-25 19:02
25

多指标蜘蛛图

下面给出“多指标蜘蛛图(LAI + 产量 + 水分利用效率 WUE)”的完整教学模块,本科零门槛:

  • • 学生勾选参数 → 平台自动计算 3 个输出指标 的敏感度

  • • 一张 三色蜘蛛图 同时展示:

    • • LAI(冠层)

    • • 产量(TWSO)

    • • 水分利用效率(WUE = TWSO / 蒸散量)


  • • 一键运行 → 可视化完成


✅ 前端升级(templates/sensitivity_multi.html)

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <title>多指标敏感性分析</title>
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  <style>
    body { font-family: Arial; margin: 40px; background: #f9f9f9; }
    .container { max-width: 1000px; margin: auto; background: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
    h1 { text-align: center; color: #2e7d32; }
    .chk-group { display: flex; flex-wrap: wrap; gap: 15px; margin: 20px 0; }
    .chk-group label { background: #e8f5e9; padding: 8px 12px; border-radius: 4px; cursor: pointer; }
    button { padding: 10px 20px; background: #2e7d32; color: white; border: none; border-radius: 4px; cursor: pointer; }
    button:hover { background: #1b5e20; }
    .chart-container { margin-top: 40px; }
  </style>
</head>
<body>
  <div class="container">
    <h1>🕷️ 多指标敏感性分析 - LAI + 产量 + 水分利用效率</h1>

    <div class="chk-group">
      <label><input type="checkbox" value="MAXLUE" checked> MAXLUE</label>
      <label><input type="checkbox" value="SPAN" checked> SPAN</label>
      <label><input type="checkbox" value="SLA" checked> SLA</label>
      <label><input type="checkbox" value="AMAXTB" > AMAXTB</label>
      <label><input type="checkbox" value="KDIFTB" > KDIFTB</label>
    </div>

    <button onclick="runMultiSensitivity()">开始分析</button>

    <div class="chart-container">
      <canvas id="radarMulti"></canvas>
    </div>
  </div>

  <script>
    const ctx = document.getElementById('radarMulti').getContext('2d');
    let radarChart = new Chart(ctx, {
      type: 'radar',
      data: { labels: [], datasets: [] },
      options: {
        responsive: true,
        plugins: {
          title: { display: true, text: '多指标敏感度(LAI | 产量 | WUE)' },
            tooltip: {
              callbacks: {
                label: function(context) {
                  return context.dataset.label + ': ' + context.parsed.r.toFixed(2);
                }
              }
            }
        },
        scales: {
          r: {
            beginAtZero: true,
            pointLabels: { font: { size: 14 } }
          }
        }
      }
    });

    async function runMultiSensitivity() {
      const checks = Array.from(document.querySelectorAll('input[type=checkbox]:checked')).map(cb => cb.value);
      if (checks.length === 0) { alert('至少选择一个参数'); return; }

      const response = await fetch('/sensitivity_multi', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ params: checks })
      });

      const data = await response.json();

      radarChart.data.labels = data.params;
      radarChart.data.datasets = [
        {
          label: 'LAI 敏感度',
          data: data.sensitivity_lai,
          borderColor: 'rgba(75, 192, 192, 1)',
          backgroundColor: 'rgba(75, 192, 192, 0.2)',
          pointBackgroundColor: 'rgba(75, 192, 192, 1)'
        },
        {
          label: '产量 敏感度',
          data: data.sensitivity_yield,
          borderColor: 'rgba(255, 159, 64, 1)',
          backgroundColor: 'rgba(255, 159, 64, 0.2)',
          pointBackgroundColor: 'rgba(255, 159, 64, 1)'
        },
        {
          label: 'WUE 敏感度',
          data: data.sensitivity_wue,
          borderColor: 'rgba(54, 162, 235, 1)',
          backgroundColor: 'rgba(54, 162, 235, 0.2)',
          pointBackgroundColor: 'rgba(54, 162, 235, 1)'
        }
      ];
      radarChart.update();
    }
  </script>
</body>
</html>

✅ 后端升级(app.py 新增)

import numpy as np
import pandas as pd
import copy
from deap import base, creator, tools
from pcse.fileinput import YAMLCropDataProvider
from pcse.base import ParameterProvider
from pcse.db import NASAPowerWeatherDataProvider
from pcse.models import Wofost71_WLP_FD
from pcse.engine import Engine
from flask import Blueprint, request, jsonify

sens_bp = Blueprint('sensitivity_multi', __name__, url_prefix='/')

@sens_bp.route('/sensitivity_multi')
def sens_multi_page():
    return render_template('sensitivity_multi.html')

# ---------- 局部分析(3 指标) ----------
@sens_bp.route('/sensitivity_multi', methods=['POST'])
def sensitivity_multi():
    selected = request.json['params']
    base_crop = {
        'VARIETY_NAME': 'MultiWheat',
        'CropType': 'wheat',
        'MAXLUE': 2.5,
        'SPAN': 30,
        'SLA': 20,
        'AMAXTB': [0, 1.0, 1.5, 1.0],
        'KDIFTB': [0, 0.6, 2, 0.6]
    }

    def run_one(crop_dict):
        cropd = YAMLCropDataProvider(crop_dict=crop_dict)
        weather = NASAPowerWeatherDataProvider(latitude=52.0, longitude=5.0)
        params = ParameterProvider(cropdata=cropd, soildata=None, sitedata=None)
        wofost = Wofost71_WLP_FD(params, weather, [])
        eng = Engine(wofost)
        eng.run_till_terminate()
        df = pd.DataFrame(eng.get_output())
        lai_max = df['LAI'].max()
        yield_val = df['TWSO'].iloc[-1] if not df.empty else 0
        et_sum = df['EVAP'].sum() + df['TRAT'].sum()
        wue = yield_val / et_sum if et_sum else 0
        return lai_max, yield_val, wue

    base_lai, base_yield, base_wue = run_one(base_crop)
    sensitivity_lai, sensitivity_yield, sensitivity_wue = [], [], []

    for p in selected:
        plus = copy.deepcopy(base_crop)
        minus = copy.deepcopy(base_crop)
        if isinstance(base_crop[p], list):
            plus[p] = [v * 1.1 if isinstance(v, float) else v for v in base_crop[p]]
            minus[p] = [v * 0.9 if isinstance(v, float) else v for v in base_crop[p]]
        else:
            plus[p] = base_crop[p] * 1.1
            minus[p] = base_crop[p] * 0.9

        plus_lai, plus_yield, plus_wue = run_one(plus)
        minus_lai, minus_yield, minus_wue = run_one(minus)

        s_lai = abs((plus_lai - minus_lai) / (0.2 * base_lai))
        s_yield = abs((plus_yield - minus_yield) / (0.2 * base_yield)) if base_yield else 0
        s_wue = abs((plus_wue - minus_wue) / (0.2 * base_wue)) if base_wue else 0

        sensitivity_lai.append(round(s_lai, 3))
        sensitivity_yield.append(round(s_yield, 3))
        sensitivity_wue.append(round(s_wue, 3))

    return jsonify({
        "params": selected,
        "sensitivity_lai": sensitivity_lai,
        "sensitivity_yield": sensitivity_yield,
        "sensitivity_wue": sensitivity_wue
    })

✅ 使用流程(学生)

  1. 1. 打开:http://localhost:5000/sensitivity_multi

  2. 2. 勾选参数(默认 3 个)

  3. 3. 点击“开始分析”

  4. 4. 等待 15–30 秒 → 看到:

    • • 一张 三色蜘蛛图

    • • 绿色 = LAI

    • • 橙色 = 产量

    • • 蓝色 = 水分利用效率 WUE



✅ 教学提示(可打印)

颜色指标怎么看
绿色LAI离圆心越远 → 参数对冠层影响越大
橙色产量越远 → 对籽粒影响越大
蓝色WUE越远 → 对水分利用影响越大

✅ 后续可拓展

  • • ➕ 下载蜘蛛图为 PNG / PDF

  • • ➕ 教师后台:查看全班平均敏感度

  • • ➕ 支持更多指标(生根深度、蒸散量)


✅ 下一步?

你想继续:

  • • ✅ 下载 PNG / PDF 报告

  • • ✅ 教师后台(全班热力图)

  • • ✅ 支持自定义指标(下拉选择)

我可以直接给你完整代码!