Flask+Pyeharts前端实时动态展现多曲线多图实践

一:FLASK和Pyechats简介

        Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。另外,Flask还有很强的定制性,用户可以根据自己的需求来添加相应的功能,在保持核心功能简单的同时实现功能的丰富与扩展,其强大的插件库可以让用户实现个性化的网站定制,开发出功能强大的网站。

        Flask的基本模式为在程序里将一个视图函数分配给一个URL,每当用户访问这个URL时,系统就会执行给该URL分配好的视图函数,获取函数的返回值并将其显示到浏览器上,其工作过程见图。

 

        Echarts 是一个由百度开源的数据可视化,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可。而 Python 是一门富有表达力的语言,很适合用于数据处理。Pyecharts是对Echarts的Python封装。

        本实践基于pyechats官方网站提供的FLask+Pyechats框架,在框架里根据自己的需求来实现相关功能的实践。

        官网链接:https://pyecharts.org/#/zh-cn/web_flask

二:代码结构

 1,新建一个Flask目录

mkdir dpt_flask
cd dpt_flask
mkdir templates

2,拷贝pyechats模板

        将 pyecharts 模板,位于 pyecharts.render.templates 拷贝至刚新建的 templates 文件夹

        附上模板下载链接:https://github.com/pyecharts/pyecharts/

 3,新建后端python代码文件app.py

        其总的代码结构如下:

.
├── app.py
├── static
│?? └── option.json
└── templates
    ├── index.html
    ├── macro
    ├── nb_jupyter_lab.html
    ├── nb_jupyter_notebook.html
    ├── nb_nteract.html
    ├── simple_chart.html
    └── simple_page.html

        关于static的文件夹及其文件作用,后面会讲到

三:功能实现

