metalhead696
metalhead696

Reputation: 345

Using D3 to make double horizontal line graph

I just starting out with D3 and need to make a horizontal bar chart using csv file. The data is to compare the pay of men and women in different US states. Each state needs to have two touching bars (one for men's and one for women's pay). The CSV file has the header row State,Women,Men, with each row below having the name of each state and the appropriate data.

Here's what I've done so far.

var margin = { top: 20, right: 10, bottom: 100, left: 40 },
    width = 700 - margin.right - margin.left,
    height = 500 - margin.top - margin.bottom;

var svg = d3.select('body')
    .append('svg')
    .attr ({ 
    "width" : width + margin.right + margin.left,
    "height" : height + margin.top + margin.bottom
})

    .append('g')
        .attr("transform", "translate(" + margin.left + ',' + margin.right + ')');

var xScale = d3.scale.ordinal()
     .rangeRoundBands([height,0], 0.2, 0.2);

var yScale = d3.scale.linear()
    .range([0, width]);

var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("left");

var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient("bottom");

d3.csv("state-women-men.csv", function(error, data) {
    if(error) console.log("Error, data not loaded");

    data.forEach(function(d) {
        d.Women = +d.Women;
        d.Men = +d.Men;
        d.State = d.State;
        console.log(d.Men);
        console.log(d.Women);
    });

    xScale.domain(data.map(function(d) { return d.State;}) );
    yScale.domain([0, d3.max(data,function (d) { return d.Women; }) ] );

    svg.selectAll('rect')
        .data(data)
        .enter()
        .append('rect')
        .attr ({
            "x": function(d) { return xScale(d.State); },
            "y": function(d) { return yScale(d.Women); },
            "height": xScale.rangeBand(),
            "width": function(d) { return (width - xScale(d.State)); }
        });

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

    svg.append("g")
        .attr("class", "y axis")
        .attr("transform", "translate(0," + height +")")
        .call(yAxis);
});

To start out with, I'm only using the women's data, I'll figure out how to put the men's in later. The bigger problem right now is the formatting; as you can see in the picture, the bars are way to close together and too far to the bottom of the screen and the bars start at the right of screen instead of the left. Can anyone point me to the reasons in my code that cause the graph to look like this, as well as give me advice on adding the second bars, as well as color to the bars? Thanks.

Picture of graph: enter image description here

Upvotes: 0

Views: 193

Answers (1)

JSBob
JSBob

Reputation: 1046

Looks like the main problem is that your rect attributes are mixed up. Try using the following, you will have much better results:

svg.selectAll('rect')
    .data(data)
    .enter()
    .append('rect')
    .attr ({
        "x": 0,
        "y": function(d) { return xScale(d.State); },
        "height": xScale.rangeBand(),
        "width": function(d) { return (yScale(d.Women)); }
});

Reasoning:

  • x value should be fixed at zero so it lines up with the axis
  • y value should be based off your xScale and State property. Kind of confusing since your scale names are flipped
  • width should simply be the x axis (yScale) using the Women property.

Upvotes: 1

Related Questions