zoukankan      html  css  js  c++  java
  • pyecharts和echarts的混合使用

      ECharts是一个由百度开发的纯 Javascript 的图表库,pyecharts是某三位大佬将ECharts移植到Python项目中的产物,在Python网站中可以更轻松的接入图表,但是个人感觉pyecharts比ECharts还是局限很大的,pyecharts0.5.x版本就更为缩水了,由于项目之前用的是pyecharts0.5.11版本,图表比较少,不足以解决问题,甚至自己用js实现了两个图表来使用,美观度比ECharts还是逊色不少,如果将项目迁移到新版pyecharts v1.0.0则更为麻烦,就直接在原来的项目中引入echarts库来混合使用,pyecharts v1.0.0虽然完善了不少问题,但是加入了新的配置规则,学习起来增加了不少负担,灵活度也没有echarts好,个人建议如果项目中使用的图表不是很复杂,数据静态的可以使用pyecharts,复杂点的还是尽量使用echarts比较方便,下面开始进入主题:

    1. 安装pyecharts:

    pip install pyecharts==0.5.11  #0.5.x的旧版,我目前使用的这个,要用pyecharts的话建议安装下面的最新版

    pip install pyecharts     #安装最新版

     pyecharts使用图表可以直接在视图代码里面构建图表,Django会将其渲染到前端模板页面中:

    # 主体图-1
    def visualPage(request):
        template = loader.get_template('visualModule/visualPage.html')  #载入模板文件
        
        parseArgData()
        
        data3D1,weights3D1,bar = drawBar() #得到图表数据
        context = dict(     #context添加在模板中要渲染的数据
            myechart = bar.render_embed(),  #图表数据
            host = DEFAULT_HOST,
            script_list = bar.get_js_dependencies(),  #由pyecharts引入需要用到的js代码文件
            guestSetArgs=startArgsSet,
            warningdata=argList,
            data3D=data3D1,
            weights3D=weights3D1,
        )
        return HttpResponse(template.render(context, request))#

    构建图表函数,这里只粘贴了图表的接口代码,数据处理和逻辑代码略去:

    def drawBar(): #绘制
            x_axis = ['','','','','','','','','','','',''] #X轴
            y_axis = [0,1,2,3,4,5,6,7,8,9,10,11]
    
        
            data = [
            #闭源5个
            dict(
            name = "",
            value=[so[0], sor[0], projects[0][0][""]],
            itemStyle=dict(color=getColorstr2(0,weights[0]))
            ),
    
            dict(
            name="",
            value=[so[4], sor4[2], projects[4][2][""]],
            itemStyle=dict(color=getColorstr2(4,weights[18]))
            ),
    
            ...
            ]
            bar3d = Bar3D("", width=1000, height=500)
            bar3d.add("",x_axis,y_axis, data,
            is_visualmap=False,
            is_xaxis_show=True,
            is_yaxis_show=False,
            is_splitline_show=False,
            xaxis3d_name =' ',
            yaxis3d_name =' ',
    
            #is_label_show =True,
            mark_point_symbol='circle',
            is_more_utils=True,
            mark_point=['max','min'],
            mark_line=['average'],
    
            zaxis3d_name ='评分',
            xaxis3d_interval =0,
            grid3d_width=150, grid3d_depth=100,
            grid3d_shading='realistic',
            is_grid3d_ratate = True,
            grid3d_rotate_speed=180,
            tooltip_formatter=formatter)
    
            bar3d.on(MOUSE_CLICK, on_click)
            return data,weights,bar3d
    <!--  模板代码-->
     <div>
     
      {{ myechart|safe }}
      <br>
      {{radarChart|safe}}
      
     </div> 

    这样就可以在前端显示柱状图图表了

    另外项目中还使用了一个折线图也是同样做法:

    其他图表也是类似添加,可以参考pyecharts官网教程:

    https://pyecharts.org/#/

    2. 接下来在项目中再引入echarts来使用,和pyecharts混合使用互不影响

    安装可参考echarts官网:

    https://www.echartsjs.com/zh/

    去https://github.com/apache/incubator-echarts下载echarts源码包,解压出来的文件夹里的 dist 目录里可以找到最新版本的 echarts 库,直接在前端页面中引入即可使用echarts图表,

    1 {% for jsfile_name in script_list %}
    2         <script src="{{ host }}/{{ jsfile_name }}.js"></script>
    3     {% endfor %}
    4     
    5          <script src="{% static 'js/dist/echarts.min.js' %}"></script>
    6      <script src="{% static 'js/dist/echarts-gl.js' %}"></script>
     <div id="container3" style="height: 800px"></div>
        
           <script type="text/javascript">
           //echarts柱状图
    var dom3 = document.getElementById("container3");
    var myChart3 = echarts.init(dom3);
    var app = {};
    option = null;
    
    var hours = [];
    var days = [];
    
    $.get("{% static 'json/eachBar3dData.json' %}",function (json_data) {
        var jdata=[];
        $(json_data.items).each(function(i,ite){  
            jdata.push(ite)
        })
        rectSize=Math.sqrt(json_data.length);
        for(var i=0;i<rectSize;i++)
        {
            hours.push('');
            days.push('');
        }    
        option = {
            title: {
                text: '所有代码子模块代码数量3D柱状图',
                subtext: '可显示代码数量,缺陷情况',
                left: 'leafDepth'
            },
            tooltip: {
                formatter:function(params)
                    {
                       var errors=0;
                       for(var i =0;i< json_data.length;i++)
                       {
                            if (json_data[i][3]==params.name)
                            {
                                errors=json_data[i][4];
                                break;
                            }
                       }
                       return "<div >"+"文件路径:"+params.name+'<br>'+
                      "代码行数:"+params.value[2]+'<br>'+
                      "缺陷数量:"+errors+
                       "</div>";
                    }, 
            },
            visualMap: {
                max: 4000,
                inRange: {
                    color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
                }
            },
            xAxis3D: {
                type: 'category',
                data: hours,
                name: ''
            },
            yAxis3D: {
                type: 'category',
                data: days,
                name:''
            },
            zAxis3D: {
                type: 'value',
                name:'代码数量'
            },
            grid3D: {
                boxWidth: 200,
                boxDepth: 180,
                viewControl: {
                    // projection: 'orthographic'
                },
                light: {
                    main: {
                        intensity: 1.2,
                        shadow: true
                    },
                    ambient: {
                        intensity: 0.3
                    }
                }
            },
           /* dataset: {
                dimensions: [
                    'Income',
                    'Life Expectancy',
                    'Population',
                    'Country',
                    {name: 'Year', type: 'ordinal'}
                ],
                source: json_data
            },
            */
            series: [{
                type: 'bar3D',
                data: json_data.map(function (item) {
                    return {
                        name:item[3],
                        value: [item[1], item[0], item[2]],
                    }
                }),
                shading: 'lambert',
    
                label: {
                    textStyle: {
                        fontSize: 16,
                        borderWidth: 0
                    }
                },
    
                emphasis: {
                    label: {
                        textStyle: {
                            fontSize: 20,
                            color: '#900'
                        }
                    },
                    itemStyle: {
                        color: '#900'
                    }
                }
            }]
        };
        myChart3.setOption(option, true);
    }); 
    if (option && typeof option === "object") {
        myChart3.setOption(option, true);
    }
           </script>  
           
           
               
        </div>         

    显示效果:

    另外项目中还用到树形图表用来表示文件目录结构:

     可钻入的矩形树图:

     由于pyecharts0.5.x中不存在这个图表,pyecharts v1.0.0和echarts中没有添加还是我没有认真看也没有发现这个,就自己实现了和这个类似的钻入树形图表:

    同时为了练手也自己实现了一个条形图表:

     图形条数和形状是根据数据变化来做适应的,但是美观度比echarts还是逊色不少

    3 . echarts事件交互的使用

    项目中使用到一个雷达图,需要鼠标点击便签进入便签的子图,也是一个类似的钻入图形,逻辑代码部分较多,省略了getOption( argName)函数中的部分逻辑代码:

     <div id="container" style="height: 800px"></div>
        
           <script type="text/javascript">
    var dom = document.getElementById("container");
    var myChart = echarts.init(dom);
    var app = {};
    var weight=1000; //权重的倍数
    var weight1=800;
    function getOption( argName){
        var ardData=[];
    
        if(argName=="闭源特性"){ //判断点击文字
           var weightBuf= [{{weights3D.0}},{{weights3D.1}},{{weights3D.2}},{{weights3D.3}},{{weights3D.4}},
                            ];
                            
            var weightBuf1=[];
            weightBuf.forEach(myFunction);    
            function myFunction(value, index, array) {
              weightBuf1.push(value*weight1); 
            }
               ardData=[
                        {
                            value : [{{data3D.0.value.2}},{{data3D.1.value.2}},{{data3D.2.value.2}},{{data3D.3.value.2}},{{data3D.4.value.2}}, 
                           ],
                            name : '评分'
                        },
                         {
                            value : weightBuf1,
                            name : '权重'
                        }
                    ];
            option = null;
            option = {
                title: {
                    text: '雷达图',
                    subtext: '点击文字要素返回顶层属性雷达图',
                },
                tooltip: {
                    formatter:function(params)
                    {
                        namelist=['正确性', '可靠性', '安全性', '可理解性','代码熵']
                        var eachli=params.value;
                        if (params.name=='权重')
                        eachli=weightBuf;
                         return "<div >"+params.name+'<br>'+
                        namelist[0]+':'+eachli[0]+'<br>'+
                       namelist[1]+':'+eachli[1]+'<br>'+
                       namelist[2]+':'+eachli[2]+'<br>'+
                       namelist[3]+':'+eachli[3]+'<br>'+
                       namelist[4]+':'+eachli[4]+
                       "</div>";
                    }, 
                },
                legend: {
                    data: ['评分(scole)', '权重(weight)']
                },
                radar: {
                    // shape: 'circle',
                    name: {
                        textStyle: {
                            color: '#000',
                            backgroundColor: '#dee',
                            borderRadius: 3,
                            padding: [3, 5]
                       }
                    }, 
                    indicator: [
                       { name: '正确性', max: 100},
                       { name: '可靠性', max: 100},
                       { name: '安全性', max: 100},
                       { name: '可理解性', max: 100},
                       { name: '代码熵', max: 100},
                    ],
                    triggerEvent:true
                },
                
                series: [{
                    name: '评分 vs 权重',
                    type: 'radar',
                    // areaStyle: {normal: {}},
                    data : ardData
                }]
            };;
        }
     return option;
    }
    option=getOption("root");
    if (option && typeof option === "object") {
        myChart.setOption(option, true);
        
        
          myChart.on('click', function (params) {
            console.log(params);
           // alert(params.name);
            myChart.setOption(getOption(params.name), true);
         });
    
    }
           </script>     
           

    主要是用

     myChart.on('click', function (params) {
            console.log(params);
           // alert(params.name);
            myChart.setOption(getOption(params.name), true);
         });
    来监听鼠标点击标签事件,然后通过getOption来动态构建option显示,就达到了钻入效果

    点击之后的钻入效果

     4. 自定义tooltip标签

    在tooltip中定义formatter,params参数为当前活动的元素数据

    tooltip: {
                formatter:function(params)
                    {
                       var errors=0;
                       for(var i =0;i< json_data.length;i++)
                       {
                            if (json_data[i][3]==params.name)
                            {
                                errors=json_data[i][4];
                                break;
                            }
                       }
                       return "<div >"+"文件路径:"+params.name+'<br>'+
                      "代码行数:"+params.value[2]+'<br>'+
                      "缺陷数量:"+errors+
                       "</div>";
                    }, 
            },

    效果:

    提示框浮层内容格式器,支持字符串模板和回调函数两种形式。

    1, 字符串模板

    模板变量有 {a}{b}{c}{d}{e},分别表示系列名,数据名,数据值等。 在 trigger 为 'axis' 的时候,会有多个系列的数据,此时可以通过 {a0}{a1}{a2} 这种后面加索引的方式表示系列的索引。 不同图表类型下的 {a}{b}{c}{d} 含义不一样。 其中变量{a}{b}{c}{d}在不同图表类型下代表数据含义为:

    • 折线(区域)图、柱状(条形)图、K线图 : {a}(系列名称),{b}(类目值),{c}(数值), {d}(无)

    • 散点图(气泡)图 : {a}(系列名称),{b}(数据名称),{c}(数值数组), {d}(无)

    • 地图 : {a}(系列名称),{b}(区域名称),{c}(合并数值), {d}(无)

    • 饼图、仪表盘、漏斗图: {a}(系列名称),{b}(数据项名称),{c}(数值), {d}(百分比)

    更多其它图表模板变量的含义可以见相应的图表的 label.formatter 配置项。

    示例:

    formatter: '{b0}: {c0}<br />{b1}: {c1}'

    2, 回调函数

    回调函数格式:

    (params: Object|Array, ticket: string, callback: (ticket: string, html: string)) => string

    第一个参数 params 是 formatter 需要的数据集。格式如下:

    {
        componentType: 'series',
        // 系列类型
        seriesType: string,
        // 系列在传入的 option.series 中的 index
        seriesIndex: number,
        // 系列名称
        seriesName: string,
        // 数据名,类目名
        name: string,
        // 数据在传入的 data 数组中的 index
        dataIndex: number,
        // 传入的原始数据项
        data: Object,
        // 传入的数据值。在多数系列下它和 data 相同。在一些系列下是 data 中的分量(如 map、radar 中)
        value: number|Array|Object,
        // 坐标轴 encode 映射信息,
        // key 为坐标轴(如 'x' 'y' 'radius' 'angle' 等)
        // value 必然为数组,不会为 null/undefied,表示 dimension index 。
        // 其内容如:
        // {
        //     x: [2] // dimension index 为 2 的数据映射到 x 轴
        //     y: [0] // dimension index 为 0 的数据映射到 y 轴
        // }
        encode: Object,
        // 维度名列表
        dimensionNames: Array<String>,
        // 数据的维度 index,如 0 或 1 或 2 ...
        // 仅在雷达图中使用。
        dimensionIndex: number,
        // 数据图形的颜色
        color: string,
    
        // 饼图的百分比
        percent: number,
    
    }

    我这里使用的回调函数,定义雷达图更方便一点
    其他可参考官方文档教程:
    https://www.echartsjs.com/zh/option.html#title

  • 相关阅读:
    Solaris 10学习笔记初学
    EBS R12中文升级补丁
    EXPDP,今天犯了个愚蠢的错误
    LOGSTDBY status: ORA01418,Logical standby問題可真多
    ORA04045,Standby停止Apple log处理一例
    无法relay信件处理一例
    cordova启动页面和图标的设置
    CSS布局探密02
    CSS布局探密01
    CSS布局探密03
  • 原文地址:https://www.cnblogs.com/pozhu15/p/11799982.html
Copyright © 2011-2022 走看看