当前位置:   article > 正文

Flask+Pyeharts前端实时动态展现多曲线多图实践_flask echart 显示多个图

flask echart 显示多个图

一: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目录

  1. mkdir dpt_flask
  2. cd dpt_flask
  3. mkdir templates

2,拷贝pyechats模板

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

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

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

        其总的代码结构如下:

  1. .
  2. ├── app.py
  3. ├── static
  4. │?? └── option.json
  5. └── templates
  6. ├── index.html
  7. ├── macro
  8. ├── nb_jupyter_lab.html
  9. ├── nb_jupyter_notebook.html
  10. ├── nb_nteract.html
  11. ├── simple_chart.html
  12. └── simple_page.html

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

三:功能实现

1,后端实现

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

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

  1. import os
  2. import zmq
  3. import threading
  4. from datetime import datetime
  5. from flask.json import jsonify
  6. from flask import Flask, render_template
  7. from pyecharts import options as opts
  8. from pyecharts.charts import Line
  9. from pyecharts.globals import ThemeType

实例化Flask

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

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

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

  1. color = ['blue','cyan','green','red','darkorange','magenta','olive','black']
  2. def line_base() -> Line:
  3. lineVol = Line(init_opts=opts.InitOpts(theme=ThemeType.SHINE))
  4. lineVol.add_xaxis([])
  5. for i in range(4):
  6. lineVol.add_yaxis(series_name="Thread"+str(i),y_axis=[],color=color[i],label_opts=opts.LabelOpts(is_show=False),)
  7. lineVol.set_global_opts(
  8. title_opts=opts.TitleOpts(title="XXXXX", pos_top="3%"),
  9. legend_opts=opts.LegendOpts(pos_top="5%"),
  10. toolbox_opts=opts.ToolboxOpts(is_show=True),
  11. tooltip_opts=opts.TooltipOpts(is_show=True, axis_pointer_type="cross", trigger="axis"),
  12. #datazoom_opts=opts.DataZoomOpts(type_="slider"),
  13. xaxis_opts=opts.AxisOpts(name='time'),
  14. yaxis_opts=opts.AxisOpts(type_='value',name='Volume',splitline_opts=opts.SplitLineOpts(is_show=True),is_scale=True),)
  15. return lineVol

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

  1. def handleReciveData(reciveData):
  2. try:
  3. pass
  4. except:
  5. Pass
  6. def getData():
  7. while True:
  8. print("*******************************************")
  9. pass
  10. def receiveDataThread():
  11. dataThread1 = threading.Thread(target=getData)
  12. dataThread1.start()

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

  1. @app.route("/")
  2. def index():
  3. return render_template("index.html")
  4. @app.route("/lineChart")
  5. def get_line_chart():
  6. c = line_base()
  7. return c.dump_options_with_quotes()
  8. idx = 0
  9. @app.route("/lineDynamicData1")
  10. def update_line_data():
  11. if not timeList:
  12. return jsonify({"xTime": 0, "yValue": [0,0,0,0]})
  13. global idx
  14. idx = idx + 1
  15. if idx > len(timeList):
  16. idx = len(timeList)
  17. 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")就是每次前端调用的时候将要显示的具体数据传递给前端。

  1. if __name__ == "__main__":
  2. receiveDataThread()
  3. 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,前端实现

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>dpt-display</title>
  6. <script src="https://cdn.bootcss.com/jquery/3.0.0/jquery.min.js"></script>
  7. <script type="text/javascript" src="static/option.json"></script>
  8. <script type="text/javascript" src="https://assets.pyecharts.org/assets/echarts.min.js"></script>
  9. <script type="text/javascript" src="https://assets.pyecharts.org/assets/themes/shine.js"></script>
  10. <script type="text/javascript" src="https://assets.pyecharts.org/assets/themes/infographic.js"></script>
  11. <script type="text/javascript" src="https://assets.pyecharts.org/assets/themes/macarons.js"></script>
  12. </head>
  13. <body>
  14. <div id="Line" style="width:1500px; height:250px;margin-top:1px"></div>
  15. <script>
  16. var chart = echarts.init(document.getElementById('Line'), 'shine', {renderer: 'canvas'});
  17. //chart.setOption(option);
  18. var old_data = new Array(4);
  19. var x_data = new Array();
  20. $(
  21. function () {
  22. fetchData(chart);
  23. setInterval(getDynamicData1, 1000);
  24. }
  25. );
  26. function fetchData() {
  27. $.ajax({
  28. type: "GET",
  29. url: "http://192.168.46.84:5000/lineChart",
  30. dataType: "json",
  31. success: function (result) {
  32. chart.setOption(result);
  33. for(var i=0;i<4;i++)
  34. old_data[i] = [];
  35. }
  36. });
  37. }
  38. function getDynamicData1() {
  39. $.ajax({
  40. type: "GET",
  41. url: "http://192.168.46.84:5000/lineDynamicData1",
  42. dataType: "json",
  43. success: function (result) {
  44. if(result.xTime == 0)
  45. window.alert('warnning: no data! server is down!')
  46. for(var i=0;i<4;i++)
  47. old_data[i].push([result.xTime, result.yValue[i]]);
  48. x_data.push(result.xTime);
  49. chart.setOption({
  50. series: [{data: old_data[0]},{data: old_data[1]},{data: old_data[2]},{data: old_data[3]}]
  51. });
  52. chart.setOption({
  53. xAxis: [{data: x_data}]
  54. });
  55. }
  56. });
  57. }
  58. </script>
  59. <div id="Line2" style="width:1500px; height:250px;"></div>
  60. <script>
  61. var chart2 = echarts.init(document.getElementById('Line2'), 'infographic', {renderer: 'canvas'});
  62. chart2.setOption(option);
  63. chart2.setOption({
  64. title: [{text: "Pps of ZXDPI"}]
  65. });
  66. chart2.setOption({
  67. yAxis: [{name: "Packages"}]
  68. });
  69. var old_data2 = new Array(4);
  70. var x_data2 = new Array();
  71. for(var i=0;i<4;i++)
  72. old_data2[i] = [];
  73. $(
  74. function () {
  75. setInterval(getDynamicData2, 1000);
  76. }
  77. );
  78. function getDynamicData2() {
  79. $.ajax({
  80. type: "GET",
  81. url: "http://10.235.46.84:5000/lineDynamicData2",
  82. dataType: "json",
  83. success: function (result) {
  84. for(var i=0;i<4;i++)
  85. old_data2[i].push([result.xTime, result.yValue[i]]);
  86. x_data2.push(result.xTime);
  87. chart2.setOption({
  88. series: [{data: old_data2[0]},{data: old_data2[1]},{data: old_data2[2]},{data: old_data2[3]}]
  89. });
  90. chart2.setOption({
  91. xAxis: [{data: x_data2}]
  92. });
  93. }
  94. });
  95. }
  96. </script>
  97. </body>
  98. </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接口的定义如下:

  1. (dom: HTMLDivElement|HTMLCanvasElement, theme?: Object|string, opts?: {
  2. devicePixelRatio?: number
  3. renderer?: string
  4. width?: number|string
  5. height? number|string
  6. }) => ECharts

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

  1. function fetchData() {
  2. $.ajax({
  3. type: "GET",
  4. url: "http://192.168.46.84:5000/lineChart",
  5. dataType: "json",
  6. success: function (result) {
  7. chart.setOption(result);
  8. for(var i=0;i<4;i++)
  9. old_data[i] = [];
  10. }
  11. });
  12. }

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

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

setInterval(getDynamicData1, 1000);

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

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

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

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

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

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

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

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

  1. "xAxis": [
  2. {
  3. "name": "time",
  4. "show": true,
  5. "scale": false,
  6. "nameLocation": "end",
  7. "nameGap": 15,
  8. "gridIndex": 0,
  9. "inverse": false,
  10. "offset": 0,
  11. "splitNumber": 5,
  12. "minInterval": 0,
  13. "splitLine": {
  14. "show": false,
  15. "lineStyle": {
  16. "show": true,
  17. "width": 1,
  18. "opacity": 1,
  19. "curveness": 0,
  20. "type": "solid"
  21. }
  22. },
  23. "data": []
  24. }
  25. ],

四:曲线展示

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/142120
推荐阅读
相关标签
  

闽ICP备14008679号