ValarMorghulis
ValarMorghulis

Reputation: 83

Unable to handle negative values on d3 bar chart

I am trying to create a bar chart in d3.I am somewhat able to do it.

Here is my code :

columns=[];
wid=300;
div="chart1";
hgt=200;
columns.push("Carrier");
measureArray=[];
measureArray.push("Weight");
data=JSON.parse('[{"Carrier":"AAA","Weight":"370521.1140920751"},{"Carrier":"BBB","Weight":"283158.83174940513"},{"Carrier":"CCC","Weight":"268412.846944693"},{"Carrier":"DDD","Weight":"249936.88014410512"},{"Carrier":"EEE","Weight":"235395.1033872669"},{"Carrier":"FFF","Weight":"194363.0"},{"Carrier":"GGG","Weight":"181281.13981602874"},{"Carrier":"HHH","Weight":"158635.0"},{"Carrier":"III","Weight":"148570.47194245495"},{"Carrier":"JJJ","Weight":"123718.89288302396"},{"Carrier":"KKK","Weight":"117170.0"},{"Carrier":"LLL","Weight":"102159.0"}]');
var customTicks = 5;
var color = d3.scale.category10();
var divWid=wid-30;
var chartData=JSON.parse('{"chart1":{"viewBys":["Carrier"],"viewIds":["81392"],"dimensions":["81392"],"aggregation":["COUNTDISTINCT"],"meassures":["Weight"],"meassureIds":["111016"],"filters":{"81392":["KUEHNE & NAGEL (KHNN)"]},"size":"S","records":"12","chartType":"Vertical-Bar","viewByLevel":"single","others":"N","othersL":"N","globalEnable":"Y","row":"1","col":"1","size_x":"19","size_y":"9","id":"divchart1"}}');

var divHgt=hgt;
var dashletid=div;
var colIds= [];
colIds = chartData[div]["viewIds"];

if(typeof chartData[div]["lbPosition"]=='undefined' || chartData[div]["lbPosition"]==='top'){
    hgt -=25;
}
var chartMap = {};
var measure1 = measureArray[0];
var minVal = 0;
if(typeof chartData[div]["yaxisrange"]!="undefined" && chartData[div]["yaxisrange"]!="" && chartData[div]["yaxisrange"]["axisTicks"]!="undefined" && chartData[div]["yaxisrange"]["axisTicks"]!="" && (typeof parent.$("#drills").val()=="undefined" || parent.$("#drills").val()=="" )) {
    customTicks = chartData[div]["yaxisrange"]["axisTicks"];
}
var autoRounding1;

autoRounding1 = "1d";

var fun="";
hasTouch = /android|iphone|ipad/i.test(navigator.userAgent.toLowerCase());
if(hasTouch){
    fun="";
}else{
    fun = "drillWithinchart(this.id,\""+div+"\")";
}

function drillFunct(id1){
    drillWithinchart(id1,div);
}

var margin = { top: 10, right: 12,  bottom: 30, left: 70 };
if(typeof chartData[div]["displayY"]!="undefined" && chartData[div]["displayY"]!="" && chartData[div]["displayY"]!="Yes"){
    margin = { top: 10, right: 12,  bottom: 30, left: 20 }; 
}else{
    margin = { top: 10, right: 12,  bottom: 30, left: 70 }; 
}

var width = divWid;
var height = 0;
if(typeof chartData[div]["displayX"]!="undefined" && chartData[div]["displayX"]!="" && chartData[div]["displayX"]!="Yes"){
    height = divHgt*.78 ; //- margin.top - margin.bottom
}else{
    height = divHgt *.73; //- margin.top - margin.bottom

}  //end condition by mayank sh. for hidden white space


var barPadding = 4;
var range="";
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], 0.1, range);
var y = d3.scale.linear()
.range([height, 0]);
var measArr = [];
if(typeof chartData[div]["displayYLine"]!="undefined" && chartData[div]["displayYLine"]!="" && chartData[div]["displayYLine"]!="Yes"){
    make_x_axis = function() {
        return d3.svg.gridaxis()
        .scale(x)
        .orient("bottom")
        .ticks(5)
    }


    make_y_axis = function() {
        return d3.svg.gridaxis()
        .scale(y)
        .orient("left")
        .ticks(customTicks)
    }
}else{
    make_x_axis = function() {
        return d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .ticks(5)
    }

    make_y_axis = function() {
        return d3.svg.axis()
        .scale(y)
        .orient("left")
        .ticks(customTicks)
    }
}
if(typeof chartData[div]["displayXLine"]!="undefined" && chartData[div]["displayXLine"]!="" && chartData[div]["displayXLine"]!="Yes"){
    var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");
}else{
    var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");
}
var    yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(function(d) {
    return d;
});

yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(customTicks)
.tickFormat(function(d, i) {
    return d;
});
var yAxis1 = d3.svg.axis()
.scale(y)
.tickFormat(function(d, i) {
    measArr.push(d);
    return "";
});
var offset=0;        
if(typeof chartData[div]["lbPosition"]=='undefined' || chartData[div]["lbPosition"]==='top'){
    offset=25;
}        
var svg = d3.select("#" + dashletid)
.append("svg")
.attr("id", "svg_" + dashletid)
.attr("viewBox", "0 0 "+(width + margin.left + margin.right)+" "+(height + margin.top + margin.bottom+65)+" ")
.append("g")
.attr("transform", "translate(" + margin.left + "," + 10 + ")");

var gradient = svg.append("svg:defs").selectAll("linearGradient").data(data).enter()
.append("svg:linearGradient")
.attr("id", function(d) {
})
.attr("x1", "0%")
.attr("y1", "30%")
.attr("x2", "50%")
.attr("y2", "30%")
.attr("spreadMethod", "pad")
.attr("gradientTransform", "rotate(0)");
colorMap = {};
gradient.append("svg:stop")
.attr("offset", "0%")
.attr("stop-color", function(d, i) {
    var colorShad;
    return colorShad="steelblue";
})
.attr("stop-opacity", 1);
gradient.append("svg:stop")
.attr("offset", "9%")
.attr("stop-color", "rgb(240,240,240)")
.attr("stop-opacity", 1);
gradient.append("svg:stop")
.attr("offset", "80%")
.attr("stop-color", function(d, i) {
    var colorShad;
})
.attr("stop-opacity", 1);
x.domain(data.map(function(d) {
    return d[columns[0]];
}));


var max = 0;
if(typeof chartData[div]["yaxisrange"]!="undefined"&& chartData[div]["yaxisrange"]!="") {

    if(chartData[div]["yaxisrange"]["YaxisRangeType"]!="MinMax" && chartData[div]["yaxisrange"]["YaxisRangeType"]!="Default" && typeof chartData[div]["yaxisrange"]["axisMax"]!="undefined" && chartData[div]["yaxisrange"]["axisMax"]!="" && (typeof parent.$("#drills").val()=="undefined" || parent.$("#drills").val()=="" ) ) {
        max = parseFloat(chartData[div]["yaxisrange"]["axisMax"]);
    }else{
        max = maximumValue(data, measure1);
    }}else{
    max = maximumValue(data, measure1);
}
if(typeof chartData[div]["yaxisrange"]!="undefined" && chartData[div]["yaxisrange"]!="") {
    if(chartData[div]["yaxisrange"]["YaxisRangeType"]!="MinMax" && chartData[div]["yaxisrange"]["YaxisRangeType"]!="Default" && typeof chartData[div]["yaxisrange"]["axisMin"]!="undefined" && chartData[div]["yaxisrange"]["axisMin"]!="" && (typeof parent.$("#drills").val()=="undefined" || parent.$("#drills").val()=="" ) ) {
        minVal = parseFloat(chartData[div]["yaxisrange"]["axisMin"]);
    }else if(chartData[div]["yaxisrange"]["YaxisRangeType"]=="Default" ){
        minVal = 0;
    }else{
        if (data.length > 1) {
            minVal = minimumValue(data, measure1) * .8;
        }}
}else{
    if (data.length > 1) {
        minVal = minimumValue(data, measure1) * .8;
    }else{
        minVal = 0;
    }
}

