简体   繁体   English

如何更改高图中条形图的宽度?

[英]How can I change the width of the bars in a highchart?

With a bar chart like this one , is is possible to change the width of the bars to represent another data attribute, say the weight of the fruits.使用像这样的条形图,可以更改条形的宽度以表示另一个数据属性,例如水果的重量。 The heavier the fruit is, the thicker the bar.水果越重,条越厚。

You play with the script here .您可以在此处使用脚本。 I am open to other javascript plotting libraries that could do that as long as they are free.我对其他 javascript 绘图库持开放态度,只要它们是免费的,就可以做到这一点。

$(function () {
    var chart;
    $(document).ready(function() {
        chart = new Highcharts.Chart({
            chart: {
                renderTo: 'container',
                type: 'column'
            },
            title: {
                text: 'Column chart with negative values'
            },
            xAxis: {
                categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
            },
            tooltip: {
                formatter: function() {
                    return ''+
                        this.series.name +': '+ this.y +'';
                }
            },
            credits: {
                enabled: false
            },
            series: [{
                name: 'John',
                data: [5, 3, 4, 7, 2]
                // I would like something like this (3.5, 6 etc is the width) :
                // data: [[5, 3.4], [3, 6], [4, 3.4], [7, 2], [2, 5]]
            }, {
                name: 'Jane',
                data: [2, -2, -3, 2, 1]
            }, {
                name: 'Joe',
                data: [3, 4, 4, -2, 5]
            }]
        });
    });

});​



pointWidth is what you require to set the width of the bars. pointWidth是设置条形宽度所需要的。 try尝试

plotOptions: {
            series: {
                pointWidth: 15
            }
        }


This display bars with the width of 15px.此显示条宽度为 15px。 Play around here .这里玩耍。 Just made an edit to the already existing code.刚刚对现有代码进行了编辑。

I use a set of area charts to simulate a variable-width-column/bar-chart.我使用一组面积图来模拟可变宽度的列/条形图。 Say, each column/bar is represented by a rectangle area.比如说,每个列/条都由一个矩形区域表示。

