milheiros
milheiros

Reputation: 619

d3 show labels only for ticks with data in a bar chart

First, I'm new with D3. :) I have a stacked bar chart. My y axis is a ordinal scale (state). In my data, I could have total=0 for some ticks. So, I just want to see the labels when the total > 0 but maintain all the ticks of the data.

var data = [{ "state":"A", "total":"10"},
{ "state":"B", "total":"0"},
{ "state":"C", "total":"0"},
{ "state":"D", "total":"20"},
{ "state":"E", "total":"0"},
{ "state":"F", "total":"50"}]

I've tried this code, but this remove all the ticks with total = 0. I just want to remove the label of that tick.

yAxis.tickValues(dataSet.map( function(d,i) 
    { 
        if (d.total > 0)
            return d.state; 
        else
            if(i % 4 === 0 ) return d.state; 
    })
    .filter(function (d) 
    { return !!d; } )); 

Thanks, Filipe

UPDATE Here is the code:

    <!DOCTYPE html>

    <html xmlns="http://www.w3.org/1999/xhtml" class="ocks-org do-not-copy">
    <head>
      <link rel="stylesheet" type="text/css" href="style.css" />
    </head>
    <body>
    <div id="timeLine"></div>
    <!--style>

    svg {
            font: 10px sans-serif;
        }

    path {
        fill: steelblue;
    }

    .axis path,
    .axis line {
        fill: none;
        stroke: #000;
        shape-rendering: crispEdges;
    }
</style-->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var timeline;
var labels;


    var margin = {
        top : 20,
        right : 10,
        bottom : 60,
        left : 80
    },
    width = 500 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

    var x = d3.scale.linear()
        .rangeRound([0, width]);

        var y = d3.scale.ordinal()
        .rangeBands([height, 0], 0.1);

    var color = d3.scale.ordinal()
        .range(["#1f77b4", "#2ca02c", "#E53524"]);
    //var color = d3.scale.category10()

    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .tickFormat(d3.format(".2s"))
        .ticks(10);

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

    timeline = d3.select("#timeLine").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 + ")")

    var dataSet;
    var all_nodes_t;
    var all_updates_t;
    var test;
    var entity = "ALL";

    dataSet = [
    { "Date":"2014-01", "insert":"27", "remove":"17","updates":"427"},
    { "Date":"2014-02", "insert":"27", "remove":"17","updates":"427"},
    { "Date":"2014-03", "insert":"27", "remove":"17","updates":"427"},
    { "Date":"2014-04", "insert":"0", "remove":"0","updates":"0"},
    { "Date":"2014-05", "insert":"27", "remove":"17","updates":"427"},
    ];
        color.domain(d3.keys(dataSet[0]).filter(function (key) {
            return key !== "Date";
        }));

    dataSet.forEach(function (d) {
        var x0 = 0;
        d.ages = color.domain().map(function (name) {
                return {
                    name : name,
                    x0 : x0,
                    x1 : x0 += +d[name]
                };
            });
        d.total = d.ages[d.ages.length - 1].x1;
    });

    //HERE
    yAxis.tickFormat(dataSet.map(function(d) { 
        d.total == 0 ? "" : d.Date; 
    }));

    y.domain(dataSet.map(function (d) {
        return d.Date;
    }));

    x.domain([0, d3.max(dataSet, function (d) {
        return (d.total + 5);
    })]);

    timeline.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis)
    .append("text")
    .attr("x", 1)
    .attr("dx", "42em")
    .attr("dy", "3em")
    .style("text-anchor", "end")
    .text("Operations");

    timeline.append("g")
    .attr("class", "y axis")
    .call(yAxis);

    var layer = timeline.selectAll(".state")
        .data(dataSet)
        .enter().append("g")
        .attr("class", "rect")
        .attr("transform", function (d) {
            return "translate(0," + y(d.Date) + ")";
        });

    var rect = layer.selectAll("rect")
        .data(function (d) {
            return d.ages;
        })
        .enter().append("rect")
        .attr("class", "rect")
        .attr("width", 0)
        .attr("x", width)
        .attr('y', function (d, i) {
                return y(d.Date);
            })
        .attr("height", y.rangeBand())
        .style("fill", function (d) {
            return color(d.name);
        });

    rect.transition()
    .duration(600)
    .delay(function (d, i) {
        return i * 300;
    })
    .attr("width", function (d) {
        return x(d.x1) - x(d.x0);
    })
    .attr("x", function (d) {
        return x(d.x0);
    });

</script>
</body>
</html>

Upvotes: 3

Views: 6189

Answers (1)

Lars Kotthoff
Lars Kotthoff

Reputation: 109232

You can use .tickFormat() to suppress the labels for those particular values. As the thing you want to check isn't part of the data that's available to the scale, you'll need to find it in your entire data:

yAxis.tickFormat(function(d) {
    var val = 0;
    dataSet.forEach(function(item) {
        if(item.Date == d) val = item.total;
    });
    return val == 0 ? "" : d;
});

This will suppress the label (return "") if the total is 0 or the value can't be found in the data set. Complete demo here.

Upvotes: 4

Related Questions