基于flask的一个数据展示网页

news/2025/3/11 3:36:04/

前言

开发语言:python3.11.6、javascript、html5‘、css3

开发框架:flask、plotly.js

开发系统:windows10 22H2

开发编辑器:vscode

作用:展示水产养殖水体氨氮和亚硝酸盐时间序列数据,使用LWLR、ESE、DLM模型进行滚动预测并绘制曲线

开发初衷:为了项目汇报更具象

开源性质:完全开源,任意使用

项目资源获取https://pan.baidu.com/s/1V53DPLVP7FT65-FtYVP44Q?pwd=1sdthttps://pan.baidu.com/s/1V53DPLVP7FT65-FtYVP44Q?pwd=1sdt

文件目录展示

图表展示static氨氮预测.xlsxplotly-2.2.0.min.jstemplateses.htmlindex.htmllwlr.htmlrw.htmlmain.py

效果展示

代码说明

基于flask的一个数据展示网页

main.py

导包

python">from flask import Flask,render_template,request,jsonify
import pandas as pd
import numpy as np
from statsmodels.tsa.holtwinters import SimpleExpSmoothing
from scipy.signal import savgol_filter
from werkzeug.datastructures import ImmutableMultiDict

全局变量

python">app=Flask(__name__)
excel_path='./static/氨氮预测.xlsx'

程序启动入口

python">if __name__=='__main__':app.run(debug=True,port=5002,host='0.0.0.0')

html页面响应函数

python">@app.route('/',methods=['GET'])
def index():return render_template('index.html')
@app.route('/lwlr',methods=['GET'])
def page_lwlr():return render_template('lwlr.html')@app.route('/es',methods=['GET'])
def es():return render_template('es.html')@app.route('/rw',methods=['GET'])
def rw():return render_template('rw.html')

excel文件打开函数

python">def open_excel(form_data,key1='sheetname',key2='NH3-NO2'):sheet_index=form_data[key1]column_name=form_data[key2]df=pd.read_excel(excel_path,f'Sheet{sheet_index}').dropna()return df['DATE'].tolist(),df[column_name].tolist()

index.html表单数据处理函数

python">@app.route('/submit',methods=['POST'])
def submit():# 获取表单数据form_data=request.form# 表单数据严格匹配审查if not isinstance(form_data, ImmutableMultiDict):return jsonify({"error": "Invalid form data format"}), 400if 'sheetname' not in form_data:return jsonify({"error": "Invalid form data format"}), 400if 'NH3-NO2' not in form_data:return jsonify({"error": "Invalid form data format"}), 400# 根据表单数据打开对应exceldate,y=open_excel(form_data)# 返回时间序列数据return jsonify({'date':date,'y':y})

lwlr.html表单数据处理函数

python"># lwlr数学定义
def lwlr(test_point,X,y,k):m = X.shape[0]weights = np.eye(m)for i in range(m):xi = X[i]weights[i, i] = np.exp(np.dot((xi - test_point), (xi - test_point).T) / (-2.0 * k**2))X_T = X.TW = weightsbeta = np.linalg.inv(X_T @ (W @ X)) @ (X_T @ (W @ y))return test_point @ beta@app.route('/submit_lwlr',methods=['POST'])
def submit_lwlr():# 获取表单数据form_data=request.form# 表单数据严格匹配审查if not isinstance(form_data, ImmutableMultiDict):return jsonify({"error": "Invalid form data format"}), 400if 'sheetname' not in form_data:return jsonify({"error": "Invalid form data format"}), 400if 'NH3-NO2' not in form_data:return jsonify({"error": "Invalid form data format"}), 400if 'k' not in form_data:return jsonify({"error": "Invalid form data format"}), 400# 根据表单数据打开对应exceldate,y=open_excel(form_data)# 适当转化便于后续匹配k=float(form_data['k'])x=np.arange(len(date)).reshape(-1,1)# 滚动预测y_preds=[]for i in range(2,x.shape[0]+1):X_pred=np.array([i]).reshape(-1,1)y_pred=[lwlr(test_point, x[:i], y[:i], k) for test_point in X_pred]y_preds.append(y_pred[0])# 根据需要可保留至小数2位y_preds=[round(x,2) for x in y_preds]# 返回原始数据和预测数据return jsonify({"date":date,"y1":y,"y2":y_preds})

