d3.js根据对象中的值创建堆积条形图 [英] d3.js create stacked bar chart from values in object

查看:74
本文介绍了d3.js根据对象中的值创建堆积条形图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码将在称为数据的对象数组中创建单个值的条形图。如何使用数据集合创建堆积条形图?

The below code will create a bar chart of a single value within the array of objects called ‘data’. How can I use the collection of data to create a stacked bar chart?

设置边距

 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

I want the height of the bar to be the sum of the values for carbs, fat, protein, but with each value to be of a different color. define x

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

定义y。这是我认为我需要帮助的地方

define y. This is where I think I need help

 var y = d3.scale.linear()
    .domain([0, d3.max(data, function(d,i){

        return parseInt(d.carbs) ;
    })])
    .range([height, 0]);

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

The above will give me a bar with a single value (carbs). But what I really want to do is to create a stacked bar chart. Any help will be greatly appreciated.

在下面发布的答案后添加'z是你的颜色标度,这将决定你的矩形看起来像'

Added after below posted answer 'z is your color scale here which will decide what your rectangles look like'

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

这是绘制图表的情节函数

This is the plot function which draws the chart

 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变量。

What I don't understand is how to draw the z variable in the bars on the chart.

推荐答案

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

Your domain for y is indeed what's wrong here. The range needs take all the variables into account, not just carbs. In other words, your max function needs to consider the sum of all properties.

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

这是因为,最终,您的酒吧将与您所有酒店的总和一样高(因为它是一个堆积的条形图)

This is because, in the end, your bars will be as high as the sum of all your properties (since it's a stacked bar graph)

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

You will then need to use the stack function when you actually draw your <rect> elements. Each bar will contain 3 <rect> elements (one for carbs, fat and protein stacked one on top of the other) You didn't post any code for that but it will most likely look like :

// 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());

示例中的serie是所有与碳水化合物相关的矩形(相对于包含碳水化合物,脂肪和蛋白质的3个矩形的堆栈)。

A "serie" in the example is, for example, all the rectangles that are related to "carbs" (as opposed to a stack that would contain the 3 rectangles for carbs, fat and protein).

如果您遗漏了某些内容,此示例应该为您提供所需的一切: http://bl.ocks.org/mbostock/3886208

This example should give you everything you need if you are missing something : http://bl.ocks.org/mbostock/3886208

编辑

根据您更新的问题,这是您应该使用z的代码部分比例

With your updated question, this is the section of the code where you should be using the z scale

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());

这篇关于d3.js根据对象中的值创建堆积条形图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