0

I need help adding a second series of data to my bar chart. Currently I'm populating the bars from the glob key in my dataset. This will be the first series. The second series I would like to be is local. How do I go about adding that?

Play with my JSFiddle here.

var w = 300;
var h = 200;

var colors = ["#377EB8", "#4DAF4A"];

var dataset = [
            {"keyword": "payday loans", "glob": 1500000, "local": 673000, "cpc": "14.11"},
            {"keyword": "title loans", "glob": 165000, "local": 165000, "cpc": "12.53" },
            {"keyword": "personal loans", "glob": 550000, "local": 301000, "cpc": "6.14"}
        ];

var data = [[1500000, 165000, 550000],
        [673000, 165000, 301000]];

var tdata = d3.transpose(dataset.glob, dataset.local);

var series = 2; // Global & Local

var x0Scale = d3.scale.ordinal()
            .domain(d3.range(dataset.length))
            .rangeRoundBands([0, w], 0.05); 
var x1Scale = d3.scale.ordinal()
            .domain(d3.range(dataset.length))
            .rangeRoundBands([0, w], 0.05);

var yScale = d3.scale.linear()
            .domain([0, d3.max(dataset, function(d) {return d.glob;})]) 
            .range([0, h]);

var glob = function(d) {
 return d.glob;
};
var cpc = function(d) {
 return d.cpc;
};

var commaFormat = d3.format(',');

//SVG element
var svg = d3.select("#searchVolume")
        .append("svg")
        .attr("width", w)
        .attr("height", h);     

// Graph Bars
svg.selectAll("rect") 
.data(dataset, cpc, glob) 
.enter()
.append("rect")
.attr("x", function(d, i){
    return x0Scale(i);
})
.attr("y", function(d) {
    return h - yScale(d.glob);
})
.attr("width", x0Scale.rangeBand())
.attr("height", function(d) {
    return yScale(d.glob); 
})
.attr("fill", colors[1])
.on("mouseover", function(d) {
    //Get this bar's x/y values, then augment for the tooltip
    var xPosition = parseFloat(d3.select(this).attr("x")) + x0Scale.rangeBand() / 3;
    var yPosition = parseFloat(d3.select(this).attr("y")) + yScale;

    //Update Tooltip Position & value
    d3.select("#tooltip")
        .style("left", xPosition + "px")
        .style("top", yPosition + "px")
        .select("#cpcVal")
        .text(d.cpc);
    d3.select("#tooltip").classed("hidden", false);
})
.on("mouseout", function() {
    //Remove the tooltip
    d3.select("#tooltip").classed("hidden", true);
}); 

//Create labels
svg.selectAll("text")
   .data(dataset, glob)
   .enter()
.append("text")
.text(function(d) {
    return commaFormat(d.glob);
})
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
    return x0Scale(i) + x0Scale.rangeBand() / 2;
})
.attr("y", function(d) {
    return h - yScale(d.glob) + 14;
})
.attr("font-family", "sans-serif") 
.attr("font-size", "11px")
.attr("fill", "white");
EnigmaRM
  • 7,523
  • 11
  • 46
  • 72
  • Have you looked at this grouped bar chart example: http://bl.ocks.org/mbostock/3887051 – Andrew Staroscik Apr 22 '13 at 23:59
  • I had looked at that. However they are getting their data from a CSV, and I struggle understanding things when I'm using a different data source – EnigmaRM Apr 23 '13 at 17:47
  • I struggled with data handling when I first started with d3. This exchange with Mike Bostock helped alot: http://stackoverflow.com/questions/11672438 The specific details of the case are not as important as the observation that he wasted no time trying to work with data structure I gave him. He went right to transforming it into a structure that was easier for d3 to use. With mapping, for loops and the array.forEach function there are abundant resources available to get data into an approachable structure prior to creating the joins in d3. – Andrew Staroscik Apr 23 '13 at 22:58

1 Answers1

4

It's easiest to create an svg group (<g>) element for each set of data, and then add the individual parts to each group. For example, roughly:

http://jsfiddle.net/WXMwv/1/

var sets = svg.selectAll(".set") 
    .data(dataset) 
    .enter().append("g")
            .attr("class","set")
     .attr("transform",function(d,i){
         return "translate(" + x0Scale(i) + ",0)"
     })
    .on("mouseover", function(d,i) {
        //Create x value from data index
        var xPosition = parseFloat(x0Scale(i) + x0Scale.rangeBand() / 6);
        var yPosition = 0;
        //Update Tooltip Position & value
        d3.select("#tooltip")
            .style("left", xPosition + "px")
            .style("top", yPosition + "px")
            .select("#cpcVal")
            .text(d.cpc);
        d3.select("#tooltip").classed("hidden", false);
    })
    .on("mouseout", function() {
        //Remove the tooltip
        d3.select("#tooltip").classed("hidden", true);
    }); 

sets.append("rect")
    .attr("class","glob")
    .attr("width", x0Scale.rangeBand()/2)
    .attr("y", function(d) {
        return yScale(d.glob);
    })
    .attr("height", function(d){
        return h - yScale(d.glob);
    })
    .attr("fill", colors[1])

sets.append("rect")
    .attr("class","local")
    .attr("width", x0Scale.rangeBand()/2)
    .attr("y", function(d) {
        return yScale(d.local);
    })
    .attr("x", x0Scale.rangeBand()/2)
    .attr("height", function(d){
        return h - yScale(d.local);
    })
    .attr("fill", colors[0])

The text elements are left as an exercise for the reader :)

minikomi
  • 8,363
  • 3
  • 44
  • 51
  • I added the text to `sets.append("rect")`. Inspecting the element with Firebug, I can see that the correct text has been bound to the correct bar, but it doesn't appear on the screen. Do you know why this would be? – EnigmaRM Apr 23 '13 at 18:01
  • Add them to the sets in the same way : http://jsfiddle.net/WXMwv/3/. You need to add the svg as you wish to layer it - bottom first, then on top. – minikomi Apr 23 '13 at 22:59