基于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)
            }
相关推荐
蹦蹦跳跳真可爱5892 分钟前
Python----数据分析(Matplotlib四:Figure的用法,创建Figure对象,常用的Figure对象的方法)
python·数据分析·matplotlib
小杨40431 分钟前
python入门系列六(文件操作)
人工智能·python·pycharm
谦行1 小时前
前端视角 Java Web 入门手册 4.4:Web 开发基础—— Listener
java·后端
xiaozaq1 小时前
在Eclipse中安装Lombok插件
java·python·eclipse
云空1 小时前
《FastRTC:开启实时音视频应用开发新时代》
python·实时音视频
非优秀程序员1 小时前
使用Python给自己网站生成llms.txt
人工智能·后端·架构
尘鹄1 小时前
一文讲懂Go语言如何使用配置文件连接数据库
开发语言·数据库·后端·golang
九丶黎2 小时前
爬虫案例七Python协程爬取视频
爬虫·python·音视频
benben0442 小时前
Django小白级开发入门
后端·python·django
HerrFu2 小时前
可狱可囚的爬虫系列课程 19:静态页面和动态页面之分
爬虫·python