echarts学习笔记

参考

5 分钟上手 ECharts

引入echarts.js:

  • GitHub 中的 echarts/dist 文件夹中获取构建好的 echarts
  • 使用完全版js:echarts/dist/echarts.js,体积最大,包含所有的图表和组件,复制该文件到 static/js 文件夹下
  • 在html文件中引入: <script src="/static/js/echarts.js"></script>

使用cdn的引入方式,参考:https://www.jsdelivr.com/package/npm/echarts, 在 <head> 引入:

<script src="https://cdn.jsdelivr.net/npm/echarts@5.0.1/dist/echarts.min.js"></script>

创建文件夹 flaskAPP\templates, 创建模版 index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts</title>
    <!-- 引入 echarts.js -->
    <script src="/static/js/echarts.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));
        var myChart2 = echarts.init(document.getElementById('main2'));
        // 指定图表的配置项和数据
        var option = {
            title:  {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            legend: {
                data:['销量']
            },
            xAxis: {
                data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
            },
            yAxis: {},
            series: [{
                name: '销量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        };

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
        myChart2.setOption(option);
    </script>
</body>
</html>

根目录下创建 server.py

from flask import Flask,render_template

app = Flask(__name__, static_folder="templates")

@app.route("/")
def index():
    return render_template("index.html")

if __name__ == '__main__':
    app.run(host='127.0.0.1',port='5000',debug=True)

执行 python server.py 后访问 http://127.0.0.1:5000/

ECharts 基础概念

一个网页中可以创建多个 echarts 实例,每个 echarts 实例独占一个 DOM 节,如上例中的 myChart。每个 echarts 实例 中可以创建多个图表和坐标系等等(用 option 来描述)。准备一个 DOM 节点(作为 echarts 的渲染容器),就可以在上面创建一个 echarts 实例。

以下建了两个 div标签装两个chart。

    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));

        // 指定图表的配置项和数据
        var option = {
            title:  {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            legend: {
                data:['销量']
            },
            xAxis: {
                data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
            },
            yAxis: {},
            series: [{
                name: '销量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        };

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>
    <div id="main2" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
    var myChart2 = echarts.init(document.getElementById('main2'));
    myChart2.setOption(option);
    </script>

系列(series):一组数值以及他们映射成的图。“系列”这个词原本可能来源于“一系列的数据”,而在 echarts 中取其扩展的概念,不仅表示数据,也表示数据映射成为的图。所以,一个 系列 包含的要素至少有:

  • 一组数值
  • 图表类型(series.type)
  • 以及其他的关于这些数据如何映射成图的参数。

echarts 里系列类型(series.type)就是图表类型。系列类型(series.type)至少有:line(折线图)、bar(柱状图)、pie(饼图)、scatter(散点图)、graph(关系图)、tree(树图)、...

var option = {
            title:  {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            legend: {
                data:['销量','价格']
            },
            xAxis: {
                data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
            },
            yAxis: {},
            series: [{
                name: '销量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            },
            {
                name: '价格',
                type: 'line',
                data: {{data2}}
            },
            ]
        };

组件(component):在系列之上,echarts 中各种内容,被抽象为“组件”。组件和系列应该是平级的。系列(series)也是一种组件,可以理解为:系列是专门绘制“图”的组件。

echarts 中至少有这些组件:xAxis(直角坐标系 X 轴)、yAxis(直角坐标系 Y 轴)、grid(直角坐标系底板)、angleAxis(极坐标系角度轴)、radiusAxis(极坐标系半径轴)、polar(极坐标系底板)、geo(地理坐标系)、dataZoom(数据区缩放组件)、visualMap(视觉映射组件)、tooltip(提示框组件)、toolbox(工具栏组件)、series(系列)、...

option:echarts 使用 option 来描述其对图表的各种需求,包括:有什么数据、要画什么图表、图表长什么样子、含有什么组件、组件能操作什么事情等等。简而言之,option 表述了:数据、数据如何映射成图形、交互行为。

所以正常的echats处理逻辑:

  • js里为各个图形在 html中申请一个容器,比如某id的 div
  • js里配置option:包括数据和其他图形配置选项
  • 每个图形调用特定的option进行渲染,option可以在python中定义

python中定义 echarts 的option,传递给模版渲染

index.html,注意使用 tojson:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts</title>
    <!-- 引入 echarts.js -->
    <script src="/static/js/echarts.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript" >
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));

        // 指定图表的配置项和数据
        var option = {{myChartOption|tojson}};

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>
</body>
</html>

server.py,注意使用 JSON_AS_ASCII避免中文乱码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from flask import Flask,render_template,url_for

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False


@app.route("/")
def index():
    echatsjs = url_for("static",filename="js/echarts.js")
    myChartOption =  {
            'title': {
                'text': 'ECharts 入门示例'
            },
            'tooltip': {},
            'legend': {
                'data':['销量','价格']
            },
            'xAxis': {
                'data': ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
            },
            'yAxis': {},
            'series':   [{
                'name': '销量',
                'type': 'bar',
                'data': [5, 20, 36, 10, 10, 20]
            },
            {
                'name': '价格',
                'type': 'line',
                'data': [10, 40, 76, 20, 20, 400]
            }]
            }

    return render_template("index.html",echatsjs=echatsjs,myChartOption = myChartOption)

if __name__ == '__main__':
    app.run(host='127.0.0.1',port='5000',debug=True)

这样模版页面只需要定义图形id等, 图形的渲染信息由flask后端传递给模版。

K线图

参考: ECharts图表使用之K线图.

echarts官方版本: https://echarts.apache.org/examples/zh/editor.html?c=candlestick-brush

效果:

源码:

<div id="mainec" style="width: 600px;height:400px;"></div>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.0.1/dist/echarts.min.js"></script>
<script type="text/javascript">
//var echarts = require('echarts');
var ROOT_PATH = 'https://cdn.jsdelivr.net/gh/apache/echarts-website@asf-site/examples';
var chartDom = document.getElementById('mainec');
var myChart = echarts.init(chartDom);
var option;
var upColor = '#00da3c';
var downColor = '#ec0000';
function splitData(rawData) {
    var categoryData = [];
    var values = [];
    var volumes = [];
    for (var i = 0; i < rawData.length; i++) {
        categoryData.push(rawData[i].splice(0, 1)[0]);
        values.push(rawData[i]);
        volumes.push([i, rawData[i][4], rawData[i][0] > rawData[i][1] ? 1 : -1]);
    }
    return {
        categoryData: categoryData,
        values: values,
        volumes: volumes
    };
}
function calculateMA(dayCount, data) {
    var result = [];
    for (var i = 0, len = data.values.length; i < len; i++) {
        if (i < dayCount) {
            result.push('-');
            continue;
        }
        var sum = 0;
        for (var j = 0; j < dayCount; j++) {
            sum += data.values[i - j][1];
        }
        result.push(+(sum / dayCount).toFixed(3));
    }
    return result;
}
$.get(ROOT_PATH + '/data/asset/data/stock-DJI.json', function (rawData) {
    var data = splitData(rawData);
    myChart.setOption(option = {
        animation: false,
        legend: {
            bottom: 10,
            left: 'center',
            data: ['Dow-Jones index', 'MA5', 'MA10', 'MA20', 'MA30']
        },
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                type: 'cross'
            },
            borderWidth: 1,
            borderColor: '#ccc',
            padding: 10,
            textStyle: {
                color: '#000'
            },
            position: function (pos, params, el, elRect, size) {
                var obj = {top: 10};
                obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 30;
                return obj;
            }
            // extraCssText: 'width: 170px'
        },
        axisPointer: {
            link: {xAxisIndex: 'all'},
            label: {
                backgroundColor: '#777'
            }
        },
        toolbox: {
            feature: {
                dataZoom: {
                    yAxisIndex: false
                },
                brush: {
                    type: ['lineX', 'clear']
                }
            }
        },
        brush: {
            xAxisIndex: 'all',
            brushLink: 'all',
            outOfBrush: {
                colorAlpha: 0.1
            }
        },
        visualMap: {
            show: false,
            seriesIndex: 5,
            dimension: 2,
            pieces: [{
                value: 1,
                color: downColor
            }, {
                value: -1,
                color: upColor
            }]
        },
        grid: [
            {
                left: '10%',
                right: '8%',
                height: '50%'
            },
            {
                left: '10%',
                right: '8%',
                top: '63%',
                height: '16%'
            }
        ],
        xAxis: [
            {
                type: 'category',
                data: data.categoryData,
                scale: true,
                boundaryGap: false,
                axisLine: {onZero: false},
                splitLine: {show: false},
                splitNumber: 20,
                min: 'dataMin',
                max: 'dataMax',
                axisPointer: {
                    z: 100
                }
            },
            {
                type: 'category',
                gridIndex: 1,
                data: data.categoryData,
                scale: true,
                boundaryGap: false,
                axisLine: {onZero: false},
                axisTick: {show: false},
                splitLine: {show: false},
                axisLabel: {show: false},
                splitNumber: 20,
                min: 'dataMin',
                max: 'dataMax'
            }
        ],
        yAxis: [
            {
                scale: true,
                splitArea: {
                    show: true
                }
            },
            {
                scale: true,
                gridIndex: 1,
                splitNumber: 2,
                axisLabel: {show: false},
                axisLine: {show: false},
                axisTick: {show: false},
                splitLine: {show: false}
            }
        ],
        dataZoom: [
            {
                type: 'inside',
                xAxisIndex: [0, 1],
                start: 98,
                end: 100
            },
            {
                show: true,
                xAxisIndex: [0, 1],
                type: 'slider',
                top: '85%',
                start: 98,
                end: 100
            }
        ],
        series: [
            {
                name: 'Dow-Jones index',
                type: 'candlestick',
                data: data.values,
                itemStyle: {
                    color: upColor,
                    color0: downColor,
                    borderColor: null,
                    borderColor0: null
                },
                tooltip: {
                    formatter: function (param) {
                        param = param[0];
                        return [
                            'Date: ' + param.name + '<hr size=1 style="margin: 3px 0">',
                            'Open: ' + param.data[0] + '<br/>',
                            'Close: ' + param.data[1] + '<br/>',
                            'Lowest: ' + param.data[2] + '<br/>',
                            'Highest: ' + param.data[3] + '<br/>'
                        ].join('');
                    }
                }
            },
            {
                name: 'MA5',
                type: 'line',
                data: calculateMA(5, data),
                smooth: true,
                lineStyle: {
                    opacity: 0.5
                }
            },
            {
                name: 'MA10',
                type: 'line',
                data: calculateMA(10, data),
                smooth: true,
                lineStyle: {
                    opacity: 0.5
                }
            },
            {
                name: 'MA20',
                type: 'line',
                data: calculateMA(20, data),
                smooth: true,
                lineStyle: {
                    opacity: 0.5
                }
            },
            {
                name: 'MA30',
                type: 'line',
                data: calculateMA(30, data),
                smooth: true,
                lineStyle: {
                    opacity: 0.5
                }
            },
            {
                name: 'Volume',
                type: 'bar',
                xAxisIndex: 1,
                yAxisIndex: 1,
                data: data.volumes
            }
        ]
    }, true);
    myChart.dispatchAction({
        type: 'brush',
        areas: [
            {
                brushType: 'lineX',
                coordRange: ['2016-06-02', '2016-06-20'],
                xAxisIndex: 0
            }
        ]
    });
});
option && myChart.setOption(option);
</script>
© Licensed under CC BY-NC-SA 4.0

想象力比知识更重要! 因为知识是有限的, 而想象力概括着世界的一切, 推动着进步, 并且是知识进化的源泉。——爱因斯坦

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!