es.html表单数据处理函数

python"># 平滑滤波
def exponential_smoothing(series, alpha=0.5):"""series: 时间序列数据alpha: 平滑系数"""result = [series[0]]  # 第一项为序列的第一值for n in range(1, len(series)):result.append(alpha * series[n] + (1 - alpha) * result[n-1])return result@app.route('/submit_es',methods=['POST'])
def submit_es():# 获取表单数据form_data=request.form# 表单数据严格匹配审查if not isinstance(form_data, ImmutableMultiDict):return jsonify({"error": "Invalid form data format"}), 400if 'sheetname' not in form_data:return jsonify({"error": "Invalid form data format"}), 400if 'NH3-NO2' not in form_data:return jsonify({"error": "Invalid form data format"}), 400if 'k' not in form_data:return jsonify({"error": "Invalid form data format"}), 400k=float(form_data['k'])if k<0.01 or k>0.99:return jsonify({"error": "Invalid form data format"}), 400# 根据表单数据打开对应exceldate,y=open_excel(form_data)# 进行滚动预测y_preds=exponential_smoothing(y,k)# 根据需要可保留至小数2位y_preds=[round(x,2) for x in y_preds]# 返回原始数据和预测数据return jsonify({"date":date,"y1":y,"y2":y_preds})

rw.html表单数据处理函数

python">@app.route('/submit_rwsg',methods=['POST'])
def submit_rwsg():# 获取表单数据form_data=request.form# 表单数据严格匹配审查if not isinstance(form_data, ImmutableMultiDict):return jsonify({"error": "Invalid form data format"}), 400if 'sheetname' not in form_data:return jsonify({"error": "Invalid form data format"}), 400if 'NH3-NO2' not in form_data:return jsonify({"error": "Invalid form data format"}), 400if 'k1' not in form_data:return jsonify({"error": "Invalid form data format"}), 400if 'k2' not in form_data:return jsonify({"error": "Invalid form data format"}), 400# 适当转化便于后续匹配k1=int(form_data['k1'])k2=int(form_data['k2'])# 表单数据严格审查if k1<=k2:return jsonify({"error": "Invalid form data format"}), 400if k1>=len(date):return jsonify({"error": "Invalid form data format"}), 400# 根据表单数据打开对应exceldate,y=open_excel(form_data)# 对原始数据进行SG滤波y=savgol_filter(res, window_length=k1, polyorder=k2)# 滚动预测res=[]for i in range(2,len(y)+1):model = SimpleExpSmoothing(y[:i])fit = model.fit()# 预测未来1天forecast = fit.forecast(1)[0]res.append(forecast)# 对模型输出进行极小值抑制res=[x if x>=0.05 else 0.05 for x in res ]y_preds=res.tolist()# 根据需要可保留至小数2位y_preds=[round(x,2) for x in y_preds]# 返回原始数据和预测数据return jsonify({"date":date,"y1":y,"y2":y_preds})

index.html

整体框架

<body><nav><a href="/">数据集</a><a href="/lwlr">LWLR</a><a href="/es">ES</a><a href="/rw">RWSG</a></nav><header><form><select></select><select></select><button></button></form><button><botton></header><main><section><table id="table"></table></section><section><div id="plot"></div></section></main>

动画

@keyframes bottomIn{from {transform: translateY(4dvh);}to {transform: translateY(0);opacity: 1;}}@keyframes topIn{from {transform: translateY(-4dvh);}to {transform: translateY(0);opacity: 1;}}@keyframes rightIn{from {transform: translateX(30vw);}to {transform: translateX(0);opacity: 1;}}@keyframes leftIn{from {transform: translateX(-30vw);}to {transform: translateX(0);opacity: 1;}}nav{opacity: 0;animation: 1.1s topIn ease-out forwards;animation-delay: 0.3s;}header{opacity: 0;animation: 1s topIn ease-out forwards;animation-delay: 0.2s;}#left{opacity: 0;animation: 1.1s leftIn ease-out forwards;animation-delay: 0.3s;}#right{opacity: 0;animation: 1.1s rightIn ease-out forwards;animation-delay: 0.3s;}

背景切换

用全局css变量定义各模块的前景色和背景色,点击背景切换按钮则触发js把变量的值相互替换

