D3js - change Vertical bar chart to Horizontal bar chart

I have a vertical bar chart that is grouped in pairs. I was trying to play around with how to flip it horizontally. In my case, the keywords would appear on the y axis, and the scale would appear on the x-axis.

I tried switching various x/y variables, but that of course just produced funky results. Which areas of my code do I need to focus on in order to switch it from vertical bars to horizontal ones?

My JSFiddle: Full Code

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

// ternary operator to determine if global or local has a larger scale
var yScale = d3.scale.linear()
    .domain([0, d3.max(dataset, function (d) {
    return (d.local > d.global) ? d.local : d.global;
})])
    .range([h, 0]);

var xAxis = d3.svg.axis()
    .scale(xScale)
    .tickFormat(function (d) {
        return dataset[d].keyword;
    })
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient("left")
    .ticks(5);

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

//SVG element
var svg = d3.select("#searchVolume")
    .append("svg")
    .attr("width", w + margin.left + margin.right)
    .attr("height", h + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// Graph Bars
var sets = svg.selectAll(".set")
    .data(dataset)
    .enter()
    .append("g")
    .attr("class", "set")
    .attr("transform", function (d, i) {
        return "translate(" + xScale(i) + ",0)";
    });

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

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

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

Answers:

Answer

I just did the same thing last night, and I basically ended up rewriting the code as it was quicker than fixing all the bugs but here's the tips I can give you.

The biggest issues with flipping the x and y axis will be with things like return h - yScale(d.global) because height is calculated from the "top" of the page not the bottom.

Another key thing to remember is that when you set .attr("x", ..) make sure you set it to 0 (plus any padding for the left side) so = .attr("x", 0)"

I used this tutorial to help me think about my own code in terms of horizontal bars instead - it really helped

http://hdnrnzk.me/2012/07/04/creating-a-bar-graph-using-d3js/

here's my own code making it horizontal if it helps:

var w = 600;
var h = 600;
var padding = 30;

var xScale = d3.scale.linear()
        .domain([0, d3.max(dataset, function(d){
                                return d.values[0]; })]) //note I'm using an array here to grab the value hence the [0]
        .range([padding, w - (padding*2)]);

        var yScale = d3.scale.ordinal()
            .domain(d3.range(dataset.length))
            .rangeRoundBands([padding, h- padding], 0.05);

        var svg = d3.select("body")
            .append("svg")
            .attr("width", w)
            .attr("height", h)

        svg.selectAll("rect")
            .data(dataset)
            .enter()
            .append("rect")
            .attr("x", 0 + padding)
            .attr("y", function(d, i){
            return yScale(i);
            })
            .attr("width", function(d) {
                return xScale(d.values[0]);
            })
            .attr("height", yScale.rangeBand())
Answer

An alternative is to rotate the chart (see this). This is a bit hacky as then you need to maintain the swapped axes in your head (the height is actually the width etc), but it is arguably simpler if you already have a working vertical chart.

An example of rotating the chart is below. You might need to rotate the text as well to make it nice.

_chart.select('g').attr("transform","rotate(90 200 200)");
Answer

Here is the procedure I use in this case:

1) Inverse all Xs and Ys

2) Remember that the 0 for y is on top, thus you will have to inverse lots of values as previous values for y will be inversed (you don't want your x axis to go from left to right) and the new y axis will be inversed too.

3) Make sure the bars display correctly

4) Adapt legends if there are problems

This question may help in the sense that it shows how to go from horizontal bar charts to vertical: d3.js histogram with positive and negative values

Answer

Another Interesting Horizontal Graph NVD3 which I found useful. Give it a Try.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.