See my fiddle demo ( http://jsfiddle.net/calfzhou/TUt2U/ ).请参阅我的小提琴演示( http://jsfiddle.net/calfzhou/TUt2U/ )。

$(function () {
    var rawData = [
        { name: 'A', x: 5.2, y: 5.6 },
        { name: 'B', x: 3.9, y: 10.1 },
        { name: 'C', x: 11.5, y: 1.2 },
        { name: 'D', x: 2.4, y: 17.8 },
        { name: 'E', x: 8.1, y: 8.4 }
    ];

    function makeSeries(listOfData) {
        var sumX = 0.0;
        for (var i = 0; i < listOfData.length; i++) {
            sumX += listOfData[i].x;
        }
        var gap = sumX / rawData.length * 0.2;
        var allSeries = []
        var x = 0.0;
        for (var i = 0; i < listOfData.length; i++) {
            var data = listOfData[i];
            allSeries[i] = {
                name: data.name,
                data: [
                    [x, 0], [x, data.y],
                    {
                        x: x + data.x / 2.0,
                        y: data.y,
                        dataLabels: { enabled: true, format: data.x + ' x {y}' }
                    },
                    [x + data.x, data.y], [x + data.x, 0]
                ],
                w: data.x,
                h: data.y
            };
            x += data.x + gap;
        }
        return allSeries;
    }

    $('#container').highcharts({
        chart: { type: 'area' },
        xAxis: {
            tickLength: 0,
            labels: { enabled: false}
        },
        yAxis: {
            title: { enabled: false}
        },
        plotOptions: {
            area: {
                marker: {
                    enabled: false,
                    states: {
                        hover: { enabled: false }
                    }
                }
            }
        },
        tooltip: {
            followPointer: true,
            useHTML: true,
            headerFormat: '<span style="color: {series.color}">{series.name}</span>: ',
            pointFormat: '<span>{series.options.w} x {series.options.h}</span>'
        },
        series: makeSeries(rawData)
    });
});

我的演示图表

Fusioncharts probably is the best option if you have a license for it to do the more optimal Marimekko charts… Fusioncharts 可能是最好的选择,如果您有许可证可以制作更佳的 Marimekko 图表……

I've done a little work trying to get a Marimekko charts solution in highcharts.我做了一些工作,试图在 highcharts 中获得 Marimekko 图表解决方案。 It's not perfect, but approximates the first Marimekko charts example found here on the Fusion Charts page…它并不完美,但近似于在 Fusion Charts 页面上找到的第一个 Marimekko 图表示例……

http://www.fusioncharts.com/resources/chart-tutorials/understanding-the-marimekko-chart/ http://www.fusioncharts.com/resources/chart-tutorials/understanding-the-marimekko-chart/

The key is to use a dateTime axis, as that mode provides you more flexibility for the how you distribute points and line on the X axis which provides you the ability to have variably sized "bars" that you can construct on this axis.关键是使用日期时间轴,因为该模式为您在 X 轴上分布点和线的方式提供了更大的灵活性,这使您能够在此轴上构建可变大小的“条”。 I use 0-1000 second space and outside the chart figure out the mappings to this scale to approximate percentage values to pace your vertical lines.我使用 0-1000 秒的空间,并在图表外找出与此比例的映射,以近似百分比值来调整垂直线。 Here ( http://jsfiddle.net/miken/598d9/2/ ) is a jsfiddle example that creates a variable width column chart.这里( http://jsfiddle.net/miken/598d9/2/ )是一个 jsfiddle 示例,它创建了一个可变宽度的柱状图。

    $(function () {

    var chart;
        Highcharts.setOptions({
            colors: [ '#75FFFF', '#55CCDD', '#60DD60' ]
        });
        $(document).ready(function() {
            var CATEGORY = {  // number out of 1000
            0: '',    
            475: 'Desktops',
            763: 'Laptops',
            1000: 'Tablets'  
        };
        var BucketSize = {  
            0: 475,
            475: 475,
            763: 288,
            1000: 237   
        };
        chart = new Highcharts.Chart({
            chart: {
                renderTo: 'container',
                type: 'area'
            },
            title: {
                text: 'Contribution to Overall Sales by Brand & Category (in US$)<br>(2011-12)'
            },
            xAxis: {
                min: 0,
                max: 1000,
                title: {
                    text: '<b>CATEGORY</b>'
                },
                tickInterval: 1,
                minTickInterval: 1,
                dateTimeLabelFormats: {
                    month: '%b'
                },
                labels: {
                    rotation: -60,
                    align: 'right',
                    formatter: function() {
                        if (CATEGORY[this.value] !== undefined) {
                            return '<b>' + CATEGORY[this.value] + ' (' + 
                                this.value/10 + '%)</b>';
                        }
                    }
                }
            },
            yAxis: {
                max: 100,
                gridLineWidth: 0,
                title: {
                    text: '<b>% Share</b>'
                },
                labels: {
                    formatter: function() {
                        return this.value +'%'
                    }
                }
            },
            tooltip: {
                shared: true,
                useHTML: true,
                formatter: function () {
                    var result = 'CATEGORY: <b>' +
                        CATEGORY[this.x] + ' (' + Highcharts.numberFormat(BucketSize[this.x]/10,1) + '% sized bucket)</b><br>';
                    $.each(this.points, function(i, datum) {
                        if (datum.point.y !== 0) {
                            result += '<span style="color:' +
                                datum.series.color + '"><b>' +
                                datum.series.name + '</b></span>: ' +
                                    '<b>$' + datum.point.y + 'K</b> (' +
                                Highcharts.numberFormat(
                                    datum.point.percentage,2) +
                                '%)<br/>';
                        }
                    });
                return (result);
                }
            },
            plotOptions: {
                area: {
                    stacking: 'percent',
                    lineColor: 'black',
                    lineWidth: 1,
                    marker: {
                        enabled: false
                    },
                    step: true
                }
            },
            legend: {
                layout: 'vertical',
                align: 'right',
                verticalAlign: 'top',
                x: 0,
                y: 100,
                borderWidth: 1,
                title: {
                text : 'Brand:'
                }
            },
            series: [ {
                name: 'HP',
                data: [
                    [0,298],
                    [475,109],
                    [763,153],
                    [1000,153]          
                ]
            }, {
               name: 'Dell',
                data: [
                    [0,245],
                    [475,198],
                    [763,120],
                    [1000,120]
               ]
            }, {
                name: 'Sony',
                data: [
                    [0,335],
                    [475,225],
                    [763,164],
                    [1000,164]          
               ]
            }]
        },
        function(chart){    
            // Render bottom line.
            chart.renderer.path(['M', chart.plotLeft, chart.plotHeight + 66, 'L', chart.plotLeft+chart.plotWidth, chart.plotHeight + 66])
            .attr({
                'stroke-width': 3,
                stroke: 'black',
                zIndex:50
            })
            .add();
            for (var category_idx in CATEGORY) {
                chart.renderer.path(['M', (Math.round((category_idx / 1000) * chart.plotWidth)) + chart.plotLeft, 66, 'V', chart.plotTop + chart.plotHeight])
                .attr({
                    'stroke-width': 1,
                    stroke: 'black',
                    zIndex:4
                })
                .add();
            }
        });
    });
});

It adds an additional array to allow you to map category names to second tic values to give you a more "category" view that you might want.它添加了一个额外的数组,允许您将类别名称映射到第二个 tic 值,从而为您提供您可能想要的更多“类别”视图。 I've also added code at the bottom that adds vertical dividing lines between the different columns and the bottom line of the chart.我还在底部添加了代码,用于在不同列和图表底线之间添加垂直分隔线。 It might need some tweaks for the size of your surrounding labels, etc. that I've hardcoded in pixels here as part of the math, but it should be doable.它可能需要对周围标签的大小进行一些调整,等等,作为数学的一部分,我在这里以像素为单位进行了硬编码,但它应该是可行的。

Using a 'percent' type accent lets you have the y scale figure out the percentage totals from the raw data, whereas as noted you need to do your own math for the x axis.使用“百分比”类型的重音可以让您通过 y 刻度计算原始数据中的百分比总数,而如前所述,您需要对 x 轴进行自己的数学计算。 I'm relying more on a tooltip function to provide labels, etc than labels on the chart itself.我更多地依赖工具提示功能来提供标签等,而不是图表本身的标签。

Another big improvement on this effort would be to find a way to make the tooltip hover area and labels to focus and be centered and encompass the bar itself instead of the right border of each bar that it is now.这项工作的另一个重大改进是找到一种方法使工具提示悬停区域和标签聚焦并居中并包含栏本身,而不是现在每个栏的右边框。 If someone wants to add that, feel free to here.如果有人想添加,请随意到这里。

If I got it right you want every single bar to be of different width.如果我做对了,您希望每个条都具有不同的宽度。 I had same problem and struggled a lot to find a library offering this option.我遇到了同样的问题,并且很难找到提供此选项的库。 I came to the conclusion - there's none.我得出结论——没有。

Anyways, I played with highcharts a little, got creative and came up with this:无论如何,我玩了点highcharts,得到了创意并想出了这个:
You mentioned that you'd like your data to look something like this: data: [[5, 3.4], [3, 6], [4, 3.4]] , with the first value being the height and the second being the width.你提到你希望你的数据看起来像这样: data: [[5, 3.4], [3, 6], [4, 3.4]] ,第一个值是高度,第二个是宽度.

Let's do it using the highcharts' column graph.让我们使用 highcharts 的柱状图来完成。

Step 1:第1步:
To better differentiate the bars, input each bar as a new series.为了更好地区分条形,请将每个条形输入为一个新系列。 Since I generated my data dynamically, I had to assign new series dynamically:由于我动态生成数据,因此必须动态分配新系列:

const objects: any = [];
const extra = this.data.length - 1;
this.data.map((range) => {
  const obj = {
    type: 'column',
    showInLegend: false,
    data: [range[1]],
    animation: true,
    borderColor: 'black',
    borderWidth: 1,
    color: 'blue'
  };
  for (let i = 0; i < extra; i++) {
    obj.data.push(null);
  }
  objects.push(obj);
});
this.chartOptions.series = objects;

That way your different series would look something like this:这样你的不同系列看起来像这样:

series: [{
  type: 'column',
  data: [5, 3.4]
}, {
  type: 'column',
  data: [3, 6]
}, {
  type: 'column',
  data: [4, 3.4]
}]



Step 2:第2步:
Assign this as plot options for highcharts:将此指定为 highcharts 的绘图选项:

plotOptions: {
  column: {
    pointPadding: 0,
      borderWidth: 0,
      groupPadding: 0,
      shadow: false
  }
}



Step 3:第 3 步:
Now let's get creative - to have the same starting point for all bars, we need to move every single one to the graph's start:现在让我们发挥创意 - 为了让所有条形具有相同的起点,我们需要将每个条形移动到图形的起点:

setColumnsToZero() {
  this.data.map((item, index) => {
    document.querySelector('.highcharts-series-' + index).children[0].setAttribute('x', '0');
  });
}



Step 4:第四步:

getDistribution() {
  let total = 0;

  // Array including all of the bar's data: [[5, 3.4], [3, 6], [4, 3.4]]
  this.data.map(item => {
    total = total + item[0];
  });

  // MARK: Get xAxis' total width
  const totalWidth = document.querySelector('.highcharts-axis-line').getBoundingClientRect().width;

  let pos = 0;
  this.data.map((item, index) => {
    const start = item[0];
    const width = (start * totalWidth) / total;
    document.querySelector('.highcharts-series-' + index).children[0].setAttribute('width', width.toString());
    document.querySelector('.highcharts-series-' + index).children[0].setAttribute('x', pos.toString());
    pos = pos + width;
    this.getPointsPosition(index, totalWidth, total);
  });
}



Step 4:第四步:
Let's get to the xAxis' points.让我们来看看 xAxis 的点。 In the first functions modify the already existing points, move the last point to the end of the axis and hide the others.在第一个函数中修改已经存在的点,将最后一个点移动到轴的末端并隐藏其他点。 In the second function we clone the last point, modify it to have either 6 or 3 total xAxis points and move each of them to the correct position在第二个函数中,我们克隆最后一个点,将其修改为总共有 6 个或 3 个 xAxis 点并将它们中的每一个移动到正确的位置

getPointsPosition(index, totalWidth, total) {
  const col = document.querySelector('.highcharts-series-' + index).children[0];
  const point = (document.querySelector('.highcharts-xaxis-labels').children[index] as HTMLElement);
  const difference = col.getBoundingClientRect().right - point.getBoundingClientRect().right;
  const half = point.getBoundingClientRect().width / 2;
  if (index === this.data.length - 1) {
    this.cloneNode(point, difference, totalWidth, total);
  } else {
    point.style.display = 'none';
  }
  point.style.transform = 'translateX(' + (+difference + +half) + 'px)';

  point.innerHTML = total.toString();
}

cloneNode(ref: HTMLElement, difference, totalWidth, total) {
  const width = document.documentElement.getBoundingClientRect().width;

  const q = total / (width > 1000 && ? 6 : 3);
  const w = totalWidth / (width > 1000 ? 6 : 3);
  let val = total;
  let valW = 0;
  for (let i = 0; i < (width > 1000 ? 6 : 3); i++) {
    val = val - q;
    valW = valW + w;
    const clone = (ref.cloneNode(true) as HTMLElement);

    document.querySelector('.highcharts-xaxis-labels').appendChild(clone);

    const half = clone.getBoundingClientRect().width / 2;

    clone.style.transform = 'translateX(' + (-valW + difference + half) + 'px)';
    const inner = Math.round(val * 100) / 100;
    clone.innerHTML = inner.toString();
  }
}



In the end we have a graph looking something like this (not the data from this given example, but for [[20, 0.005], [30, 0.013333333333333334], [20, 0.01], [30, 0.005555555555555555], [20, 0.006666666666666666]] with the first value being the width and the second being the height):最后,我们有一个看起来像这样的图(不是来自这个给定示例的数据,而是[[20, 0.005], [30, 0.013333333333333334], [20, 0.01], [30, 0.005555555555555555], [20, 0.006666666666666666]] ,第一个值为宽度,第二个值为高度): 在此处输入图片说明


There might be some modifications to do to 100% fit your case.可能需要进行一些修改以 100% 适合您的情况。 Fe I had to adjust the xAxis' points a specific starting and end point - I spared this part. Fe 我不得不将 xAxis 的点调整为特定的起点和终点 - 我省去了这部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM