赞
踩
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的文件夹及其文件作用,后面会讲到
前端网页会定时从后端取数据进行动态实时显示,在具体实践中,数据是另外一个进程产生的,用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服务器。 |
- <!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": []
- }
- ],
最后的效果就是一秒钟曲线动一次,由于某些原因不能给出动态图,抱歉,就看看静态的,想象它动起来的样子
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。