答案 0 :(得分:1)
是的,这是可能的!
与大多数可视化一样,该过程是确定图表结构,然后确定如何将数据放入该结构的过程之一。在这种情况下,我认为最简单形式的数据看起来像这样......
let groups = [
{ name:'one', values:[1,3,6,2] },
{ name:'two', values:[3,5,7,3,2,5] },
{ name:'three', values:[9,2,5] },
{ name:'four', values:[6] }
];
一组组,其中每个组都有一些属性,包括要表示为单个条形的一组值。
棘手的一点是计算出每个组和每个条沿水平轴的位置。我的想法是这样的:如果我们说每个条形的宽度为 1 个单位,那么我们希望在组之间有多少空间?也许一个半格,所以 1.5 个单位。现在,每个组将占用的空间等于其中的柱数(values
数组的长度),图表所需的总宽度将是这些值加上它们之间的空间的总和。
即
let dataWidth = d3.sum(groups, d=>d.values.length) + (groups.length-1) * groupPadding;
我们还想遍历组并计算出它们的“起始位置”,即按照条形单位将组水平放置的位置,如下所示:
let groupPadding = 1.5;
let currentWidth = 0;
groups = groups.map(group=>{
group.width = group.values.length;
group.startPosition = currentWidth;
currentWidth += group.width+groupPadding;
return group;
});
接下来我们需要使用 d3-scale 制作 x 和 y 尺度。
对于 y 尺度,让我们保持简单并硬编码最大值
const yScale = d3.scaleLinear()
.domain([0,10])
.range([chartHeight, 0]); // chart height is just your charts height in pixels
对于 x 比例,我们使用上面计算的 dataWidth
作为域的最大值,我们将使用此比例将条形单位转换为屏幕像素
const xScale = d3.scaleLinear()
.domain([0, barWidth)
.range([0, chartWidth]); //chartWidth, the width of your chart in pixels
好的。现在我们有了绘制图表所需的一切知识。我所看到的图表结构所设想的......
groups 中的每个 group 都是一个 svg g
元素,根据其 startPosition
定位。这些 g
元素中的每一个都包含一组 rect
元素,每个值一个。在 g
元素中,您可能还想放置诸如组标签之类的内容。
大致上看起来像这样...
创建群组
const barGroups = chart.selectAll('g.bar-group')
.data(groups)
.enter()
.append('g')
.classed('bar-group', true)
.attr('transform', group=>`translate(${xScale(group.startPosition)}, 0)`);
添加矩形
barGroups.each(function(group){
const barGroup = d3.select(this);
barGroup.selectAll('rect')
.data(group.values)
.enter()
.append('rect')
.attr('width', xScale(1))
.attr('height', value => yScale(value))
.attr('x', (value, i) => xScale(i))
.attr('y', value => chartHeight - yScale(value));
这是一个将所有内容放在一起并填补空白以提供工作示例的块:Grouped Bars