y.domain([parseFloat(minVal), parseFloat(max)]);
if(typeof chartData[div]["GridLines"]!="undefined" && chartData[div]["GridLines"]!="" && chartData[div]["GridLines"]!="Yes"){}else{
    svg.append("g")
    .attr("class", "grid11")
    .call(make_y_axis()
    .tickSize(-width, 0, 0)
    .tickFormat("")
)
}
if(typeof chartData[div]["displayX"]!="undefined" && chartData[div]["displayX"]!="" && chartData[div]["displayX"]!="Yes"){}else{
    svg.append("g")
    .attr("class", ".x axis")
    .attr("transform", "translate(0," + (height*1) + ")")
    .call(xAxis)
    .selectAll('text')
    .attr('x',function(d,i){  // add by mayank sharma
       return 0;
    })
    .attr('y',function(d,i){
       return 5;
    })
    .text(function(d,i) {
        return d;
    })
    .attr('transform',function(d,i){
        if(typeof chartData[div]["legendPrintType"]!="undefined" && chartData[div]["legendPrintType"]!="" && chartData[div]["legendPrintType"]=== "Alternate") {
            return  "";
        }else if (chartData[div]["legendPrintType"] === "Horizontal") {
            return  "";
        }else if (chartData[div]["legendPrintType"] === "Vertical") {
            return "rotate(-85)";
        }else {
            return "rotate(-35)";
        }
    })
    .style('text-anchor',function(d,i){
        if(typeof chartData[div]["legendPrintType"]!="undefined" && chartData[div]["legendPrintType"]!="" && chartData[div]["legendPrintType"]=== "Alternate") {
            return  "middle";
        }else if(chartData[div]["legendPrintType"] === "Horizontal"){
            return  "middle";
        }else if (chartData[div]["legendPrintType"] === "Vertical") {
            return "end";
        }else {
            return "end";
        }
    })
    .append("svg:title")
    .text(function(d) {
        return d;
    })
    .style("font-size","11px");
}
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").style("font-size","11px");
barRadius=0;
var bars=svg.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bar")
.append("rect");
bars.attr("rx", barRadius)
.attr("fill", function(d,i) {
    return "blue";
})
.attr("color_value", function(d,i){
    return "blue";
})
.attr("index_value", function(d, i) {
    return "index-" + d[columns[0]].replace(/[^a-zA-Z0-9]/g, '', 'gi');
})
.attr("class", function(d, i) {
    return "bars-Bubble-index-" + d[columns[0]].replace(/[^a-zA-Z0-9]/g, '', 'gi')+div;
})
.attr("id", function(d) {
    return d[columns[0]] + ":" + d[measure1];
})
.attr("onclick", fun)
.attr("x", function(d) {
    return x(d[columns[0]]);
})
.attr("width",0)
.transition()
.duration(2000)//1 second
.attr("width", x.rangeBand())
.attr("y", function(d) {
    return y(d[measure1]);
})
.attr("height", function(d) {
    return height - y(d[measure1]);
});

var sum = d3.sum(data, function(d) {
    return d[measureArray[0]];
});


function maximumValue(data, measure) {
    var max;
    for (var j = 0; j < data.length; j++) {

        if (j === 0) {
            max = data[j][measure];
        } else {
            if (max < parseFloat(data[j][measure])) {
                max = data[j][measure];
            }
        }
    }
    return max;
}
function minimumValue(data, measure) {
    var min;
    try {
        for (var k = 0; k < data.length; k++) {
            if (k === 0) {
                min = data[k][measure];
            } else {
                if (min > parseFloat(data[k][measure])) {
                    min = data[k][measure];
                }
            }
        }
    } catch (e) {
    }
    return min;
}

Running example is here

In this case all the values I am showing happen to be positive. But this is not the case all the time.Some times there are negative values too.

But when negative values come, my chart cant seem to handle them. From the research i have done over past few days I have come to know that I need to do some tweaks in the scaling of the chart. Reference : handle negative values

But as I am very new to d3 I am not able to do it.

Same Example with negative values. As you would clearly see that negative are not shown correctly.

With negative values my chart should somewhat look like follows enter image description here

Means in case of negative value the bar should start from x axis(as usual) and stretch down to bottom depending on values.

Can anyone help me out on this. I'll be very thankful :) Some explanation will be very much appreciated.

Upvotes: 2

Views: 2363

Answers (1)

Cyril Cherian
Cyril Cherian

Reputation: 32327

For that you can make the middle line like this:

   svg.append("line")
    .attr("x1",-6)
    .attr("y1",y(0))//so that the line passes through the y 0
    .attr("x2",width)
    .attr("y2",y(0))//so that the line passes through the y 0
    .style("stroke", "black");

For negative lines the y of the bar will be y(0)

Something like this

    .attr("y", function(d) {
        if(y(0) > y(d[measure1]))
            return y(d[measure1]);
        else
          return y(0);
    })

For height you take the absolute of Math.abs(y(0) - y(d[measure1])):

   .attr("height", function(d) {
        return Math.abs(y(0) - y(d[measure1]));
    });

For making the x axis to the bottom give it y translate of its height.

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

Working code here

Upvotes: 2

Related Questions