简体   繁体   中英

D3JS Barchart : How to allow repeated x-axis label values?

Here is the JSFiddle

please look at the function drawBarchart();

Note: in my example when xData values are renamed and made unique all 4 bars are shown, but omitted when values are same, i know this is expected behavior but i have to allow repeated values.Please help..

code:

$(document).ready(function(){
   var dataArray = [
                {
                    "xData" : "Repeat",
                    "yData" : 38
                },
                {
                    "xData" : "Unique",
                    "yData" : 27
                },
                {
                    "xData" : "Repeat",
                    "yData" : 27
                },
                {
                    "xData" : "Repeat",
                    "yData" : 29
                }  ];
drawBarchart("graph",dataArray,"count",700,400);
}
);


function drawBarchart(containerId, dataArray, yAxisText, chartAreaWidth,
        chartAreaHeight) {  
    var margin = {
        top : 20,
        right : 20,
        bottom : 30,
        left : 40
    }, width = chartAreaWidth - margin.left - margin.right, height = chartAreaHeight
            - margin.top - margin.bottom;

    var formatPercent = d3.format(".0%");

    var x = d3.scale.ordinal().rangeRoundBands([ 0, width ], .1);

    var y = d3.scale.linear().range([ height, 0 ]);

    var xAxis = d3.svg.axis().scale(x).orient("bottom");

    //var yAxis = d3.svg.axis().scale(y).orient("left").tickFormat(formatPercent);
    var yAxis = d3.svg.axis().scale(y).orient("left");

    var svg = d3.select("#" + containerId).append("svg").attr("width",
            width + margin.left + margin.right).attr("height",
            height + margin.top + margin.bottom).append("g").attr("transform",
            "translate(" + margin.left + "," + margin.top + ")");

    x.domain(dataArray.map(function(d) {
        return d.xData;
    }));
    y.domain([ 0, d3.max(dataArray, function(d) {
        return d.yData;
    }) ]);

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

    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").text(yAxisText);

    svg.selectAll(".bar").data(dataArray).enter().append("rect")
            .attr("class", "bar").attr("x", function(d) {
                return x(d.xData);
            }).attr("width", x.rangeBand()).attr("y", function(d) {
                return y(d.yData);
            }).attr("height", function(d) {
                return height - y(d.yData);
            });

    function type(d) {
        d.yData = +d.yData;
        return d;
    }
}    

You can do this by not using a scale for the x axis. The point of a scale is to map input values to outputs, ie the same inputs will give you the same outputs. Given that this is not what you want in this case, you don't need a scale.

You can calculate the position of each bar based on the index within the data:

.attr("x", function(d, i) {
    return i * width/dataArray.length;
})

The width of each bar can be calculated in a similar fashion. Same thing for the text labels, which you have to add manually. Complete jsfiddle here .

You MUST use unique values on an scale because it will "map" those values. Nevertheless we will modify the text on the ticks and make your graph to appear that it has repeated values.

add the following above the x scale definition(var x =...) :

// Rewrite xData and prepend index -> xData: "Repeat0"
dataArray = dataArray.map(function(d,i){d.xData = d.xData +i; return d});

// Remove the index from the ticks ->  xData: "Repeat0" -> "Repeat"
var adjustTicks = function(){
   var xaxisgroup = this.node();
   var ticks = xaxisgroup.children;
   for (var i = 0; i < ticks.length; i++) {
       if(ticks[i].localName == 'path'){continue; }

       var tick_text = d3.select(ticks[i].children[1]);
       tick_text.text(tick_text.text().substring(0, tick_text.text().length - 1))

   };
}

Then,. when you are actually drawing the scale invoke the call method passing adjustTicks as argument, like this :

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

What it does is create a scale using unique values but replaces the text on the scale so it appears that repeated values are being used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM