关于pyecharts可视化与Flask相结合

2022-03-11 14:34:10 浏览数 (1)

关于pyecharts和flask结合的案例不多,查阅了数十篇文章,尝试了若干遍,感觉还是不理想,最大的问题在于对echarts的理解上,对我而言,又需要向上推到ajax,jquery,bootstrap,html,css,javascript等等,有点超出了我的技能范围,所以最大程度的做到能用就够了,复用和进一步优化看起来还是遥遥无期。

关于pyecharts可视化与中国经济、人口等数据系列的笔记也暂时告以段落了。

Flask 模板渲染

Step 0: 新建一个 Flask 项目

mkdir pyecharts-flask-demo

cd pyecharts-flask-demo

mkdir templates

Step 1: 拷贝 pyecharts 模板

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

|--components.html

|--macro

|--nb_components.html

|--nb_jupyter_globe.html

|--nb_jupyter_lab.html

|--nb_jupyter_lab_tab.html

|--nb_jupyter_notebook.html

|--nb_jupyter_notebook_tab.html

|--nb_nteract.html

|--simple_chart.html

|--simple_globe.html

|--simple_page.html

|--simple_tab.html

Step 2: 渲染图表

在项目的根目录下新建server.py

一种是把图表render到templates目录下

一种是直接使用render_embed方式

Flask 前后端分离

前后端分离可以使用动态更新数据,增量更新数据等功能。

Step 0,Step 1 参见上面模板渲染章节内容

Step 3: 新建一个 HTML 文件, 新建 HTML 文件保存位于项目根目录的 templates 文件夹

Step 4: 编写 flask 和 pyecharts 代码渲染图表,将代码保存项目的根目录下。

定时全量更新图表

前端主动向后端进行数据刷新

定时刷新的核心在于 HTML 的 setInterval 方法。

带参数访问方式,也是采用render_embed方式,只不过是把参数又传递给图表了

代码语言:javascript复制
import os
from random import randrange

from flask.json import jsonify
from flask importFlask
from flask import render_template
from jinja2 importMarkup, Environment, FileSystemLoader
import random
from flask importFlask, render_template
from flask import request

from pyecharts.globals importCurrentConfig
from pyecharts.faker importFaker
from pyecharts import options as opts
from pyecharts.charts importBar,Line
from pyecharts import options as opts
from pyecharts.charts importGauge, Page,Map,Scatter

# 关于 CurrentConfig,可参考 [基本使用-全局变量]
#CurrentConfig.GLOBAL_ENV = Environment(loader=FileSystemLoader("./templates"))
app = Flask(__name__, static_folder="templates")

# render()方法:默认会在当前目录生成 render.html 文件
# render()方法传入路径参数:传入路径参数,如 bar.render(“mycharts.html”),这种方法好一点,可以设定文件路径
# render_notebook()方法:这个方法可用在notebook中
# render_embed()方法:来自pyecharts的flask一章中的Markup(c.render_embed())
# chart.dump_options()方法:这个方法能和flask配合不错,能够实现一个flask网页中绘制很多个图表;
# 然而却依然需要自己引入echarts.js文件、自己设定div、自己初始化echarts对象、自己给echarts对象设置图表配置,唯一简化的就是图表配置是来自于python服务端;
# 获取全局 options,JSON 格式(JsCode生成的函数不带引号)
# def dump_options() -> str:
# 获取全局 options,JSON 格式(JsCode生成的函数带引号,在前后端分离传输数据时使用)
# def dump_options_with_quotes() -> str:
# 从实际执行的角度,这两种方法暂时没发现有什么区别,先人云亦云的练习吧

# 生成bart图
def bar_base() -> Bar:
    c = (
Bar()
.add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
.add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
.add_yaxis("商家B", [15, 25, 16, 55, 48, 8])
.set_global_opts(title_opts=opts.TitleOpts(title="Bar-基本示例", subtitle="我是副标题"))
)
return c


# 生成line图
def line_base() -> Line:
    c = (
Line()
.add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.set_global_opts(title_opts=opts.TitleOpts(title="Line-基本示例"))
)
return c


# 仪表盘图
def gauge_base() -> Gauge:
    c = (
Gauge()
.add("", [("完成率", 66.6)])
.set_global_opts(title_opts=opts.TitleOpts(title="Gauge-基本示例"))
)
return c


# 地图map
def map_base() -> Map:
    c = (
Map()
.add("商家A", [list(z) for z in zip(Faker.provinces, Faker.values())], "china")
.set_global_opts(title_opts=opts.TitleOpts(title="Map-基本示例"))
)
return c


#散点图
def scatter_base() -> Scatter:
    c = (
Scatter()
.add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.set_global_opts(title_opts=opts.TitleOpts(title="Scatter-基本示例"))
)
return c


#  新增全量更新数据
def full_bar_base() -> Bar:
    c = (
Bar()
.add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
.add_yaxis("商家A", [randrange(0, 100) for _ in range(6)])
.add_yaxis("商家B", [randrange(0, 100) for _ in range(6)])
.set_global_opts(title_opts=opts.TitleOpts(title="Bar-基本示例", subtitle="我是副标题"))
)
return c


