D3js - change Vertical bar chart to Horizontal bar chart

32,470

Solution 1

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())

Solution 2

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)");

Solution 3

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

Share:
32,470
EnigmaRM
Author by

EnigmaRM

I've focused my learning to front-end technologies. AngularJS, D3.js, jQuery, and AJAX.

Updated on June 05, 2020

Comments

  • EnigmaRM
    EnigmaRM almost 4 years

    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])
        ;
    
  • Chandrakant Thakkar
    Chandrakant Thakkar almost 7 years
    You can also refer this gist.github.com/ChandrakantThakkarDigiCorp/… It contains horizontal bar chart with tooltips and legend ,also it is responsible in mobile