1,后端实现

        前端网页会定时从后端取数据进行动态实时显示,在具体实践中,数据是另外一个进程产生的,用zmq将数据从产生的地方传到本程序里(关于ZMQ的使用可查看我的另一篇博客https://blog.csdn.net/qq_27071221/article/details/119209941)。故单独起了一个线程去接收数据处理数据。具体代码如下:

头文件部分,主要是引入flask和pyechats的模块

import os
import zmq
import threading
from datetime import datetime
from flask.json import jsonify
from flask import Flask, render_template

from pyecharts import options as opts
from pyecharts.charts import Line
from pyecharts.globals import ThemeType

实例化Flask

app = Flask(__name__, static_folder="static",template_folder='templates')

Flask构造函数使用当前模块(__name __)的名称作为参数。

        我们这次要画的是曲线图(也可以说折线图),在后台实例化一个曲线图对象,并配置好相关参数,后面会将该配置好的曲线图参数传递到前端显示,该部分代码如下:

color = ['blue','cyan','green','red','darkorange','magenta','olive','black']

def line_base() -> Line:

    lineVol = Line(init_opts=opts.InitOpts(theme=ThemeType.SHINE))
    lineVol.add_xaxis([])
    for i in range(4):
        lineVol.add_yaxis(series_name="Thread"+str(i),y_axis=[],color=color[i],label_opts=opts.LabelOpts(is_show=False),)
    lineVol.set_global_opts(
            title_opts=opts.TitleOpts(title="XXXXX", pos_top="3%"),
            legend_opts=opts.LegendOpts(pos_top="5%"),
            toolbox_opts=opts.ToolboxOpts(is_show=True),
            tooltip_opts=opts.TooltipOpts(is_show=True, axis_pointer_type="cross", trigger="axis"),
            #datazoom_opts=opts.DataZoomOpts(type_="slider"),
            xaxis_opts=opts.AxisOpts(name='time'),
            yaxis_opts=opts.AxisOpts(type_='value',name='Volume',splitline_opts=opts.SplitLineOpts(is_show=True),is_scale=True),)

    return lineVol

        上面说过我们另外起了一个线程从另外一个进程取数据,这里面涉及到数据处理的部分,由于大家的数据需求不一样,故这里只给出一个框架,具体数据处理部分大家自己实现

def handleReciveData(reciveData):
    try:
        pass
    except:
        Pass

def getData():
    while True:
        print("*******************************************")
        pass

def receiveDataThread():
    dataThread1 = threading.Thread(target=getData)
    dataThread1.start()

接下来就是要实现前端和后端的交互实现

@app.route("/")
def index():
    return render_template("index.html")


@app.route("/lineChart")
def get_line_chart():
    c = line_base()
    return c.dump_options_with_quotes()

idx = 0
@app.route("/lineDynamicData1")
def update_line_data():
    if not timeList:
        return jsonify({"xTime": 0, "yValue": [0,0,0,0]})
    global idx
    idx = idx + 1
    if idx > len(timeList):
        idx = len(timeList)
return jsonify({"xTime": datetime.fromtimestamp(timeList[idx]).strftime("%H:%M:%S"), "yValue": volumeList[idx]})

Flask类的route()函数是一个装饰器,它告诉应用程序哪个URL应该调用相关的函数。

app.route(rule, options)
  • rule 参数表示与该函数的URL绑定。

  • options 是要转发给基础Rule对象的参数列表。

        在上面的示例中,'/ ' URL与index()函数绑定。因此,当在浏览器中打开web服务器的主页时,将呈现该函数的输出。

        对于@app.route("/lineChart"),当前端请求该URL的时候,会将上面配置好的曲线图进行实例化,然后c.dump_options_with_quotes()返回给前端显示。

        对于@app.route("/lineDynamicData1")就是每次前端调用的时候将要显示的具体数据传递给前端。

if __name__ == "__main__":
    receiveDataThread()
    app.run(host='192.168.46.84',port=5000,debug=False)

最后在主程序里,调用线程函数和app.run来运行起来后端应用程序

下面具体讲讲Flask的run方法

app.run(host, port, debug, options)

所有参数都是可选的

序号参数与描述
1

host

要监听的主机名。 默认为127.0.0.1(localhost)。设置为“0.0.0.0”以使服务器在外部可用

2

port

默认值为5000

3

debug

默认为false。 如果设置为true,则提供调试信息

4

options

要转发到底层的Werkzeug服务器。

2,前端实现

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>dpt-display</title>
    <script src="https://cdn.bootcss.com/jquery/3.0.0/jquery.min.js"></script>
    <script type="text/javascript" src="static/option.json"></script>
    <script type="text/javascript" src="https://assets.pyecharts.org/assets/echarts.min.js"></script>
    <script type="text/javascript" src="https://assets.pyecharts.org/assets/themes/shine.js"></script>
    <script type="text/javascript" src="https://assets.pyecharts.org/assets/themes/infographic.js"></script>
    <script type="text/javascript" src="https://assets.pyecharts.org/assets/themes/macarons.js"></script>
</head>
<body>
    <div id="Line" style="width:1500px; height:250px;margin-top:1px"></div>
    <script>
        var chart = echarts.init(document.getElementById('Line'), 'shine', {renderer: 'canvas'});
        //chart.setOption(option);
        var old_data = new Array(4);
        var x_data = new Array();
        $(
            function () {
                fetchData(chart);
                setInterval(getDynamicData1, 1000);
            }
        );
        function fetchData() {
            $.ajax({
                type: "GET",
                url: "http://192.168.46.84:5000/lineChart",
                dataType: "json",
                success: function (result) {
                    chart.setOption(result);
                    for(var i=0;i<4;i++) 
                        old_data[i] = [];
                }
            });
        }

        function getDynamicData1() {
            $.ajax({
                type: "GET",
                url: "http://192.168.46.84:5000/lineDynamicData1",
                dataType: "json",
                success: function (result) {
                    if(result.xTime == 0)
                        window.alert('warnning: no data! server is down!')
                    for(var i=0;i<4;i++)
                        old_data[i].push([result.xTime, result.yValue[i]]);
                    x_data.push(result.xTime);
                    chart.setOption({
                            series: [{data: old_data[0]},{data: old_data[1]},{data: old_data[2]},{data: old_data[3]}]
                        });
                    chart.setOption({
                            xAxis: [{data: x_data}]
                        });
                }
            });
        }

</script>

<div id="Line2" style="width:1500px; height:250px;"></div>
    <script>
        var chart2 = echarts.init(document.getElementById('Line2'), 'infographic', {renderer: 'canvas'});
        chart2.setOption(option);
        chart2.setOption({
                            title: [{text: "Pps of ZXDPI"}]
                        });
        chart2.setOption({
                            yAxis: [{name: "Packages"}]
                        });

        var old_data2 = new Array(4);
        var x_data2 = new Array();
        for(var i=0;i<4;i++) 
            old_data2[i] = [];
        $(
            function () {
                setInterval(getDynamicData2, 1000);
            }
        );
        function getDynamicData2() {
            $.ajax({
                type: "GET",
                url: "http://10.235.46.84:5000/lineDynamicData2",
                dataType: "json",
                success: function (result) {
                    for(var i=0;i<4;i++)
                        old_data2[i].push([result.xTime, result.yValue[i]]);
                    x_data2.push(result.xTime);
                    
                    chart2.setOption({
                            series: [{data: old_data2[0]},{data: old_data2[1]},{data: old_data2[2]},{data: old_data2[3]}]
                        });
                    chart2.setOption({
                            xAxis: [{data: x_data2}]
                        });
                }
            });
        }
    </script>

</body>
</html>

        这次需求是要展现的是三张图,由于篇幅以上给出了两张图的HTML,具体图的数量大家可以根据自己的需求去调整代码。下面具体讲讲我认为比较重要的地方。

        初始化一个Echats实例,配置渲染器,目前只支持'canvas'.width可显式指定实例宽度,单位为像素。如果传入值为 null/undefined/'auto',则表示自动取 dom(实例容器)的宽度。height可显式指定实例高度,单位为像素。如果传入值为 null/undefined/'auto',则表示自动取 dom(实例容器)的高度。'shine'是配置的主题

var chart = echarts.init(document.getElementById('Line'), 'shine', {renderer: 'canvas'});

init接口的定义如下:

(dom: HTMLDivElement|HTMLCanvasElement, theme?: Object|string, opts?: {
    devicePixelRatio?: number
    renderer?: string
    width?: number|string
    height? number|string
}) => ECharts

         fetchData()的url为"http://192.168.46.84:5000/lineChart"就是从后端的lineChart函数那里得到曲线图的配置json,然后用chart.setOption(result);设置好,此时前端就可以根据配置的参数进行曲线图的初步展示了。此时就有同学有疑问了,前端怎么根据url从后端拿数据呢,这就用到了ajax。

function fetchData() {
            $.ajax({
                type: "GET",
                url: "http://192.168.46.84:5000/lineChart",
                dataType: "json",
                success: function (result) {
                    chart.setOption(result);
                    for(var i=0;i<4;i++) 
                        old_data[i] = [];
                }
            });
        }

这里可以按F12查看我们前端设置的option是什么样子

        那么怎么让图动起来呢,女主角来了

setInterval(getDynamicData1, 1000);

         该语句的作用就是1秒钟调用一次getDynamicData1方法,getDynamicData1方法同样利用ajax去后端取数据,将取到的数据塞到相应的data里,这样图就动起来了。

        需要注意的是这里面有一个坑,setInterval当我们电脑在正常运行没有锁屏或者休眠的情况下,的确是按照我们设置的1秒钟执行一次,但是假如我们电脑锁屏或者进入休眠状态后,有个现象是变成了1分钟执行一次,这是操作系统原因导致的。

        接下来我们只要依葫芦画瓢,在html里面再添加一个div块,就可以显示第二张图了。第二张图的设置里面,chart2.setOption(option);参数option是怎么来的呢

var chart2 = echarts.init(document.getElementById('Line2'), 'infographic', {renderer: 'canvas'});
        chart2.setOption(option);
        chart2.setOption({
                            title: [{text: "Pps of ZXDPI"}]
                        });
        chart2.setOption({
                            yAxis: [{name: "Packages"}]
                        });

上面讲到fetchData()的作用就是从后端拿到图标的配置数据,但是假如我们有现成的图标数据呢,这面的option就是我拷贝下来的第一张图的option,并且保存在static的文件夹下,其形式如下:

 在html的head里引入该文件即可直接使用

<script type="text/javascript" src="static/option.json"></script>

 值得注意的是我们在填数据的时候会注意到往series里面填,因为官方例子也是只填了这地方,但实际上在个人开发中,还需要往xAxis的data里面填,这样显示才正常

"xAxis": [
        {
            "name": "time",
            "show": true,
            "scale": false,
            "nameLocation": "end",
            "nameGap": 15,
            "gridIndex": 0,
            "inverse": false,
            "offset": 0,
            "splitNumber": 5,
            "minInterval": 0,
            "splitLine": {
                "show": false,
                "lineStyle": {
                    "show": true,
                    "width": 1,
                    "opacity": 1,
                    "curveness": 0,
                    "type": "solid"
                }
            },
            "data": []
        }
    ],

四:曲线展示

         最后的效果就是一秒钟曲线动一次,由于某些原因不能给出动态图,抱歉,就看看静态的,想象它动起来的样子

  • 12
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
1.安装Flaskpyecharts 在命令行中输入以下命令: ``` pip install flask pip install pyecharts ``` 2.创建Flask应用程序 在项目文件夹中创建app.py文件,并输入以下代码: ``` from flask import Flask,render_template from pyecharts import options as opts from pyecharts.charts import Bar app = Flask(__name__) @app.route("/") def index(): return render_template('index.html') @app.route('/bar') def get_bar(): bar = Bar() bar.add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]) bar.add_yaxis("商家A", [5, 20, 36, 10, 75, 90]) bar.add_yaxis("商家B", [15, 6, 45, 20, 35, 66]) bar.set_global_opts(title_opts=opts.TitleOpts(title="柱状示例")) return bar.dump_options_with_quotes() if __name__ == '__main__': app.run(debug=True) ``` 这里我们在Flask应用程序中定义了两个路由,一个是首页,一个是柱状路由,其中柱状路由返回了一个pyecharts柱状的JSON数据,这里我们使用了dump_options_with_quotes()方法将pyecharts表对象转换为JSON格式的字符串。 3.创建HTML模板 在项目文件夹中创建templates文件夹,并在其中创建index.html文件,输入以下代码: ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>数据大屏</title> </head> <body> <div id="bar" style="width:600px;height:400px;"></div> <script src="https://cdn.bootcss.com/echarts/4.2.1-rc1/echarts.min.js"></script> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script> $(function () { var myChart = echarts.init(document.getElementById('bar')); $.get('/bar', function (data) { myChart.setOption(JSON.parse(data)); }); }); </script> </body> </html> ``` 这里我们在HTML中定义了一个div元素,用于显示柱状,同时引入了echarts和jquery库,并使用jquery的get()方法获取柱状的JSON数据,使用echarts的setOption()方法将JSON数据转换为表。 4.运行应用程序 在命令行中进入项目文件夹,输入以下命令启动应用程序: ``` python app.py ``` 然后在浏览器中输入http://127.0.0.1:5000/,即可看到Flask应用程序的首页,点击柱状链接,即可看到pyecharts柱状。如果需要添加其他pyecharts表,只需在Flask应用程序中定义新的路由,返回相应的JSON数据即可。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ftzchina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值