/*css*/
a:hover,button:hover,select:hover{transform: scale(1.1);text-shadow: 0 0 3vw var(--f-color);box-shadow: 0 0 3vw var(--f-color);}
select{appearance: none;color: var(--f-color);background: var(--b-color);width: 8vw;height: 4dvh;border: 1px solid var(--f-color);border-radius: 1dvh;padding-left: 1vw;}
:root{--f-color:#cccccc;--b-color:#333333;}
/*js*/
function changeTheme(){const root=document.documentElementconst color1=window.getComputedStyle(root).getPropertyValue('--f-color').trim()const color2=window.getComputedStyle(root).getPropertyValue('--b-color').trim()root.style.setProperty('--f-color',color2)root.style.setProperty('--b-color',color1)}

响应式布局

所有模块大小使用相对视口尺寸定义

select{appearance: none;color: var(--f-color);background: var(--b-color);width: 8vw;height: 4dvh;border: 1px solid var(--f-color);border-radius: 1dvh;padding-left: 1vw;}

鼠标浮动光影

a:hover,button:hover,select:hover{transform: scale(1.1);text-shadow: 0 0 3vw var(--f-color);box-shadow: 0 0 3vw var(--f-color);}

异步表单提交

async function submitForm(event){event.preventDefault()const submitButton = event.target.querySelector('button[type="submit"]')submitButton.disabled = trueconst formData=new FormData(event.target)try{const response=await fetch('/submit',{method:'POST',body:formData})if (!response.ok) {throw new Error(`HTTP error! Status: ${response.status}`);}const data = await response.json()createTable(data)createPlot(data)}catch(error){console.error('Error submitting form:', error);alert('非法输入')}finally{submitButton.disabled = false}}

表格绘制函数

function createTable(data){const table=document.getElementById('table')table.innerHTML=''const thead=document.createElement('thead')const tr=document.createElement('tr')const th1=document.createElement('th')const th2=document.createElement('th')const tbody=document.createElement('tbody')th1.textContent='时间'tr.appendChild(th1)th2.textContent='index'tr.appendChild(th2)thead.appendChild(tr)table.appendChild(thead)for(let i=0;i<data.date.length;i++){const tr=document.createElement('tr')const td1=document.createElement('td')const td2=document.createElement('td')td1.textContent=data.date[i]tr.appendChild(td1)td2.textContent=data.y[i]tr.appendChild(td2)tbody.appendChild(tr)}table.appendChild(tbody)}

图像数据绘制

function createPlot(data){const y=data.yconst x=Array.from({length:y.length},(_,index)=>index)const traces=[{x,y,mode: "lines",type: "scatter"}]const layout={xaxis:{title:'时间',titlefont: {color: 'green',size:20},tickfont: {color: 'green',size:20}},yaxis:{title:'index',titlefont: {color: 'green',size:20},tickfont: {color: 'green',size:20}},paper_bgcolor: 'rgba(0,0,0,0)',plot_bgcolor: 'rgba(0,0,0,0)'}Plotly.newPlot("plot",traces,layout)}

其他html

与index.html基本相同,主要区别在画图

function createPlot(data){data.y1.pop()data.y2.shift()data.y2.shift()const y1=data.y1const x1=Array.from({ length: y1.length }, (_, index) => index)const y2=data.y2const x2=Array.from({ length: y2.length }, (_, index) => index+2)const trace1={x:x1,y:y1,name:'True',mode: "lines",type: "scatter"}const trace2={x:x2,y:y2,name:'lwlr-predict',mode: "lines",type: "scatter"}const y1y2=[trace1,trace2]const layout={xaxis:{title:'时间',titlefont: {color: 'green',size:20},tickfont: {color: 'green',size:20}},yaxis:{title:'index',titlefont: {color: 'green',size:20},tickfont: {color: 'green',size:20}},legend:{font:{color:'green',size:20}},showlegend:true,paper_bgcolor: 'rgba(0,0,0,0)',plot_bgcolor: 'rgba(0,0,0,0)'}Plotly.newPlot("plot",y1y2,layout)}

绘表

            function createTable(data){const table=document.getElementById('table')table.innerHTML=''const thead=document.createElement('thead')const tr=document.createElement('tr')const th1=document.createElement('th')const th2=document.createElement('th')const th3=document.createElement('th')const tbody=document.createElement('tbody')th1.textContent='时间'tr.appendChild(th1)th2.textContent='index'tr.appendChild(th2)th3.textContent='预测值'tr.appendChild(th3)thead.appendChild(tr)table.appendChild(thead)let lastDateStr = data.date[data.date.length-1]let lastDate = new Date(lastDateStr)lastDate.setDate(lastDate.getDate() + 1);let newDateStr = lastDate.toISOString().split('T')[0];data.date.push(newDateStr);data.y1.push(null)data.y2.unshift(null)data.y2.unshift(null)for(let i=0;i<data.y1.length;i++){const tr=document.createElement('tr')const td1=document.createElement('td')const td2=document.createElement('td')const td3=document.createElement('td')td1.textContent=data.date[i]tr.appendChild(td1)td2.textContent=data.y1[i]tr.appendChild(td2)td3.textContent=data.y2[i]tr.appendChild(td3)tbody.appendChild(tr)}table.appendChild(tbody)}


http://www.ppmy.cn/news/1578244.html

相关文章

正点原子[第三期]Arm(iMX6U)Linux移植学习笔记-2.1 uboot简介

前言&#xff1a; 本文是根据哔哩哔哩网站上“Arm(iMX6U)Linux系统移植和根文件系统构键篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。 引用&#xff1a; …

DeepSeek【部署 03】客户端应用ChatBox、AnythingLLM及OpenWebUI部署使用详细步骤

DeepSeek客户端应用 1.ChatBox2.AnythingLLM3.OpenWebUI4.总结 客户端软件提供可视化的模型及参数配置&#xff0c;人性化的对话窗口及文件上传功能&#xff0c;大大降低了大模型的使用门槛。 1.ChatBox Chatbox AI 是一款 AI 客户端应用和智能助手&#xff0c;支持众多先进的…

【前缀和与差分 C/C++】洛谷 P8218 求区间和

2025 - 03 - 09 - 第 72 篇 Author: 郑龙浩 / 仟濹 【前缀和与差分 C/C】 文章目录 洛谷 P8218 求区间和题目描述输入格式输出格式输入输出样例 #1输入 #1输出 #1 说明/提示思路代码 洛谷 P8218 求区间和 题目描述 给定 n n n 个正整数组成的数列 a 1 , a 2 , ⋯ , a n a_…

AI日报 - 2025年3月10日

AI日报 - 2025年3月10日 &#x1f31f; 今日概览&#xff08;60秒速览&#xff09; ▎&#x1f916; AGI突破 | Anthropic CEO预测强AI最早2026年到来 &#x1f52c; SAGE框架提升问答质量61.25%&#xff0c;Reflexion框架将GPT-4成功率提至91% ▎&#x1f4bc; 商业动向 | xA…

护照阅读器在旅游景区流程中的应用

在旅游景区的日常运营与管理中&#xff0c;为游客提供便捷、高效且安全的游览体验至关重要。护照阅读器作为先进的身份识别设备&#xff0c;在景区的自助购票、行李寄存以及自助安检等关键环节发挥着重要作用&#xff0c;极大地优化了景区的运营流程&#xff0c;提升了游客的满…

docker已创建容器设置自启动

在Docker中&#xff0c;你可以通过几种方式来设置容器在启动时自动运行。以下是几种常见的方法&#xff1a; 1. 使用docker run命令的--restart选项 当你使用docker run命令创建容器时&#xff0c;可以使用--restart选项来指定容器的重启策略。例如&#xff0c;如果你想让容器…

thinkphp5.1 在fetch模版就超时

场景 当被渲染模版不存在&#xff0c;请求不响应任何内容&#xff0c;过一会就timeout 排查过程 使用xdebug,追踪代码&#xff0c;发现走到D:\temporary_files\m40285_mini\40285_mini\thinkphp\library\think\exception\Handle.php&#xff0c;进入死循环&#xff0c;一直…

django中路由配置规则的详细说明

在 Django 中,路由配置是将 URL 映射到视图函数或类视图的关键步骤,它决定了用户请求的 URL 会触发哪个视图进行处理。以下将详细介绍 Django 中路由配置的规则、高级使用方法以及多个应用配置的规则。 基本路由配置规则 1. 项目级路由配置 在 Django 项目中,根路由配置文…