js从对象中的值创建堆叠条形图

d3.js create stacked bar chart from values in object

本文关键字:创建 条形图 对象 js      更新时间:2023-09-26

下面的代码将在名为' data '的对象数组中创建单个值的条形图。如何使用收集的数据创建堆叠条形图?

设置页边距

 var w = 700;
 var    h = 500;
 var margin = {
    top: 58,
 bottom: 120,
    left: 60,
    right: 40
};
var width = w - margin.left - margin.right;
var height = h - margin.top - margin.bottom;

定义数据

 data =[
 { name: "Subway", carbs: "480", fat: "400", protein: "120", sum: "1000"}, 
 { name: "Steak & Potatos", carbs: "900", fat: "350", protein: "200", sum:    "1450"}, 
 { name: "Sausage", carbs: "50", fat: "350", protein: "80", sum: "480"} 
 ];

我希望条的高度是碳水化合物,脂肪,蛋白质的值的总和,但每个值都是不同的颜色。定义x

 var x = d3.scale.ordinal()
    .domain(data.map(function(e){
        return e.name;
    }))
    .rangeBands([0,width]);

定义y.这就是我想我需要帮助的地方

 var y = d3.scale.linear()
    .domain([0, d3.max(data, function(d,i){
        return parseInt(d.carbs) ;
    })])
    .range([height, 0]);

以上将给我一个单一值(碳水化合物)的酒吧。但我真正想做的是创建一个堆叠条形图。如有任何帮助,我将不胜感激。

在回复后添加"z是你的色阶,它将决定你的矩形看起来像什么"

 var z = d3.scale.ordinal()
.range(["#ff0", "#f00", "#0ff"])
.domain(["carbs", "fat", "protein"]);

这是绘制图表的plot函数

 function plot(params){
    this.append('g')
    .call(params.gridlines)
    .classed('gridline', true)
    .attr('transform','translate(0,0)');
    this.selectAll('bar')
    .data(params.data)
    .enter()
    .append('rect')
    .classed('bar', true)
    .attr('x', function(d,i){
        return x(d.name)
    })
    .attr('y',function(d,i){
        return y(d.carbs);
    })
    .attr('width', function(d){
        return x.rangeBand();
    })
    .attr('height', function(d,i){
        return height - y(d.carbs)
    })
    .style('fill',function(d,i){
        return ordinal_color_scale(i);
    });
this.selectAll('.bar_label')
        .data(params.data)
        .enter()
            .append('text')
            .classed('bar_label', true)
            .attr('x', function(d,i){
                return x(d.name) + (x.rangeBand()/2);
            })
            .attr('dx', 0)
            .attr('y', function(d,i){
                    return y(d.carbs);
                })
            .attr('dy', -6)
            .text(function(d){
                return d.carbs;
            });
        this.append('g')
            .classed('x axis', true)
            .style('fill', '#ffd000')
            .attr('transform','translate('+ 0 +','+ height +')')
            .call(params.axis.x)
                .selectAll('text')
                .style('text-anchor','end')
                .attr( 'dx', -8)
                .attr('dy',8)
                .attr('transform','translate(0,0) rotate(-45)');
        this.append('g')
            .classed('y axis', true)
            .style('fill', '#ffd000')
            .attr('transform','translate(0,0)')
            .call(params.axis.y);
}
plot.call(chart, {
    data: data,
    axis: {
        x: x_axis,
        y: y_axis
    },
    gridlines: y_gridlines
});

我不明白的是如何在图表上的条形图中绘制z变量

您的y域确实是这里的问题所在。这个范围需要考虑所有的变量,而不仅仅是碳水化合物。换句话说,你的max函数需要考虑所有属性的和。

var y = d3.scale.linear()
    .domain([0, d3.max(data, function(d,i){
        return parseInt(d.sum);
})])
.range([height, 0]);

这是因为,最终,你的条形图将与你所有属性的总和一样高(因为它是一个堆叠条形图)

当您实际绘制<rect>元素时,您将需要使用stack函数。每个条将包含3个<rect>元素(一个碳水化合物,脂肪和蛋白质堆叠在另一个之上)你没有发布任何代码,但它很可能看起来像:

// z is your color scale here which will decide what your rectangles look like
var z = d3.scaleOrdinal()
    .range(["#<colorForCarbs>", "#<colorForFat>", "#<colorForProtein>"])
    .domain(["carbs", "fat", "protein"]);
g.selectAll(".serie")
.data(stack.keys(["carbs", "fat", "protein"])(data))
.enter().append("g")
  .attr("class", "serie")
  .attr("fill", function(d) { return z(d.key); })
.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
  .attr(class, 'bar')
  .attr("x", function(d) { return x(d.data.name); })
  .attr("y", function(d) { return y(d[1]); })
  .attr("height", function(d) { return y(d[0]) - y(d[1]); })
  .attr("width", x.bandwidth());

示例中的"系列"是,例如,与"碳水化合物"相关的所有矩形(而不是包含碳水化合物,脂肪和蛋白质的3个矩形的堆栈)。

这个例子应该给你你需要的一切,如果你错过了什么:http://bl.ocks.org/mbostock/3886208

编辑

对于你更新的问题,这是你应该使用z刻度的代码部分

this.selectAll('bar')
    .data(params.data)
    .enter()
    .append('rect')
    .classed('bar', true)
    .attr('x', function(d,i){
        return x(d.name)
    })
    .attr('y',function(d,i){
        return y(d.carbs);
    })
    .attr('width', function(d){
        return x.rangeBand();
    })
    .attr('height', function(d,i){
        return height - y(d.carbs)
    })
    .style('fill',function(d,i){
        return ordinal_color_scale(i);
    });

请使用

var stack = d3.stack(); 
g.selectAll(".serie")
    .data(stack.keys(["carbs", "fat", "protein"])(data))
    .enter().append("g")
    .attr("class", "serie")
    .attr("fill", function(d) { return z(d.key); })
    .selectAll("rect")
       .data(function(d) { return d; })
       .enter()
       .append("rect")
           .attr("x", function(d) { return x(d.data.name); })
           .attr("y", function(d) { return y(d[1]); })
           .attr("height", function(d) { return y(d[0]) - y(d[1]); })
           .attr("width", x.rangeBand());