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

前言

开发语言: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
        氨氮预测.xlsx
        plotly-2.2.0.min.js
    templates
        es.html
        index.html
        lwlr.html
        rw.html
    main.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"}), 400
    if 'sheetname' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    if 'NH3-NO2' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    # 根据表单数据打开对应excel
    date,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.T
    W = weights
    beta = 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"}), 400
    if 'sheetname' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    if 'NH3-NO2' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    if 'k' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    # 根据表单数据打开对应excel
    date,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"}), 400
    if 'sheetname' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    if 'NH3-NO2' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    if 'k' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    k=float(form_data['k'])
    if k<0.01 or k>0.99:
        return jsonify({"error": "Invalid form data format"}), 400
    # 根据表单数据打开对应excel
    date,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"}), 400
    if 'sheetname' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    if 'NH3-NO2' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    if 'k1' not in form_data:
        return jsonify({"error": "Invalid form data format"}), 400
    if '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"}), 400
    if k1>=len(date):
        return jsonify({"error": "Invalid form data format"}), 400
    # 根据表单数据打开对应excel
    date,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

整体框架

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>

动画

html 复制代码
@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把变量的值相互替换

html 复制代码
/*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.documentElement
                const 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)
            }

响应式布局

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

html 复制代码
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;
            }

鼠标浮动光影

html 复制代码
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);
            }

异步表单提交

javascript 复制代码
async function submitForm(event){
                event.preventDefault()
                const submitButton = event.target.querySelector('button[type="submit"]')
                submitButton.disabled = true
                const 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
                }
            }

表格绘制函数

javascript 复制代码
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)
            }

图像数据绘制

javascript 复制代码
function createPlot(data){
                const y=data.y
                const 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基本相同,主要区别在画图

javascript 复制代码
function createPlot(data){
                data.y1.pop()
                data.y2.shift()
                data.y2.shift()
                const y1=data.y1
                const x1=Array.from({ length: y1.length }, (_, index) => index)
                const y2=data.y2
                const 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)
            }

绘表

javascript 复制代码
            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)
            }
相关推荐
DLYSB_1 小时前
存储运维实战:基于 Ceph Event 监听与 Python 适配器的分布式存储健康度物理声光响应架构
运维·ceph·python·报警灯
陈随易1 小时前
FFmpeg 9.0 发布,代号 Lei,音视频处理再升级
前端·后端·程序员
阿童木写作2 小时前
跨境图片翻译工具多合一,批量图片视频字幕翻译加智能抠图
人工智能·python·音视频·语音识别
阿童木写作3 小时前
Python实现Temu图片批量翻译自动化教程
运维·人工智能·python·自动化
就是一只白4 小时前
复制地理信息python版本
python
凌虚4 小时前
面向 MySQL 用户的 PostgreSQL 快速上手指南
数据库·后端·架构
看浪的路人5 小时前
第1讲:Agent 到底是什么?和 Chatbot 有什么区别
python·ai
瓦学妹5 小时前
什么是网络索引?它是如何工作的?
大数据·网络·python·网络爬虫
IT_陈寒6 小时前
Vite静态资源引用这个坑我踩得有点疼
前端·人工智能·后端
天天爱吃肉82186 小时前
商用车多体动力学实战笔记|第6篇:动力传动系统(发动机、变速箱、分动器、TCS、LSD限滑差速)
大数据·人工智能·笔记·python·嵌入式硬件·汽车