gamehen
gamehen

Reputation: 324

Single Stacked Bar Graph Data Setup?

I'm trying to make a singular column for a bar graph in d3.js, the purpose of which is to bar-graph the coefficients of the other line graph in my program. I'm familiar with how they are made when the data is in .csv format, but in this case right now I'm trying to make it from three variables. The three variables are:

  var xtwo;
  var xone;
  var xzero;

which have values put into them in a later part. I've built a skeleton based on what I know and have seen, which is right here:

       //Bar Graph
        var barmargin = {
                top: 20,
                right: 20,
                bottom: 30,
                left: 60
            },
            barwidth = 500 - barmargin.left - barmargin.right,
            barheight = 350 - barmargin.top - barmargin.bottom;

        //X scale
        var barx = d3.scale.ordinal()
            .rangeRoundBands([0, barwidth], .1);

        //Y scale
        var bary = d3.scale.linear()
            .rangeRound([barheight, 0]);


        //bar graph colors
        var color = d3.scale.ordinal()
            .range(["#FF5C33", "#F48C00", "#FFFF5C"]);

        // Use X scale to set a bottom axis
        var barxAxis = d3.svg.axis()
            .scale(barx)
            .orient("bottom");

        // Same for y
        var baryAxis = d3.svg.axis()
            .scale(bary)
            .orient("left")
            .tickFormat(d3.format(".2s"));

        // Addchart to the #chart div
        var svg = d3.select("#chart").append("svg")
            .attr("width", barwidth + barmargin.left + barmargin.right)
            .attr("height", barheight + barmargin.top + barmargin.bottom)
            .append("g")
            .attr("transform", "translate(" + barmargin.left + "," + barmargin.top + ")");


        //Where data sorting happens normally
        var bardata.data([xzero, xone, xtwo]);


        //Y domain is from zero to 5
        y.domain([0, 5]);

        svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + barheight + ")")
            .call(barxAxis);

        svg.append("g")
            .attr("class", "y axis")
            .call(baryAxis);

        bardata.selectAll("rect")
            .data(function(d) {
                return d.types;
            })
            .enter().append("rect")
            .attr("width", barx.rangeBand())
            .attr("y", function(d) {
                return bary(d.y1);
            })
            .attr("height", function(d) {
                return bary(d.y0) - bary(d.y1);
            })
            .style("fill", function(d) {
                return color(d.name);
            });

but I can't really figure out how to make it work correctly. I thought that I could manually make the .data but it seems to not be working that way.

Full code if necessary: https://jsfiddle.net/tqj5maza/1/

Upvotes: 2

Views: 1289

Answers (1)

Godwhacker
Godwhacker

Reputation: 3922

Broadly speaking: you want to create three bars, sat on top of each other, from three different values. The three values will be enough to scale the bars, but they in themselves won't be enough to position the bars- each bar needs to be offset by the size of the bars that have gone before.

d3 can only read the values that are already in the data you send it- you can't really access the previous values as you go, as each datum is bound to a separate element. Thus, what you need to do is to create some new data, which has all the numbers required to display it.

Here's one way that you might do that:

var canvas = d3.select("#canvas").append("svg").attr({width: 400, height: 400})

var values = [50, 90, 30]

var colours = ['#FA0', '#0AF', '#AF0']

var data = []

var yOffset = 0

//Process the data

for(var i = 0; i < values.length; i++) {

    var datum = {

        value : values[i],
        colour : colours[i],
        x: 0,
        y: yOffset

    }

    yOffset += values[i] 

    data.push(datum)

}

var bars = canvas.selectAll('rect').data(data)

bars
    .enter()
    .append('rect')
    .attr({
        width : 30,
        height : function(d) {
            return d.value
        },
        y : function(d) {
            return d.y  // 
        }
    })
    .style({
        fill : function(d) {
            return d.colour
        }
    })

http://jsfiddle.net/r3sazt7m/

d3's layout functions all do more or less this- you pass them a set of data, and they return new data containing the values that the SVG drawing instructions require.

Upvotes: 3

Related Questions