7

使用这样的条形图,可以更改条形的宽度以表示另一个数据属性,例如水果的重量。水果越重,条越粗。

你在这里玩脚本。我对其他可以做到这一点的 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]
            }]
        });
    });

});​
4

4 回答 4

39



pointWidth 是您设置条形宽度所需的。尝试

plotOptions: {
            series: {
                pointWidth: 15
            }
        }


此显示条的宽度为 15px。在这里玩。刚刚对已经存在的代码进行了编辑。

于 2012-10-30T07:37:39.390 回答
8

我使用一组面积图来模拟可变宽度列/条形图。比如说,每列/条都由一个矩形区域表示。

请参阅我的小提琴演示(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)
    });
});

我的演示图

于 2013-12-13T15:10:25.560 回答
1

如果您有许可证,Fusioncharts 可能是最好的选择,可以制作更优化的 Marimekko 图表……</p>

我做了一些工作,试图在 highcharts 中获得 Marimekko 图表解决方案。它并不完美,但与 Fusion Charts 页面上的第一个 Marimekko 图表示例相近……</p>

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

关键是使用 dateTime 轴,因为该模式为您在 X 轴上分配点和线的方式提供了更大的灵活性,这使您能够在此轴上构建可变大小的“条”。我使用 0-1000 秒的空间,并在图表之外找出到这个比例的映射,以近似百分比值来调整你的垂直线。这里 ( 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();
            }
        });
    });
});

它添加了一个额外的数组,允许您将类别名称映射到第二个 tic 值,从而为您提供您可能想要的更多“类别”视图。我还在底部添加了代码,在不同的列和图表的底线之间添加了垂直分界线。作为数学的一部分,我在此处以像素为单位硬编码可能需要对周围标签的大小等进行一些调整,但这应该是可行的。

使用“百分比”类型的重音可以让 y 刻度从原始数据中计算出总百分比,而如上所述,您需要对 x 轴进行自己的数学运算。我更多地依赖工具提示功能来提供标签等,而不是图表本身的标签。

这项工作的另一个重大改进是找到一种方法使工具提示悬停区域和标签集中并居中并包含栏本身,而不是现在每个栏的右边框。如果有人想添加它,请随时到这里。

于 2013-08-12T04:37:14.233 回答
0

如果我猜对了,您希望每个条形都具有不同的宽度。我遇到了同样的问题,并且很难找到提供此选项的库。我得出结论——没有。

无论如何,我玩了一下 highcharts,很有创意并想出了这个:
你提到你希望你的数据看起来像这样:data: [[5, 3.4], [3, 6], [4, 3.4]],第一个值是高度,第二个是宽度。

让我们使用 highcharts 的柱形图来实现。

第 1 步:
为了更好地区分条形图,将每个条形图输入为一个新系列。由于我动态生成数据,我必须动态分配新系列:

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;

这样,您的不同系列将如下所示:

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



第 2 步:
将其指定为 highcharts 的绘图选项:

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



第 3 步:
现在让我们发挥创意 - 要使所有条形图的起点相同,我们需要将每个条形图移动到图表的起点:

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



第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);
  });
}



第 4 步:
让我们到达 xAxis 的点。在第一个函数中修改已经存在的点,将最后一个点移动到轴的末端并隐藏其他点。在第二个函数中,我们克隆最后一个点,将其修改为总共有 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();
  }
}



最后,我们有一个看起来像这样的图表(不是这个给定示例中的数据,而是[[20, 0.005], [30, 0.013333333333333334], [20, 0.01], [30, 0.005555555555555555], [20, 0.006666666666666666]]第一个值是宽度,第二个值是高度): 在此处输入图像描述


可能需要进行一些修改以 100% 适合您的情况。Fe 我不得不将 xAxis 的点调整为特定的起点和终点——我省去了这部分。

于 2020-02-13T15:21:11.557 回答