echarts使用多图的表达

记录瞬间

在实际的工作中总会遇到一些报表的展示问题,echarts作为百度的开源工具针对作图来说是不二选择。

教程链接: https://echarts.apache.org/zh/tutorial.html#5%20%E5%88%86%E9%92%9F%E4%B8%8A%E6%89%8B%20ECharts

参数设置:https://echarts.apache.org/zh/option.html#title

本文主要介绍使用echarts时关于一批关联数据,展示到一张图上的方法

主要应用:flask+bootstrap+echarts

由于使用flask的三方插件(pyecharts)在灵活处理非图表数据时较为复杂,所以需要考虑,单独使用echarts进行考虑

先将flask的pyecharts实现简单代码作以展示

def render_result(data):
    from pyecharts.charts import Bar, Grid, Timeline
    from pyecharts import options as opts
    # 内置主题类型可查看 pyecharts.globals.ThemeType
    from pyecharts.globals import ThemeType
    from pyecharts.globals import CurrentConfig
    from jinja2 import Markup, Environment, FileSystemLoader
    from pyecharts.commons.utils import JsCode
    # 关于 CurrentConfig,可参考 [基本使用-全局变量]
    CurrentConfig.GLOBAL_ENV = Environment(loader=FileSystemLoader("./templates/echarts"))
    # js代码
    js_code_str = '''
                        function(params){
                        return params.data.text;
                        }
                        '''

    all_bar_keys = []
    # 获取所有的key数据  result是从执行结果的数据信息中获取的数据,不是最完整的数据结果
    for get_data in data:
        all_bar_keys += data[get_data]['result'].keys()
    # 去重
    get_bar_keys = list(set(all_bar_keys))  # 所有模块名称去重后的结果
    get_bar_keys.sort()                     # 排序保证每次显示的结果一致
    all_keys = list(data.keys())            # 获取执行的所有时间区间的值
    all_keys.sort(reverse=True)                         # 按照大小进行排序
    bar = (
        Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
        .add_xaxis([i for i in range(1, len(all_keys))])
        .set_global_opts(title_opts=opts.TitleOpts(title="结果展示", subtitle="统计当前展示结果"),
                         tooltip_opts=opts.TooltipOpts(formatter=JsCode(js_code_str)),
                         toolbox_opts=opts.ToolboxOpts(is_show=True,
                                                       feature={"saveAsImage": {},
                                                                "dataZoom": {"yAxisIndex": "none"},
                                                                "restore": {},
                                                                "magicType": {"show": True, "type": ["line", "bar",
                                                                                                     "stack"]}})
                         )
    )

    for bar_key in get_bar_keys:  # 遍历所有的模块数据
        get_list = []  # 保存执行结果中的,未出现模块个数数据,但不是最准确的数据结果

        temp_dict = {"value": 0, "text": ""}
        for data_key in all_keys:  # 遍历所有时间区间,筛选出符合相关模块的query词
            temp_dict["text"] = data_key + "<br>" + bar_key
            if bar_key in data[data_key]['result']:  # 结果是从执行query词的结果中获取的,不是最准确的结果,可参考
                temp_dict["value"] = len(data[data_key]['result'][bar_key])
                get_list.append(copy.deepcopy(temp_dict))
            else:
                temp_dict["value"] = 0
                get_list.append(copy.deepcopy(temp_dict))

        bar_ = (
            Bar()
            .add_xaxis([i for i in range(1, len(all_keys))])
            .add_yaxis(bar_key, get_list)
        )
        bar.overlap(bar_)

    get_all_order_dict = {}
    all_bar = []    # 保存所有模块下的柱状图
    row_list = []   # 记录行数据
    count = 1       # 遍历所有模块,每增加一个模块进行 +1 处理
    revise = 0      # 数据校正标记
    for bar_key in get_bar_keys:  # 遍历所有的模块数据
        get_all_order_dict[bar_key] = []
        for data_key in all_keys:
            if bar_key in data[data_key]['result']:
                for word in data[data_key]['result'][bar_key]:
                    if word not in get_all_order_dict[bar_key]:
                        get_all_order_dict[bar_key].append(word)
        get_len = len(str(get_all_order_dict[bar_key]))  # 获取所有词的长度
        rows = int(get_len / 85) + 1                     # 除以95后,获取需要分几行,每行在乘以30就可以获取到词位置的高度了
        
        title_pos = 460 + 330 * (count - 1) + revise
        
        legend_pos = 510 + 330 * (count - 1) + revise
        row_list.append(rows)
        if row_list[count - 1] > 3:
            revise += (row_list[count - 1] - 3) * 30
        print(title_pos, legend_pos, revise)
        key_bar = (
            Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
            .add_xaxis([i for i in range(1, len(all_keys))])
            .set_global_opts(title_opts=opts.TitleOpts(title="关键字统计展示-{}".format(bar_key),
                                                       subtitle="统计当前出现了关键字的相关词展示结果",
                                                       pos_top="{}px".format(title_pos)),
                             tooltip_opts=opts.TooltipOpts(formatter=JsCode(js_code_str)),
                             legend_opts=opts.LegendOpts(pos_top="{}px".format(legend_pos),
                                                         is_show=True, selected_mode='single'))
            # selected_mode 可以使用“single”、“multiple”使用单选或多选模式,默认为multiple
        )
        count += 1
        for word in get_all_order_dict[bar_key]:
            get_keys = []               # 保存所有模块的对应query词的个数数据,准确的结果
            temp_dict = {"value": 0, "text": ""}
            for data_key in all_keys:   # 遍历结果数据
                temp_dict["text"] = word + '<br>' + data_key + '<br>' + bar_key
                if bar_key in data[data_key]["keys_order"]:
                    if word in data[data_key]["keys_order"][bar_key]:
                        temp_dict['value'] = 1
                        get_keys.append(copy.deepcopy(temp_dict))
                    else:
                        temp_dict['value'] = 0
                        get_keys.append(copy.deepcopy(temp_dict))
                else:
                    temp_dict['value'] = 1
                    get_keys.append(copy.deepcopy(temp_dict))
            key_bar_ = (
                Bar()
                .add_xaxis([i for i in range(1, len(all_keys))])
                .add_yaxis(word, get_keys)
            )
            key_bar.overlap(key_bar_)
        all_bar.append(copy.deepcopy(key_bar))

    grid = Grid(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='1100px', height='{}px'.format(700+len(row_list)*365)))
    grid.add(bar, grid_opts=opts.GridOpts(pos_left="5%", pos_right="1%", height="350px"))
    # grid.add(key_bar, grid_opts=opts.GridOpts(pos_top="520px", pos_left="5%", pos_right="1%", height="30%"))
    count = 1    # 循环展示模块的柱形图
    revise = 0   # 校正数据
    for key_bar in all_bar:
        # grid_pos = 600 + (240 + (sum(row_list[:count])) * 30) * (count - 1)
        if row_list[count - 1] > 3:
            revise += (row_list[count - 1] - 3) * 30
        grid_pos = 600 + 330 * (count - 1) + revise
        grid.add(key_bar, grid_opts=opts.GridOpts(pos_top="{}px".format(grid_pos), pos_left="5%",
                                                  pos_right="1%", height="150px"))
        count += 1
    # return Markup(bar.render_embed())
    return grid.render_embed()

 

