Search code examples
echarts

Apache echarts linear transformation of dataset


I want to perform linear transformation from input dataset to another unit (ex: millimeters to meters). In the documentation I see 'filter' and 'sort' and other builtins but no 'map'. I tried the following:

  const dataset = [{
            source : source // source in millimeters
        },{
            transform : {
                type: 'map',
                config: {
                    convert: value => value / 1000 // to meters
                }
            }
        }
        ]
        var option = {
            legend: {},
            tooltip: {},
            dataset : dataset,
            xAxis: {type: 'category' },
            yAxis: {type: 'value', name: 'm'},
            series: [ {
                    // some series configuration here to group some elements
                    datasetIndex: 1
              } ]
        };

        var myChart = echarts.init(document.getElementById('graph'));
        myChart.setOption(option);

Echarts throws an exception when I added datasetIndex: 1. Was not performing any transform prior to that. I'm not quite sure what is missing here


Solution

  • A custom transform should be defined externally (with respect to the chart configuration object); the config part of the transform is used to define the parameters of the transform, in the same way it is used for a sort transform to set dimension (which component to sort the data by) or order (sort ascending or descending).

    Here's a simple example of a transform that does what you intend.

    A custom transform's type will necessarily have a namespace and a function, let's call it units:multiple. It has to be registered to echarts, see the example in the tutorial on "Use external transforms".

    // Register the external transform at first.
    echarts.registerTransform(units.multiple);
    

    We'll use as parameters to be set up in config, dimension - which component to transform, and factor (the multiplicative factor). With these, we're done with the use of the transform:

    dataset: [
       {
          source : [
              {'year': '2012', 'value': 4110},
              {'year': '2013', 'value': 3040},
              //.......
           ]
       },
    
       {
           transform: {
           type: 'units:multiple',
           config: {dimension: 'value', factor: 0.001}
       }
    ]
    

    Now we can start with the implementation of the transform, which will have to be available to the script, before the others, i.e., before the echarts registration call. We'll use as model the ecStat:regression implementation.

    const units = {
        multiple:{
            type: 'units:multiple',
            transform: function(params){
                const rawData = params.upstream.cloneRawData();
                const {dimension, factor} = params.config; // add default case and error management
                const data = rawData.map(o=>({...o, [dimension]: o[dimension]*factor}));
                return [{
                    dimensions: params.upstream.cloneAllDimensionInfo(),
                    data
                }];
            }
        }
    };
    

    Further information (e.g., on upstream) in can be gained by looking at the source code of transform.ts.

    Full snippet example:

    const units = {
        multiple:{ // the tranform code
            type: 'units:multiple',
            transform: function(params){
                const rawData = params.upstream.cloneRawData();
                const {dimension, factor} = params.config; // add default case and error management
                const data = rawData.map(o=>({...o, [dimension]: o[dimension]*factor}));
                return [{
                    dimensions: params.upstream.cloneAllDimensionInfo(),
                    data
                }];
            }
        }
    };
    
    echarts.registerTransform(units.multiple);
    
    
    const dom = document.getElementById('chart-container');
    const myChart = echarts.init(dom, null, {
        renderer: 'canvas',
        useDirtyRect: false
    });
    
    const option = {
        dataset: [
            {
                source : [
                    {'year': '2012', 'total': 4110},
                    {'year': '2013', 'total': 3040},
                    {'year': '2014', 'total': 6510},
                    {'year': '2015', 'total': 5330},
                    {'year': '2016', 'total': 5830},
                    {'year': '2017', 'total': 5940},
                    {'year': '2018', 'total': 6550},
                    {'year': '2019', 'total': 6380},
                    {'year': '2020', 'total': 4540},
                    {'year': '2021', 'total': 5120},
                    {'year': '2022', 'total': 5290},
                    {'year': '2023', 'total': 6900},
                ]
            },
    
            {
                transform: {
                    type: 'units:multiple',
                    config: {dimension: 'total', factor: 0.001}
                }
            }
        ],
        xAxis: [
            { type: 'category' },
        ],
        yAxis: [{}],
        series: [
            { type: 'bar',  datasetIndex: 1}
        ]
    };
    
    myChart.setOption(option);
    <div id="chart-container" style="min-width: 700px;height: 80vh; min-height: 500px"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.3/echarts.min.js"></script>