#  新增动态更新数据
def incre_line_base() -> Line:
    line = (
Line()
.add_xaxis(["{}".format(i) for i in range(10)])     #初始化10个值
.add_yaxis(
            series_name="",
            y_axis=[randrange(50, 80) for _ in range(10)],  #在50-80循环出10个值
            is_smooth=True,
            label_opts=opts.LabelOpts(is_show=False),
)
.set_global_opts(
            title_opts=opts.TitleOpts(title="动态数据"),
            xaxis_opts=opts.AxisOpts(type_="value"),
            yaxis_opts=opts.AxisOpts(type_="value"),
)
)
return line


# 生成bart图,带参数
def bar_base_withpara(title,ydata) -> Bar:
    c = (
Bar()
.add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
.add_yaxis("商家A", ydata)
.set_global_opts(title_opts=opts.TitleOpts(title=title, subtitle="动态标题"))
)
return c


# render_embed方法
@app.route("/render_embed")
def render_embed():
    c = bar_base()
returnMarkup(c.render_embed())


# render到文件方法,注意render的缺省工作目录和flask的template工作目录不同
@app.route("/render")
def renderhtml():
    filename='terenderfile.html'
    currentpath=os.path.abspath('.')
    pathfilename=os.path.join(currentpath, 'templates',filename)
    c = line_base()
    c.render(pathfilename)
return render_template(filename)


# 外部访问链路
@app.route('/')
def hello_world():
return'Hello World'

# ----------------------------------------------------------
# 经测试bar,line,scatter和gauge可通过ajax   url: "http://127.0.0.1:8080/XXXChart"方式
# 但Map不行,估计是map访问的百度地图资源受限,待核查
# ----------------------------------------------------------

# 外部访问链路,bar图
@app.route("/dumpbar")
def dump_bar():
return render_template("barbaseindex.html")


# barbaseindex.html指向的链路
@app.route("/barChart")
def get_bar_chart():
    c = bar_base()
return c.dump_options_with_quotes()


# 外部访问链路,line图
@app.route("/dumpline")
def dump_line():
return render_template("linebaseindex.html")


# linebaseindex.html指向的链路
@app.route("/lineChart")
def get_line_chart():
    c = line_base()
return c.dump_options_with_quotes()


# 外部访问链路,scatter图
@app.route("/dumpscatter")
def dump_scatter():
return render_template("scatterbaseindex.html")


# scatterbaseindex.html指向的链路
@app.route("/scatterChart")
def get_scatter_chart():
    c = scatter_base()
return c.dump_options_with_quotes()


# 外部访问链路,gauge图
@app.route("/dumpgauge")
def dump_gauge():
return render_template("gaugebaseindex.html")


# gaugebaseindex.html指向的链路
@app.route("/gaugeChart")
def get_gauge_chart():
    c = gauge_base()
return c.dump_options()
#return c.dump_options_with_quotes()


# 通过mapbaseindex.html对http://127.0.0.1:8080/mapChart"调用,只能看到标题,无法打开地图
# # 外部访问链路,map图
# @app.route("/dumpmap")
# def dump_map():
#     return render_template("mapbaseindex.html")
#
# # mapbaseindex.html指向的链路
# @app.route("/mapChart")
# def get_map_chart():
#     c = map_base()
#     return c.dump_options_with_quotes()


# 外部访问链路,bar图
@app.route("/dumpfullbar")
def dump_full_bar():
return render_template("fullupdatebarbase.html")


# barbaseindex.html指向的链路
@app.route("/fullbarChart")
def get_full_bar_chart():
    c = full_bar_base()
return c.dump_options_with_quotes()


# 外部访问链路,动态新增值的line图
@app.route("/dumpincreline")
def index():
return render_template("increupdatelinebase.html")


# increupdatelinebase.html指向的链路
@app.route("/increlineChart")
def get_incre_line_chart():
    c = incre_line_base()
return c.dump_options_with_quotes()


idx = 9
# 生成动态新增数据值,在increupdatelinebase.html的http://127.0.0.1:8080/lineDynamicData被引用
@app.route("/lineDynamicData")
def update_line_data():
    global idx
    idx = idx   1
return jsonify({"name": idx, "value": randrange(50, 80)})   



@app.route("/dumpbarwithpara")
def dump_bar_withpara():
return render_template("barbasewithparaindex.html")


@app.route("/barChartwithpara", methods=['post','get'])
def get_bar_chart_withpara():
    title = request.args.get('title')
    type = request.args.get('type')
    ydata=list(randrange(1,100) for i in range(6))
    c = bar_base_withpara(title, ydata)
returnMarkup(c.render_embed())



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

关于barbaseindex.html文件

代码示例

代码语言:javascript复制
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Awesome-pyecharts</title>
    <script src="templates/jquery-3.4.1.min.js"></script>
    <script type="text/javascript" src="templates/echarts.min.js"></script>
</head>
<body>
    <div id="bar" style="width:1000px; height:600px;"></div>
    <script>
        var chart = echarts.init(document.getElementById('bar'), 'white', {renderer: 'canvas'});
        $(
            function () {
                fetchData(chart);
                setInterval(fetchData, 2000);
            }
        );
        function fetchData() {
            $.ajax({
                type: "GET",
                url: "http://127.0.0.1:8080/fullbarChart",
                dataType: 'json',
                success: function (result) {
                    chart.setOption(result);
                }
            });
        }
    </script>
</body>
</html>

0 人点赞