方法调用如下:

 1 @ots.route('aisi_summary', methods=["GET"])
 2 def aisi_summary():
 3     get_time = get_time_section(96, flag=True)[1]
 4     get_objs = TempData.objects(CREATE_TIME__gte=get_time).all()
 5     if get_objs and len(get_objs) > 85:
 6         data = sfo.aisi_summary()
 7         from jinja2 import Markup
 8         get_render = render_result(data=data)
 9         return Markup(get_render)       # 直接渲染结果
10     else:
11         # 准备数据过程中
12         try:
13             executor.submit(sfo.aisi_summary, flag=True)
14         except:
15             pass
16         return render_template("aisi_summary.html", error="数据修整中,请稍后重试!")

当然使用前提是需要安装pyecharts,并将pyecharts下面的模板放到templates目录下,才可以正常展示结果。

此结果是按照既定的pyecharts的模板进行渲染展示的,所以很大程度上无法进行非图表数据的展示

 


 

# 引入echarts

我们希望在展示图表数据的过程中,还要展示其他的数据,比如:判断结果,表格,说明等等

过程分为:1、数据准备;2、渲染页面;3、展示结果

数据准备代码

 1 def total_result_for_data(data):
 2     result = {"height": 0, "x": [], "y": [], "title": ['结果概览'], "count": 0}
 3     all_bar_keys = []
 4     # 获取所有的key数据  result是从执行结果的数据信息中获取的数据,不是最完整的数据结果
 5     for get_data in data:
 6         all_bar_keys += data[get_data]['result'].keys()
 7     # 去重
 8     get_bar_keys = list(set(all_bar_keys))   # 所有模块名称去重后的结果
 9     get_bar_keys.sort()                      # 排序保证每次显示的结果一致
10     result['title'] += get_bar_keys          # 主标题设置
11     result['count'] = len(result['title'])   # 记录显示的柱形图的个数
12     all_keys = list(data.keys())             # 获取执行的所有时间区间的值
13     all_keys.sort(reverse=True)              # 按照大小进行排序
14     result['all_keys'] = all_keys
15     result['x'] = [i for i in range(1, len(all_keys)+1)]   # 生成x轴刻度
16     # 总体数据展示结果
17     get_all_order_dict = {}
18     row_list = []  # 记录行数据
19     count = 1      # 遍历所有模块,每增加一个模块进行 +1 处理
20     result['结果概览_source'] = []
21     result['结果概览'] = get_bar_keys
22     result['grid_pos'] = [100]
23     for bar_key in get_bar_keys:
24         set_date_key = {"name": bar_key, "type": "bar", "data": [], "label": {"show": "true"}}
25         for data_key in all_keys:           # 遍历所有时间区间,筛选出符合相关模块的query词
26             temp_dict = {"value": 0, "text": data_key + '===' + bar_key}
27             get_all_order_dict[bar_key] = []
28             if bar_key in data[data_key]['result']:  # 结果是从执行query词的结果中获取的
29                 data_value = len(data[data_key]['result'][bar_key])
30                 temp_dict["value"] = len(data[data_key]['result'][bar_key])
31             else:
32                 temp_dict["value"] = 0
33                 data_value = 0
34             set_date_key["data"].append(copy.deepcopy(temp_dict))
35             if bar_key in data[data_key]['result']:
36                 for word in data[data_key]['result'][bar_key]:
37                     if word not in get_all_order_dict[bar_key]:
38                         get_all_order_dict[bar_key].append(word)
39         result['结果概览_source'].append(copy.deepcopy(set_date_key))
40     print(result['结果概览_source'])
41     for bar_key in get_bar_keys:            # 遍历所有的模块数据
42         result[bar_key + "_source"] = []
43         get_all_order_dict[bar_key] = []
44         for data_key in all_keys:           # 遍历所有时间区间,筛选出符合相关模块的query词
45             if bar_key in data[data_key]['result']:
46                 for word in data[data_key]['result'][bar_key]:
47                     if word not in get_all_order_dict[bar_key]:
48                         get_all_order_dict[bar_key].append(word)
49         result[bar_key] = copy.deepcopy(get_all_order_dict[bar_key])
50 
51         get_len = len(str(get_all_order_dict[bar_key]))  # 获取所有词的长度
52         rows = int(get_len / 85) + 1            # 除以85后,获取需要分几行,每行在乘以30就可以获取到词位置的高度了
53 
54         result['grid_pos'].append(70 + 30 * rows)
55 
56         count += 1
57         for word in get_all_order_dict[bar_key]:
58             set_date_key = {"name": word, "type": "bar", "data": [], "label": {"show": "true"}}
59             for data_key in all_keys:  # 遍历结果数据
60                 temp_dict = {"value": 0, "text": word + '===' + data_key + '===' + bar_key}
61                 if bar_key in data[data_key]["keys_order"]:
62                     if word in data[data_key]["keys_order"][bar_key]:
63                         temp_dict["value"] = 1
64                     else:
65                         temp_dict["value"] = 0
66                 else:
67                     temp_dict["value"] = 1
68                 set_date_key["data"].append(copy.deepcopy(temp_dict))
69             result[bar_key + "_source"].append(copy.deepcopy(set_date_key))
70         print(result[bar_key + "_source"])
71 
72     result['height'] = (len(row_list) + 1) * 365
73 
74     return result

 

