Question

I have data that looks something like this:

var data = {

     { name: Andrew,
       date: 12/08/07,
       alpha: 1.2,
       beta: 3.4
     },
     { name: Fred,
       date: 14/12/06,
       alpha: 1.7,
       beta: 2.8
     }
};

I want a bar graph with names on x-axis and each name having two bars: one for alpha and one for beta. All the examples that I came across have grouped bars within a category/format (eg. all bars representing dates etc.) and that's why their solutions aren't helping much. I have reached this far:

var x0 = d3.scale.ordinal()
            .rangeRoundBands([0, width], 0.2);

    var x1 = d3.scale.ordinal();

    var y = d3.scale.linear()
         .range([height, 0]);

    var color = d3.scale.ordinal()
            .range([ "#6b486b", "#ff8c00"]);

    var xAxis = d3.svg.axis()
            .scale(x0)
            .orient("bottom");

    var yAxis = d3.svg.axis()
            .scale(y)
            .orient("left")
            .tickFormat(d3.format(".2s"));

    var svg = d3.select("#punchcard").append("svg")
        .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
        .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var ageNames = ["Alpha", "Beta"];

    x0.domain(patient_names);
    x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()], 0);
    console.log(patientList);


    console.log(data);

    var alpha_max = d3.max(data, function(d) {return parseFloat(d.alpha); });
    var beta_max = d3.max(data, function(d) { return parseFloat(d.beta); });

    console.log(alpha_max);
    console.log(beta_max);
    var y_domain = [ alpha_max, beta_max];

    y.domain([0, parseFloat(d3.max(y_domain))+0.5]);

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

    svg.append("g")
    .attr("class", "y axis")
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", ".71em")
    .style("text-anchor", "end");

    svg.selectAll("bars")
        .data(data)
        .enter().append("rect")
        .attr("transform", function(d) { return "translate(" + x0(d.name)+",0)";})
        .style("fill", "#ff8c00")
        .attr("x", function(d) { return x1(d.alpha); })
        .attr("width", x1.rangeBand())      
        .attr("y", function(d) { return y(d.alpha); })
        .attr("height", function(d) { return height - y(d.alpha); });

    svg.selectAll("bars")
        .data(data)
        .enter().append("rect")
        .style("fill", "#6b486b")
        .attr("transform", function(d) { return "translate(" + x0(d.name)+",0)";})
        .attr("x", function(d) { return x1(d.beta); })
        .attr("width", x1.rangeBand())      
        .attr("y", function(d) { return y(d.beta); })
        .attr("height", function(d) { return height - y(d.beta); });


var legend = svg.selectAll(".legend")
      .data(ageNames.slice().reverse())
    .enter().append("g")
      .attr("class", "legend")
      .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });

  legend.append("rect")
      .attr("x", width - 18)
      .attr("width", 18)
      .attr("height", 18)
      .style("fill", color);

  legend.append("text")
      .attr("x", width - 24)
      .attr("y", 9)
      .attr("dy", ".35em")
      .style("text-anchor", "end")
      .text(function(d) { return d; });

This code stacks alpha and beta bars rather than besides each other. I have spent hours looking at various examples but still cannot figure out a way of doing this.

Thanks in advance !

Was it helpful?

Solution

You can create the nested array data structure, with one object for each variable, by using a mapping function in your second data-join.

You start by joining your groups to your array of data objects, then dynamically create the sub-array for each group by using a function in the nested data join:

var propertyNames = ["Alpha", "Beta"];

var groups = plottingArea.selectAll("g.groups")
                .data(data);

/* and handle the enter selection, classes, etc */

var bars = groups.selectAll("rect.bars")
                .data( function(d) {
                   //the `d` value is the data object for the *group*
                   //this function needs to return an array of data objects
                   //representing each bar in the group

                   return propertyNames.map( function(property){
                      //to get one bar for each variable, start with the
                      //array of variable names, and use a map function
                      //to create data objects for each:

                      return { type: property,
                               value: d[property],
                               name: d.name,
                               date: d.date
                             };

                   });

                });

The rest of the code should follow a standard grouped bar chart structure. The inner data objects you create should contain all the data you need to properly position and colour each bar.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top