代码(html)

<!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>电阻-温度数据拟合工具</title><script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script><style>body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;max-width: 1000px;margin: 0 auto;padding: 20px;background-color: #f5f7f9;color: #333;}h1 {color: #2c3e50;text-align: center;margin-bottom: 30px;}.container {display: flex;flex-wrap: wrap;gap: 20px;margin-bottom: 30px;}.data-section {flex: 1;min-width: 300px;background: white;border-radius: 8px;padding: 20px;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);}.result-section {flex: 2;min-width: 300px;background: white;border-radius: 8px;padding: 20px;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);}table {width: 100%;border-collapse: collapse;margin-bottom: 15px;}th, td {border: 1px solid #ddd;padding: 10px;text-align: center;}th {background-color: #f2f2f2;}th:first-child, th:nth-child(2) {width: 35%;}th:last-child {width: 30%;}#data-table td.action-cell {display: flex;justify-content: center;align-items: center;}input {width: 100%;box-sizing: border-box;padding: 8px;border: 1px solid #ddd;border-radius: 4px;}.btn {padding: 10px 15px;margin: 5px;border: none;border-radius: 4px;cursor: pointer;font-weight: bold;}.btn-primary {background-color: #3498db;color: white;}.btn-danger {background-color: #e74c3c;color: white;}.btn-success {background-color: #2ecc71;color: white;}.buttons {display: flex;justify-content: center;gap: 10px;margin-top: 10px;}.equation {font-size: 18px;margin: 15px 0;padding: 15px;background-color: #f9f9f9;border-left: 4px solid #3498db;border-radius: 4px;}.r-squared {font-size: 16px;margin: 15px 0;padding: 15px;background-color: #f9f9f9;border-left: 4px solid #2ecc71;border-radius: 4px;}.kb-values {font-size: 16px;margin: 10px 0;padding: 10px;background-color: #fff7f0;border-left: 4px solid #6c5ce7;border-radius: 4px;}.chart-container {margin-top: 20px;position: relative;height: 300px;width: 100%;}.instructions {background-color: #f8f9fa;padding: 15px;border-radius: 8px;margin-bottom: 20px;border-left: 4px solid #ffc107;}</style> </head> <body><h1>电阻-温度数据拟合工具</h1><div class="container"><div class="data-section"><h2>数据输入</h2><table id="data-table"><thead><tr><th>电阻值 (Ω)</th><th>温度值 (°C)</th><th>操作</th></tr></thead><tbody><tr><td><input type="number" class="resistance" step="0.1" value="100"></td><td><input type="number" class="temperature" step="0.1" value="20"></td><td class="action-cell"><button class="btn btn-danger" onclick="deleteRow(this)">删除</button></td></tr><tr><td><input type="number" class="resistance" step="0.1" value="120"></td><td><input type="number" class="temperature" step="0.1" value="25"></td><td class="action-cell"><button class="btn btn-danger" onclick="deleteRow(this)">删除</button></td></tr><tr><td><input type="number" class="resistance" step="0.1" value="140"></td><td><input type="number" class="temperature" step="0.1" value="30"></td><td class="action-cell"><button class="btn btn-danger" onclick="deleteRow(this)">删除</button></td></tr></tbody></table><div class="buttons"><button class="btn btn-primary" onclick="addRow()">添加行</button><button class="btn btn-success" onclick="calculateFit()">计算拟合</button></div></div><div class="result-section"><h2>拟合结果</h2><div class="equation" id="equation-result">拟合方程将显示在这里</div><div class="kb-values" id="kb-values">k = - , b = -</div><div class="r-squared" id="r-squared-result">决定系数将显示在这里</div><div class="chart-container" id="fit-chart"></div></div></div><script>// 全局变量存储图表实例 let fitChart = null;// 添加新行function addRow() {const tbody = document.querySelector('#data-table tbody');const newRow = document.createElement('tr');newRow.innerHTML = `<td><input type="number" class="resistance" step="0.1" value="0"></td><td><input type="number" class="temperature" step="0.1" value="0"></td><td class="action-cell"><button class="btn btn-danger" onclick="deleteRow(this)">删除</button></td>`;tbody.appendChild(newRow);}// 删除行function deleteRow(button) {const tbody = document.querySelector('#data-table tbody');const row = button.parentNode.parentNode;if (tbody.rows.length > 1) { // 确保至少保留一行 tbody.removeChild(row);} else {alert("至少需要保留一行数据");}}// 获取数据function getData() {const rows = document.querySelectorAll('#data-table tbody tr');const data = [];rows.forEach(row => {const resistance = parseFloat(row.querySelector('.resistance').value);const temperature = parseFloat(row.querySelector('.temperature').value);if (!isNaN(resistance) && !isNaN(temperature)) {data.push([resistance, temperature]);}});return data;}// 最小二乘法拟合function linearRegression(data) {let sumX = 0, sumY = 0, sumXY = 0, sumXX = 0;const n = data.length;data.forEach(point => {sumX += point[0];sumY += point[1];sumXY += point[0] * point[1];sumXX += point[0] * point[0];});const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);const intercept = (sumY - slope * sumX) / n;return { slope, intercept };}// 计算决定系数R²function calculateRSquared(data, slope, intercept) {// 计算y的平均值 const yMean = data.reduce((sum, point) => sum + point[1], 0) / data.length;// 计算总平方和 const totalSumOfSquares = data.reduce((sum, point) => {return sum + Math.pow(point[1] - yMean, 2);}, 0);// 计算残差平方和 const residualSumOfSquares = data.reduce((sum, point) => {const predictedY = slope * point[0] + intercept;return sum + Math.pow(point[1] - predictedY, 2);}, 0);// 计算R² const rSquared = 1 - (residualSumOfSquares / totalSumOfSquares);return rSquared;}// 计算拟合function calculateFit() {const data = getData();if (data.length < 2) {alert("至少需要两个有效数据点才能进行拟合");return;}// 执行线性回归 const { slope, intercept } = linearRegression(data);// 计算决定系数 const rSquared = calculateRSquared(data, slope, intercept);// 显示结果:k、b单独一行 document.getElementById('equation-result').textContent = `拟合方程: y = ${slope.toFixed(6)} x + ${intercept.toFixed(6)}`;document.getElementById('kb-values').textContent = `k = ${slope.toFixed(6)} , b = ${intercept.toFixed(6)}`;document.getElementById('r-squared-result').textContent = `决定系数 R² = ${rSquared.toFixed(6)}`;// 绘制图表 drawChart(data, slope, intercept);}// 绘制图表function drawChart(data, slope, intercept) {const chartDom = document.getElementById('fit-chart');// 如果已有图表实例,先销毁if (fitChart) {fitChart.dispose();}// 创建新图表 fitChart = echarts.init(chartDom);// 对x值进行排序,以便绘制平滑的拟合线 const sortedData = [...data].sort((a, b) => a[0] - b[0]);const minX = Math.min(...sortedData.map(point => point[0]));const maxX = Math.max(...sortedData.map(point => point[0]));// 生成拟合线上的点 const fitLine = [[minX, slope * minX + intercept],[maxX, slope * maxX + intercept]];// 计算用于自动设置坐标轴范围的值(包含数据点与拟合线) const allX = sortedData.map(p => p[0]).concat(fitLine.map(p => p[0]));const allY = sortedData.map(p => p[1]).concat(fitLine.map(p => p[1]));const rawMinX = Math.min(...allX);const rawMaxX = Math.max(...allX);const rawMinY = Math.min(...allY);const rawMaxY = Math.max(...allY);// 添加小的边距(当范围为0时提供默认边距) const xRange = rawMaxX - rawMinX;const yRange = rawMaxY - rawMinY;const xPad = xRange === 0 ? Math.abs(rawMinX) * 0.1 + 1 : xRange * 0.06;const yPad = yRange === 0 ? Math.abs(rawMinY) * 0.1 + 1 : yRange * 0.06;const xMin = rawMinX - xPad;const xMax = rawMaxX + xPad;const yMin = rawMinY - yPad;const yMax = rawMaxY + yPad;// 配置选项 const option = {title: {text: '电阻-温度关系拟合',left: 'center'},tooltip: {trigger: 'axis',axisPointer: { type: 'cross' },formatter: function (params) {// params 是一个数组,里面包含两个 series 的数据(scatter 和 line) const parts = params.map(p => {if (p.seriesType === 'scatter') {return `${p.marker} ${p.seriesName}: 电阻 ${p.data[0]} Ω, 温度 ${p.data[1]} °C`;} else if (p.seriesType === 'line') {return `${p.marker} ${p.seriesName}: 拟合值 ${p.data[1].toFixed(2)} °C`;} else {return '';}});return parts.join('<br/>');}},legend: {data: ['原始数据', '拟合直线'],top: 30},xAxis: {type: 'value',name: '电阻值 (Ω)',nameLocation: 'middle',nameGap: 30,min: xMin,max: xMax},yAxis: {type: 'value',name: '温度值 (°C)',nameLocation: 'middle',nameGap: 30,min: yMin,max: yMax},series: [{name: '原始数据',type: 'scatter',data: sortedData,symbolSize: 8},{name: '拟合直线',type: 'line',data: fitLine,lineStyle: {width: 2},symbol: 'none'}]};// 使用配置项和数据显示图表 fitChart.setOption(option);}// 页面加载时初始化图表 window.onload = function() {calculateFit();};// 窗口大小变化时调整图表大小 window.addEventListener('resize', function() {if (fitChart) {fitChart.resize();}});</script> </body> </html>