python|Flask&bootstrap&echarts简单应用

上手做了一个简单的小系统,这才对flask的整个流程有所理解。主要为数据库配置及简单使用、前端bootstrap框架、前后端通过Ajax传值、前端echarts绘图。
本文对flask、bootstrap、echarts的结合使用做简单记录。

0 系统简介

系统主界面如下,主要由用户输入处方和支持度、置信度、提升度阈值,系统前端显示频繁项集表、关联规则表和复杂网络图。
(真的丑啊(不过能写出来就很开心辣

1 Flask部分

flask官方文档 http://docs.jinkan.org/docs/flask/index.html
flask教程 http://www.pythondoc.com/flask-mega-tutorial/
flask教程 https://www.w3cschool.cn/flask/flask_overview.html

以下为文件间关系:
wsgi.py为系统入口文件;config.py为配置文件,如数据库的连接
App目录则包含其他文件:algorithm目录存放后端算法;static目录存放静态文件,如js/css/image;templates目录存放前端HTML文件;models.py主要用于数据库建库;route.py为路由视图文件;test.py用于测试数据库是否成功,可忽略。
PS:由于本系统十分简单,非庞大的项目,故未涉及蓝图等内容。
在这里插入图片描述

1.1 wsgi.py

在这里插入图片描述
有时候代码中开启debug模式不太管用,需要按下面的步骤选择FLASK_DEBUG,就ok了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 config.py + models.py

配置部分主要为数据库连接

SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:password@localhost:3306/xgfy'
#格式  'mysql+pymysql://用户名:密码@localhost:端口/数据库'

在这里插入图片描述
将数据库每个表重新建类,便于后端使用
在这里插入图片描述
查询通过filter_by

在这里插入图片描述

1.3 router.py

路由部分由不同路由组成,这是最简单的格式

@app.route('/')     #默认路由,名称自定义
def Apriori_home():     #函数名称自定义
    return render_template('Apriori.html')     #此路由返回的是渲染'Apriori.html'界面

在这里插入图片描述

1.4 jinjia2传值至前端

为啥要用jinjia2嘞,本来前端数据都是写死的,但是需要对前端结果分析然后将后端数据动态传到前端时,就需要一种方法来表示后端的各种数据或参数。

flask官网文档中有jinjia2介绍部分

康这个例子,后端生成freqSetNew,然后传至前端生成表格
简单来说,就是看前端本来需要啥数据,换成后端的某个参数,加上俩大括号。其他的语法和python一样,如判断、循环、列表字典等。

在这里插入图片描述

1.5 Ajax

Ajax教程 https://www.w3school.com.cn/ajax/index.asp
jQuery-Ajax教程 https://www.w3school.com.cn/jquery/ajax_ajax.asp

flask可以实现前后端分离,前端写前端,后端写后端,可是咋把二者连接起来嘞,就需要使用Ajax
比如说,前端输入一个text,按某个button之后,后端就接收到这个text数据,对它各种操作再返回前端一个表格
下面来康康怎么通过Ajax,前端->后端传送数据,后端->前端返回表格

1.5.1 前端向后端传递数据

前端点击id为analyze_btn的按钮之后,触发click函数。获取四个参数,并封装为data
在这里插入图片描述
后端router通过request.form.get(“参数”) 获得该参数对应的值
在这里插入图片描述

1.5.2 后端向前端传递响应

该路由对前端传递的4个参数一顿操作后,返回的是freqSetNew,rulesNew,nodes,links这几个参数
在这里插入图片描述
前端Ajax
对应的路由,类型,数据,是否为异步,如果成功则出现相应div的界面,如果失败。

  • data是上面前端的几个参数
  • result是后端路由返回的freqSetNew,rulesNew,nodes,links这几个参数
  • 这样就连接成功辣

注意:可以适当添加console.log(“数据”);语句(相当于print)进行测试,在chrome中右击检查可以查看。
在这里插入图片描述

2 bootstrap部分

2.1 下载

官网下载地址 https://v4.bootcss.com/docs/getting-started/download/

使用前直接按照官网示例引入link和script即可
在这里插入图片描述

2.2 使用

官网文档 https://v4.bootcss.com/docs/components/alerts/

文档中“页面内容”“布局”“组件”可供选择
下面举两个栗子

2.2.1 垂直侧边导航栏

以“组件”-“导航(Navs)”中垂直导航(即侧边导航栏)为例
在这里插入图片描述
把官网代码贴进去就可,导航条宽度、颜色等内容可以自由调节
在这里插入图片描述

2.2.2 带分页的表格

这玩意官网有点难找

戳链接 https://www.bootstrap-table.com.cn/

和之前一样,找到自己喜欢的样式,直接贴到代码里,可直接用

3 echarts

3.1 下载

echarts官网 https://echarts.apache.org/zh/index.html
社区 https://gallery.echartsjs.com/explore.html#sort=ranktimeframe=allauthor=all

引入时注意文件所在位置
在这里插入图片描述

3.2 使用

以该关系图为例 https://gallery.echartsjs.com/editor.html?c=x1wc1W6Eyr

使用时可以直接把示例代码贴进去
步骤可以简化为以下几点,可以将其封装为函数,Ajax中直接调用

#1、初始化一个echarts(通过id获取图片放置位置)
var myChart = echarts.init(document.getElementById('contact'));
#2、定义nodes、links数据(注意格式内容要和官网示例保持一致)
#3、对nodes、links进行操作,这部分直接复制粘贴官网示例即可
#4、设置option
myChart.setOption(option);

nodes、links数据是后端通过Ajax传值的,Ajax中如果成功则调用echarts绘图函数
在这里插入图片描述
在这里插入图片描述

4 所有代码

4.1 wsgi.py代码

from App import app
from flask_script import Manager, Server
from App import route

app = app
manager = Manager(app)
manager.add_command("runserver", Server(host='0.0.0.0', port=5000, use_debugger=True))

if __name__ == '__main__':
    app.run('127.0.0.1', debug=True)

4.2 route.py代码

from App import app  # 导入已创建的app
from flask import Flask,render_template,request
import json,re
from App.algorithm.Apriori import Apriori
from App.algorithm.Apriori.graph import genNodeLink

@app.route('/')
def Apriori_home():
    return render_template('Apriori.html')


# 画频繁项集表和关联规则表的路由,返回新界面
@app.route('/api/tb_pic',  methods=['POST'])
def associationRule():
    if request.method == 'POST':
        # 获取参数值
        dataSet = request.form.get('dataSet')
        minSup = float(request.form.get('minSup'))
        minConf = float(request.form.get('minConf'))
        minLift = float(request.form.get('minLift'))
        dataSetAppendNew = None
        typeRelated = False
        maxCount = 4    # 最大频繁项集数

        datasetNew = []

        # 将输入处方转换为list
        items = dataSet.split('|')
        for item in items:
            elements = re.split(r'[;;,,、]', item)
            datasetNew.append(elements)

        itemSet,freqSet,rules = Apriori.loadApriori(dataset=datasetNew,
                                                    dataSetAppend=dataSetAppendNew,
                                                    minSup=minSup,
                                                    minConf=minConf,
                                                    minLift=minLift,
                                                    typeRelated=typeRelated,
                                                    maxCount=maxCount)

        freqSetNew = Apriori.SetsToJson(itemSet,freqSet)    # 转换格式后的频繁项集
        rulesNew = Apriori.RulesToJson(rules)   # 转换格式后的关联规则
        # freqSetDemo: [{'item': 't', 'supp': 0.5}, {'item': 'r', 'supp': 0.5}]
        # rulesDemo: [{'conf': 1.0, 'supp': 0.3333333333333333, 'leftNode': 'q', 'rule': 'q-->z', 'lift': 1.2, 'rightNode': 'z'}]

        nodes, links = genNodeLink(rulesNew)
        return render_template("Apriori_tbpic.html",
                               freqSetNew=dict(enumerate(freqSetNew)),
                               rulesNew=dict(enumerate(rulesNew)),
                               nodes=nodes, links=links)


# 画图的路由,传递nodes结点和links线
@app.route('/api/tb_pic1',  methods=['POST'])
def associationRule1():
    if request.method == 'POST':
        # 获取参数值
        dataSet = request.form.get('dataSet')
        minSup = float(request.form.get('minSup'))
        minConf = float(request.form.get('minConf'))
        minLift = float(request.form.get('minLift'))
        dataSetAppendNew = None
        typeRelated = False
        maxCount = 4    # 最大频繁项集数

        datasetNew = []

        # 将输入处方转换为list
        items = dataSet.split('|')
        for item in items:
            elements = re.split(r'[;;,,、]', item)
            datasetNew.append(elements)

        itemSet,freqSet,rules = Apriori.loadApriori(dataset=datasetNew,
                                                    dataSetAppend=dataSetAppendNew,
                                                    minSup=minSup,
                                                    minConf=minConf,
                                                    minLift=minLift,
                                                    typeRelated=typeRelated,
                                                    maxCount=maxCount)

        freqSetNew = Apriori.SetsToJson(itemSet,freqSet)    # 转换格式后的频繁项集
        rulesNew = Apriori.RulesToJson(rules)   # 转换格式后的关联规则
        # freqSetDemo: [{'item': 't', 'supp': 0.5}, {'item': 'r', 'supp': 0.5}]
        # rulesDemo: [{'conf': 1.0, 'supp': 0.3333333333333333, 'leftNode': 'q', 'rule': 'q-->z', 'lift': 1.2, 'rightNode': 'z'}]

        nodes, links = genNodeLink(rulesNew)

        return json.dumps({'nodes':nodes,'links':links})



# @app.errorhandler(404)
# def internal_error(error):
#     return render_template('404.html'), 404

4.3 Apriori.html代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>新型冠状病毒肺炎</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css"
          integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.css">

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
            integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
            crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.min.js"
            integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
            crossorigin="anonymous"></script>
    <script src="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.js"></script>
    <script src="https://unpkg.com/bootstrap-table@1.15.3/dist/locale/bootstrap-table-zh-CN.min.js"></script>
    <script src={{url_for("static",filename="echarts/echarts.min.js")}}></script>
    <script src={{url_for("static",filename="echarts/dataTool.js")}}></script>
{#    <script src="dataTool.js"></script>#}
</head>

<body>
<div class="main_content">
    {#    界面头#}
    <nav class="navbar navbar-dark bg-primary">
        <div>
            <h4></h4>
            <h4>新型冠状病毒肺炎中医药推荐方分析系统</h4>
            <h4></h4>
        </div>
    </nav>
    {#    侧边导航栏#}
    <div class="row">
        <div class="col-2">
            <div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
                <a class="nav-link active" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab"
                   aria-controls="v-pills-home" aria-selected="true">关联分析</a>
                <a class="nav-link" id="v-pills-profile-tab" data-toggle="pill" href="#v-pills-profile" role="tab"
                   aria-controls="v-pills-profile" aria-selected="false">聚类分析</a>
            </div>
        </div>
        <div class="col-9">
            <div class="tab-content" id="v-pills-tabContent">
                {#                关联部分#}
                <div class="tab-pane fade show active" id="v-pills-home" role="tabpanel"
                     aria-labelledby="v-pills-home-tab">
                    {#                    输入框+查找按钮#}
                    <div class="input-group mb-4">
                        <input id="text_dataSet" type="text" class="form-control" value="麻黄,桂枝,杏仁,甘草|桂枝,芍药,甘草|麻黄,杏仁,芍药,甘草|桂枝,芍药"
                               aria-label="Recipient's username" aria-describedby="basic-addon2">
{#                        <button type="button" class="btn btn-primary">确定</button>#}
                    </div>
                    {#                    三个输入框:最小支持度,最小置信度,最小提升度#}
                    <div class="input-group mb-3">
                        <input id="text_minSup" type="number" class="form-control input-sm" value="0.5" step="0.1"
                               aria-label="Recipient's username" aria-describedby="inputGroup-sizing-sm">
                        <input id="text_minConf" type="number" class="form-control input-sm" value="0.5" step="0.1"
                               aria-label="Recipient's username" aria-describedby="inputGroup-sizing-sm">
                        <input id="text_minLift" type="number" class="form-control input-sm" value="0.5" step="0.1"
                               aria-label="Recipient's username" aria-describedby="inputGroup-sizing-sm">
                        <button id="analyze_btn" type="button" class="btn btn-primary">确定</button>
                    </div>

                    {#                    导航:选择 频繁项集/关联规则/复杂网络#}
                    <ul class="nav nav-tabs" id="myTab" role="tablist">
                        <li class="nav-item">
                            <a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab"
                               aria-controls="home" aria-selected="true">频繁项集</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab"
                               aria-controls="profile" aria-selected="false">关联规则</a>
                        </li>
                        <li class="nav-item" >
                            <a class="nav-link" id="contact-tab" data-toggle="tab" href="#contact" role="tab"
                               aria-controls="contact" aria-selected="false">复杂网络</a>
                        </li>
                    </ul>
                    {#                    导航下内容#}
                    <div class="tab-content" id="myTabContent">
                        {#                        频繁项集#}
                        <div class="tab-pane fade show active" id="id_fre" role="tabpanel" aria-labelledby="home-tab">
                        </div>
                        {#                        关联规则#}
                        <div class="tab-pane fade" id="id_ass" role="tabpanel" aria-labelledby="profile-tab">
                        </div>
                        {#                        复杂网络#}
                        <div class="tab-pane fade" id="id_pic" role="tabpanel" aria-labelledby="contact-tab" >
                         </div>
                    </div>
                </div>


                {#                聚类部分#}
                <div class="tab-pane fade" id="v-pills-profile" role="tabpanel" aria-labelledby="v-pills-profile-tab">
                    聚类内容
                </div>
            </div>
        </div>
    </div>
</div>
</body>


<script type=text/javascript>
    $('#analyze_btn').click(function () {
        var dataSet = $("#text_dataSet").val();
        var minSup = $("#text_minSup").val();
        var minConf = $("#text_minConf").val();
        var minLift = $("#text_minLift").val();
        var data = {
            minSup: minSup,
            minConf: minConf,
            minLift: minLift,
            dataSet: JSON.stringify(dataSet),
        };

        {#console.log(data); #}
        {#console.log相当于print,输出数据,chrome检查中console可查看#}

        //画表
        $.ajax({
            url: '/api/tb_pic',
            type: 'POST',
            data: data,
            async: false,
            success: function (result) {
                {#console.log(result);#}
                $("#id_fre").html(result)
                $("#id_ass").html(result)
                {#console.log(result);#}
            },
            error: function (err) {
                console.log(err)
                {#$.messager.progress('close');#}
            }
        });

        //画图
        $.ajax({
            url: '/api/tb_pic1',
            type: 'POST',
            data: data,
            dataType: "json",
            async: false,
            {#传递的rusult是nodes和links,注意:要和echarts官网示例中的nodes、links格式一致#}
            success: function (result) {
                {#console.log(result);#}
                console.log(result.nodes);
                console.log(result.links);
                {#调用画图函数#}
                init_graph(result.nodes, result.links);
            },
            error: function (err) {
                console.log(err)
                {#$.messager.progress('close');#}
            }
        });
    });


    function init_graph(nodes, links) {
        {#创建一个echarts,通过Apriori_tbpic.html中id"contact"#}
        var myChart = echarts.init(document.getElementById('contact'));
        let data = {
            nodes: JSON.parse(JSON.stringify(nodes)),
            links: links
        }
        {#下面内容复制粘贴官网示例即可#}
        const color1 = '#006acc';
        data.nodes.forEach(node => {
            node.symbolSize = 50;
            node.itemStyle = {
                color: color1
            };
        });

        data.links.forEach(link => {
            link.label = {
                align: 'center',
                fontSize: 12
            };
        });

        let categories = [{}
        ]
        option = {

            legend: [{
                // selectedMode: 'single',
                data: categories.map(x => x.name),
                // icon: 'circle'
            }],
            series: [{
                type: 'graph',
                layout: 'force',
                symbolSize: 58,
                draggable: true,
                roam: true,
                focusNodeAdjacency: true,
                edgeSymbol: ['', 'arrow'],
                // edgeSymbolSize: [80, 10],
                edgeLabel: {
                    normal: {
                        show: true,
                        textStyle: {
                            fontSize: 20
                        },
                        formatter(x) {
                            return x.data.name;
                        }
                    }
                },
                label: {
                    show: true,
                },
                force: {
                    repulsion: 2000,
                    edgeLength: 200
                },
                data: data.nodes,
                links: data.links
            }]
        }
        // 第四处:
        myChart.setOption(option);
    }
</script>
</html>

4.4 Apriori_tbpic.html代码

<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.css">
<script src="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.js"></script>
<script src="https://unpkg.com/bootstrap-table@1.15.3/dist/locale/bootstrap-table-zh-CN.min.js"></script>
{#<script src="echarts.min.js"></script>#}
{#<script src={{url_for("static",filename="echarts.js")}}></script>#}
<script src={{url_for("static",filename="echarts/echarts.min.js")}}></script>
<script src={{url_for("static",filename="echarts/dataTool.js")}}></script>

{#                    导航下内容#}
<div class="tab-content" id="myTabContent">
    {#                        频繁项集#}
    <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
        <table data-toggle="table" data-pagination="true" data-search="true">
            <thead>
            <tr>
                <th scope="col">序号</th>
                <th scope="col">频繁项集</th>
                <th scope="col" data-sortable="true">频率</th>
            </tr>
            </thead>
            <tbody>
            {% for ind,foo in freqSetNew.items() %}
                <tr>
                <td scope="row">{{ ind + 1 }}</td>
                <td>{{ foo['item'] }}</td>
                <td>{{ foo['supp'] }}</td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
    </div>
    {#                        关联规则#}
    <div class="tab-pane fade" id="profile" role="tabpanel" aria-labelledby="profile-tab">
        <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
            <table data-toggle="table" data-pagination="true" data-search="true">
                <thead>
                <tr>
                    <th scope="col">序号</th>
                    <th scope="col">规则</th>
                    <th scope="col" data-sortable="true">支持度</th>
                    <th scope="col" data-sortable="true">置信度</th>
                    <th scope="col" data-sortable="true">提升度</th>
                </tr>
                </thead>
                <tbody>
                {% for ind,foo in rulesNew.items() %}
                    <tr>
                        <td scope="row">{{ ind + 1 }}</td>
                        <td>{{ foo['rule'] }}</td>
                        <td>{{ foo['supp'] }}</td>
                        <td>{{ foo['conf'] }}</td>
                        <td>{{ foo['lift'] }}</td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
    {#                        复杂网络#}
    <div class="tab-pane fade" id="contact" style="width: 1000px;height:500px;" role="tabpanel" aria-labelledby="contact-tab">
    </div>

</div>

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Flask Bootstrap是一个基于Flask框架的开源前端工具包,它集成了Bootstrap框架,使得开发者可以更方便地构建美观、响应式的Web应用界面。Bootstrap提供了大量的CSS和JavaScript组件,包括页面布局、按钮、表单、导航等,使得开发者能够快速地创建出具有一致性和响应式设计的界面。 而Echarts是一个开源的数据可视化库,它基于JavaScript,并提供了丰富的图表类型和交互功能。Echarts可以支持多种图表类型,包括折线图、柱状图、饼图等,同时也支持动态更新和交互操作,使得数据可视化更加生动、直观。 结合Flask BootstrapEcharts可以实现强大的Web应用开发和数据可视化功能。Flask Bootstrap提供了美观的前端界面,而Echarts可以将数据转化为各种图表,通过使用它们,我们可以快速实现数据的可视化展示,使得Web应用更加互动和有趣。 在Flask应用中使用Flask BootstrapEcharts也相对简单。只需将Flask Bootstrap集成到Flask应用中,然后通过引入Echarts的相关JavaScript库来实现数据的可视化效果。开发者可以根据具体的需求选择不同的图表类型,通过简单的配置和数据传入,即可实现出具有丰富功能的数据可视化界面。 总结而言,Flask BootstrapEcharts作为前端工具包和数据可视化库的结合,为开发者提供了强大的开发工具和数据展示手段,使得Web应用开发和数据可视化更加便捷、高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值