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服务器。 |
dpt-display
这次需求是要展现的是三张图,由于篇幅以上给出了两张图的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里引入该文件即可直接使用
值得注意的是我们在填数据的时候会注意到往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": []
}
],
最后的效果就是一秒钟曲线动一次,由于某些原因不能给出动态图,抱歉,就看看静态的,想象它动起来的样子