d3如何制作单个堆积柱形图
d3 how to make single stacked column chart
我正在尝试让 d3 绘制单个堆叠条形图,如下所示:
<svg width = '500' height= '100'>
<rect x='0' y='0' width='224' height='30' fill='green'/>
<rect x='224' y='0' width='84' height='30' fill='blue'/>
<rect x='308' y='0' width='29' height='30' fill='darkgray'/>
<rect x='337' y='0' width='3' height='30' fill='#606060'/>
</svg>
如您所见,x 位置从零开始,然后每个后续 x 位置等于前面宽度的总和。
所以我试图让 d3 从名为 datavars 的数组中绘制类似的东西:
var datavars = [224, 84, 29, 3];
... 并确保 d3 将正确的宽度值分配给正确的 x 值,我创建了这些变量:
var prev_width0 = 0;
var prev_width1 = datavars[0];
var prev_width2 = datavars[0] + datavars[1];
var prev_width3 = datavars[0] + datavars[1] + datavars[2];
... 并像这样定义 x 值:
//create SVG element
var svg = d3.select('body')
.append('svg')
.attr('width', w)
.attr('height', h);
svg.selectAll('rect')
.data(datavars)
.enter()
.append('rect')
.attr('width', function(d){
return d;})
.attr('x',function(d, i){
return 'prev_width'+i; })
.attr('y',0)
.attr('height', 30);
正如您可能已经猜到的那样,强缩进函数(基于前面宽度的总和,并在 prev_width
变量中定义)returns 每次迭代一个字符串(prev_width0、prev_width1 等)和 不是 我认为我在创建 prev_width
变量时定义的值。
我显然错误地定义了变量。知道我该如何正确地做到这一点吗?
JavaScript 不会将字符串 "datavars1"
解释为变量 datavars1
。要将字符串解释为 JavaScript 变量,您可以使用 eval()
。因此,将:return 'prev_width'+i; })
更改为 return eval('prev_width'+i); })
。尽管更好的主意可能是使用数组代替,例如:
var prev_width = [0,
datavars[0],
datavars[0] + datavars[1],
datavars[0] + datavars[1] + datavars[2]
];
...
.attr('x',function(d, i){
return prev_width[i]; })
您可以对颜色做类似的事情:
var colors = ['green','blue','darkgray','#606060'];
...
.attr('fill', function(d, i){ return colors[i]; })
您还可以创建单个对象数组来存储颜色、宽度等
一个更具可扩展性的想法是摆脱数组 prev_width
并拥有一个可以将总和计算为一个点的函数。如:
function sum(array, start, end) {
var total = 0;
for(var i=start; i<end; i++) total += array[i];
return total;
}
那么你可以这样做:
...
.attr('x',function(d, i){
return sum(datavars, 0, i); })
这是一个片段(我的做法略有不同)
//this function deals with pairing finding x for each width in the array and add them to a new array called x_and_width_values
//example :[[0,224],[84,224],[29,308],[3,337]]
// ^ ^ ^ ^ ^ ^ ^ ^
// x width x width .............
function combinations(prev,current,index,arr){
// This method focus on accummulating results by reference previous and current element
//for the first and second element we need specifically add this
if(index==1){
x_and_width_values.push([arr[index-1],0]);
x_and_width_values.push([arr[index],prev])
}
//other elements we use index as follows;
else{
x_and_width_values.push([arr[index],prev])
}
return prev+current
}
//after creating an array with all [x,width] combination, we map it to colors to get out final array
//example :[[[0,224],'green'],[[84,224],'blue'],[29,308],[[3,337],'darkgray']
function colors_with_combination(e, i) {
return [x_and_width_values[i], colors[i]];
}
//*******************acutal beef og code***************
var x_and_width_values=[];
//this link is needed to creation of svg elements
var link="http://www.w3.org/2000/svg"
//all your widths
var all_widths=[224,84,29,3];
//all your colors
var colors=['green','blue','darkgray','#606060'];
//sort your width array to be on the safe side
all_widths.sort(function(a,b){return b-a});
//find all width and x combination
all_widths.reduce(combinations);
//map width and x values to color values
var all = x_and_width_values.map(colors_with_combination);
//create a loop for object creation
for(var i=0;i<all.length;++i){
var rect=document.createElementNS(link,'rect');
rect.setAttributeNS(null,'x',all[i][0][1])
rect.setAttributeNS(null,'width',all[i][0][0]);
rect.setAttributeNS(null,'fill',all[i][1]);
rect.setAttributeNS(null,'height','30');
rect.setAttributeNS(null,'y','0');
document.getElementById('svg').appendChild(rect);;
}
<svg id='svg' width = '500' height= '100'>
</svg>
我正在尝试让 d3 绘制单个堆叠条形图,如下所示:
<svg width = '500' height= '100'>
<rect x='0' y='0' width='224' height='30' fill='green'/>
<rect x='224' y='0' width='84' height='30' fill='blue'/>
<rect x='308' y='0' width='29' height='30' fill='darkgray'/>
<rect x='337' y='0' width='3' height='30' fill='#606060'/>
</svg>
如您所见,x 位置从零开始,然后每个后续 x 位置等于前面宽度的总和。
所以我试图让 d3 从名为 datavars 的数组中绘制类似的东西:
var datavars = [224, 84, 29, 3];
... 并确保 d3 将正确的宽度值分配给正确的 x 值,我创建了这些变量:
var prev_width0 = 0;
var prev_width1 = datavars[0];
var prev_width2 = datavars[0] + datavars[1];
var prev_width3 = datavars[0] + datavars[1] + datavars[2];
... 并像这样定义 x 值:
//create SVG element
var svg = d3.select('body')
.append('svg')
.attr('width', w)
.attr('height', h);
svg.selectAll('rect')
.data(datavars)
.enter()
.append('rect')
.attr('width', function(d){
return d;})
.attr('x',function(d, i){
return 'prev_width'+i; })
.attr('y',0)
.attr('height', 30);
正如您可能已经猜到的那样,强缩进函数(基于前面宽度的总和,并在 prev_width
变量中定义)returns 每次迭代一个字符串(prev_width0、prev_width1 等)和 不是 我认为我在创建 prev_width
变量时定义的值。
我显然错误地定义了变量。知道我该如何正确地做到这一点吗?
JavaScript 不会将字符串 "datavars1"
解释为变量 datavars1
。要将字符串解释为 JavaScript 变量,您可以使用 eval()
。因此,将:return 'prev_width'+i; })
更改为 return eval('prev_width'+i); })
。尽管更好的主意可能是使用数组代替,例如:
var prev_width = [0,
datavars[0],
datavars[0] + datavars[1],
datavars[0] + datavars[1] + datavars[2]
];
...
.attr('x',function(d, i){
return prev_width[i]; })
您可以对颜色做类似的事情:
var colors = ['green','blue','darkgray','#606060'];
...
.attr('fill', function(d, i){ return colors[i]; })
您还可以创建单个对象数组来存储颜色、宽度等
一个更具可扩展性的想法是摆脱数组 prev_width
并拥有一个可以将总和计算为一个点的函数。如:
function sum(array, start, end) {
var total = 0;
for(var i=start; i<end; i++) total += array[i];
return total;
}
那么你可以这样做:
...
.attr('x',function(d, i){
return sum(datavars, 0, i); })
这是一个片段(我的做法略有不同)
//this function deals with pairing finding x for each width in the array and add them to a new array called x_and_width_values
//example :[[0,224],[84,224],[29,308],[3,337]]
// ^ ^ ^ ^ ^ ^ ^ ^
// x width x width .............
function combinations(prev,current,index,arr){
// This method focus on accummulating results by reference previous and current element
//for the first and second element we need specifically add this
if(index==1){
x_and_width_values.push([arr[index-1],0]);
x_and_width_values.push([arr[index],prev])
}
//other elements we use index as follows;
else{
x_and_width_values.push([arr[index],prev])
}
return prev+current
}
//after creating an array with all [x,width] combination, we map it to colors to get out final array
//example :[[[0,224],'green'],[[84,224],'blue'],[29,308],[[3,337],'darkgray']
function colors_with_combination(e, i) {
return [x_and_width_values[i], colors[i]];
}
//*******************acutal beef og code***************
var x_and_width_values=[];
//this link is needed to creation of svg elements
var link="http://www.w3.org/2000/svg"
//all your widths
var all_widths=[224,84,29,3];
//all your colors
var colors=['green','blue','darkgray','#606060'];
//sort your width array to be on the safe side
all_widths.sort(function(a,b){return b-a});
//find all width and x combination
all_widths.reduce(combinations);
//map width and x values to color values
var all = x_and_width_values.map(colors_with_combination);
//create a loop for object creation
for(var i=0;i<all.length;++i){
var rect=document.createElementNS(link,'rect');
rect.setAttributeNS(null,'x',all[i][0][1])
rect.setAttributeNS(null,'width',all[i][0][0]);
rect.setAttributeNS(null,'fill',all[i][1]);
rect.setAttributeNS(null,'height','30');
rect.setAttributeNS(null,'y','0');
document.getElementById('svg').appendChild(rect);;
}
<svg id='svg' width = '500' height= '100'>
</svg>