Reference Line

Bar Chart with reference Line

main
run-button
run-button
reset-button
loadData('/static/cars.json').then((res) => {
    // Retrieves the DataModel from muze namespace. Muze recognizes DataModel as a first class source of data.
    let DataModel = muze.DataModel;
    // Get the factory to compose new layers
    let layerFactory = muze.layerFactory;
    // Import the reference to the DataModel operator
    let groupBy = DataModel.Operators.groupBy;
    let sort = DataModel.Operators.sort;

    // Compose layers to draw the bars as well as the reference line and text
    layerFactory.composeLayers('compositeBar', [
        {
            name: 'simplebar',
            mark: 'bar',
            encoding: {
                x: 'compositeBar.encoding.x',
                y: 'compositeBar.encoding.y',
                color: 'compositeBar.encoding.color',
            }
        },
        {
            name: 'averageLine',
            mark: 'tick',
            source: 'averageLine',
            className: 'averageLine',
            encoding: {
                y: 'compositeBar.encoding.y',
                x: null
            },
            calculateDomain: false
        },
        {
            name: 'averageText',
            mark: 'text',
            source: 'averageLine',
            className: 'averageText',
            encoding: {
                y: 'compositeBar.encoding.y',
                text: 'compositeBar.encoding.text',
                background: {
                    enabled: true
                }
            },
            encodingTransform: (points, layer, dependencies) => {
                // Transforms the test after the physical dimension is resolved so that it comes in the middle of the background
                let width = layer.measurement().width;
                let smartLabel = dependencies.smartLabel;
                for (let i = 0; i < points.length; i++) {
                    let size = smartLabel.getOriSize(points[i].text);
                    points[i].update.x = width - 5;
                    points[i].textanchor = 'end';
                    points[i].update.y -= size.height / 2;
                    points[i].color = '#000';
                }
                return points;
            },
            calculateDomain: false
        }
    ]);
    
    // Schema for the data
    const schema = [
        { name: 'Name', type: 'dimension' },
        { name: 'Maker', type: 'dimension' },
        { name: 'Miles_per_Gallon', type: 'measure', defAggFn: 'max' },
        { name: 'Displacement', type: 'measure', defAggFn: 'max' },
        { name: 'Horsepower', type: 'measure', defAggFn: 'avg' },
        { name: 'Weight_in_lbs', type: 'measure', defAggFn: 'min' },
        { name: 'Acceleration', type: 'measure', defAggFn: 'avg' },
        { name: 'Origin', type: 'dimension' },
        { name: 'Cylinders', type: 'dimension' },
        { name: 'Year', type: 'dimension' },
    ];
     
    let rootData = new DataModel(res, schema);

    // Apply groupBy and sorting from outside muze. Muze internally perfoms gouping of data to eliminate duplicate data. Sorting followed by groupBy does not
    // ensure retention of the order of data defined by sorting. Hence we do grouping and sorting from outside the visualizaiton.
    rootData = groupBy(['Year'], {
        Horsepower: 'max',
        Acceleration: 'avg'
    })(rootData);
    rootData = sort([['Horsepower', 'DESC']])(rootData);

    // Create an environment for future rendering
    let env = muze();
     // Create an instance of canvas which houses the visualization
    let canvas = env.canvas();

    canvas = canvas
        .rows(['Horsepower']) // Horsepower goes in Y-Axis
        .columns(['Year']) // Year goes in X-Axis
        .data(rootData)
        .transform({ // Create different sources (data) from the root source (data). Layers can access these sources and draw any visualization
            'averageLine': (dt) => dt.groupBy([''], { Horsepower: 'avg' }) // Removes all the dim and aggregate the measures
        })
        .layers([
            {
                mark: 'compositeBar',
                encoding: {
                    text: {
                        field: 'Horsepower',
                        formatter: (value) => {
                            return `Average Horsepower: ${Math.round(value)}`;
                        }
                    }
                }
            }
        ])
        .config({
            autoGroupBy: { // Dont perform groupBy internally, as sorting order was specified
                disabled: true
            }
        })
        .width(600)
        .height(400)
        .title('Sorted bar with trendline', { position: "top", align: "left", })
        .subtitle('Average horsepower per year with average horsepower of all time marked as reference', { position: "top", align: "left" })
        .mount(document.getElementById('chart-container'));
});