欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

pyecharts和echarts的混合使用

程序员文章站 2022-06-16 21:01:20
ECharts是一个由百度开发的纯 Javascript 的图表库,pyecharts是某三位大佬将ECharts移植到Python项目中的产物,在Python网站中可以更轻松的接入图表,但是个人感觉pyecharts比ECharts还是局限很大的,pyecharts0.5.x版本就更为缩水了,由于 ......

  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和echarts的混合使用

 

 

 

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

pyecharts和echarts的混合使用

 

 

 

其他图表也是类似添加,可以参考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>         

显示效果:

pyecharts和echarts的混合使用

 

 

 

 

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

pyecharts和echarts的混合使用

 

 

 可钻入的矩形树图:

pyecharts和echarts的混合使用

 

 

pyecharts和echarts的混合使用

 

 

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

pyecharts和echarts的混合使用

 

 

 

pyecharts和echarts的混合使用

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

pyecharts和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显示,就达到了钻入效果

pyecharts和echarts的混合使用

点击之后的钻入效果

pyecharts和echarts的混合使用

 

 

 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>";
                }, 
        },

效果:

pyecharts和echarts的混合使用

 

 

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

1, 字符串模板

模板变量有 {a}{b}{c}{d}{e},分别表示系列名,数据名,数据值等。 在  为 '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