前端代码如下

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5 
  6     <meta name="viewport" content="width=device-width, initial-scale=1">
  7     <meta name="description" content="">
  8     <meta name="generator" content="Hugo 0.84.0">
  9     <title>数据分析</title>
 10     <link href="{{ url_for('static', filename='bs/css/bootstrap.min.css') }}" rel="stylesheet">
 11     <link href="{{ url_for('static', filename='bs/css/carousel.css') }}" rel="stylesheet">
 12     <!-- 引入echarts -->
 13     <script src="/static/js/echarts.min.js"></script>
 14 </head>
 15 <body>
 16 {% include "common/header.html" %}
 17 
 18 <div class="container">
 19     <main>
 20         <div style="margin-top:25px">
 21             <nav aria-label="breadcrumb">
 22               <ol class="breadcrumb">
 23                 <li class="breadcrumb-item"><a href="#">监控</a></li>
 24                 <li class="breadcrumb-item active" aria-current="page">数据分析</li>
 25               </ol>
 26             </nav>
 27         </div>
 28     <div class="px-4 py-5 my-5 text-left">
 29         {% if error %}
 30         <span style="color: #e4393c">{{ error }}</span>
 31         {% endif %}
 32     <table class="table table-hover">
 33         <tr><th style="text-align: center;font-size: 0.8cm;background-color: #c8e0cf">结果一览</th></tr>
 34         <tr>
 35             <td>
 36                 <div id="main_picture"></div>
 37             </td>
 38         </tr>
 39         {% for foo in range(data.count) %}
 40         <tr>
 41             <td>
 42                 <div id="main_picture_{{ foo }}"></div>
 43             </td>
 44         </tr>
 45         {% endfor %}
 46     </table>
 47 
 48     </div>
 49     </main>
 50 </div>
 51 
 52 {% include "common/footer.html" %}
 53 
 54 <script src="/static/bs/js/bootstrap.bundle.min.js"></script>
 55 
 56 <script type="text/javascript">
 57     let temp_str = "{{ data }}".replace(/&#39;/g, '"');
 58     // 将接受的数据转换为json对象
 59     let obj = eval("("+temp_str+")");
 60     {% if data %}
 61         init(obj);
 62     {% endif %}
 63 
 64     function init(obj){
 65         console.log(obj);
 66         let num = obj.count;
 67         let xdata = obj.x;
 68         let title_data = obj.title;
 69         let grid_pos = obj.grid_pos
 70         for (let mpnum=0; mpnum<num; mpnum++){
 71             let main_picture = document.getElementById('main_picture_' + mpnum);
 72             //计算所需要的高度
 73             if (mpnum === 0) {
 74                 main_picture.style.height = "440px";
 75             } else {
 76                 main_picture.style.height = 150 + grid_pos[mpnum] + "px";
 77             }
 78             // 基于准备好的dom,初始化echarts实例
 79             let myChart = echarts.init(main_picture);
 80             let toolbox = [];      // 设置
 81             let legend = [];       // 图例显示
 82 
 83             //通过配置xAxi和yAxis的gridIndex  series的xAxisIndex和yAxisIndex 来配套格子
 84             let option = {
 85                 title: {
 86                       textAlign: "left",
 87                       text: title_data[mpnum],
 88                       subtext: title_data[mpnum],
 89                       top: "0px"
 90                 },
 91                 xAxis: {
 92                     type: "category",
 93                     data: xdata
 94                 },
 95                 yAxis: {
 96                   type: "value",
 97                   inverse: false,
 98                   splitLine: {
 99                     show: true
100                   }
101                 },
102                 series: obj[title_data[mpnum]+"_source"],
103                 grid: {
104                     left: "3%",
105                     right: "1%",
106                     width: "95%",
107                     top: grid_pos[mpnum] + "px"
108                 }
109             };
110             // 工具栏设置
111             if (mpnum === 0) {
112                 toolbox.push({
113                     show: true,
114                     feature: {
115                         mark: {show: true},
116                         dataZoom: {show: true},
117                         dataView: {show: true,readOnly: false},
118                         magicType: {show: true,type: ['line', 'bar', 'stack']},
119                         restore: {show: true},
120                         saveAsImage: {show: true}
121                     }
122                 });
123             } else {
124                 toolbox.push({
125                     show: false
126                 });
127             }
128             option["toolbox"] = toolbox[0];
129             option["tooltip"] = {
130                 position: "top",
131                 formatter: function (params) {
132                     return params.data.text.replace(/===/g, "<br>");
133                 }
134             };
135 
136             // 图例设置
137             if (mpnum === 0){
138                 legend.push({
139                     selectedMode: 'multiple',
140                     top: "60px",
141                     show: true
142                 });
143             } else {
144                 legend.push({
145                     selectedMode: 'single',
146                     top: "60px",
147                     show: true
148                });
149             }
150             option["legend"] = legend[0];
151             // 使用刚指定的配置项和数据显示图表。
152             myChart.setOption(option);
153         }
154     }
155 </script>
156 </body>
157 </html>

 

展示结果如图

 

 

 当然图表都是动态加载的,整图下面还有其他的图表,由于截屏关系只截取当前两张

注意:当前使用的都是最新的版本(bootstrap-v5.0、echarts-5.1.2)

 


 

供参考---结束了

===

posted @ 2021-08-10 15:49  wozijisun  阅读(365)  评论(0编辑  收藏  举报