Subrata Sarkar
Subrata Sarkar

Reputation: 3064

D3 v4: charting tool: How to send horizontal gridlines behind columns

I am drawing a chart using D3 charting tool. The problem is I cannot send the horizontal gridlines behind the columns. Please see the screenshot.

enter image description here

This approach here does send the gridlines behind the bars but at the same time, all the column labels get disappeared! Please see the screenshot below:

enter image description here

CODE

public function evd_unitary_growth_plan_chart( $data_str ){
        ob_start(); ?>

        <style> /* set the CSS */

            .line {
                fill: none;
                stroke: steelblue;
                stroke-width: 2px;
            }

            .grid line {
                stroke: lightgrey;
                stroke-opacity: 0.6;
                shape-rendering: crispEdges;
            }

            .grid path {
                stroke-width: 0;
            }

            .axis {
                font-size: 13px;
                font-family: 'Roboto';
                color: #394041;
            }

        </style>

        <script type="text/javascript">
            var h = 300;
            var w = 750;
            var barPadding = 2;

            function barColor(data_month, current_month) {
                if( parseInt(data_month) >= current_month)
                    return "#008600";
                else
                    return "#c4c4c4";
            }

            // set the dimensions and margins of the graph
            var margin = {top: 30, right: 20, bottom: 30, left: 40},
                width = w - margin.left - margin.right,
                height = h - margin.top - margin.bottom;

            var data = <?php echo $data_str ?>;

            // set the ranges
            var x = d3.scaleBand().range([0, width]).padding(0.2);
            var y = d3.scaleLinear().range([height, 0]);

            var svg = d3.select("#ecbg_unitary").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 + ")");

            // Scale the range of the data in the domains
            x.domain(data.map(function(d) { return d.month; }));

            var y_domain_upperBound = d3.max(data, function(d) { return d.points; });
            y_domain_upperBound = Math.round(y_domain_upperBound / 10) * 10 + 10;
            y.domain([0, y_domain_upperBound]);

            // Create Y-Axis tick array to draw grid lines
            var yTicks = [];
            var tickInterval = 5;
            for(var i = 0; i <= y_domain_upperBound; i = i + 5) {
                yTicks.push(i);
            }

            // gridlines in y axis function
            function draw_yAxis_gridlines() {
                return d3.axisLeft(y)
                    .tickValues(yTicks);
            }

            // append the rectangles for the bar chart
            svg.selectAll("rect")
                .data(data)
                .enter().append("rect")
                .attr("x", function(d) {
                    return x(d.month);
                })
                .attr("width", x.bandwidth())
                .attr("y", function(d) { return y(d.points); })
                .attr("height", function(d) { return height - y(d.points); })
                .attr("fill", function(d){return barColor(d.data_month_number, d.current_month_number)});



            // column labels
            svg.selectAll("text")
                .data(data)
                .enter()
                .append("text")
                .text(function(d) {
                    return d.points;
                })
                .attr("text-anchor", "middle")
                .attr("x", function(d, i) {
                    return x(d.month) + x.bandwidth() / 2;
                })
                .attr("y", function(d) {
                    return y(d.points) - 10;
                })
                .attr("font-family", "Roboto")
                .attr("font-size", "13px")
                .attr("font-weight", "bold")
                .attr("fill", "#394041");

            // add the x Axis
            svg.append("g")
                .attr("class", "axis")
                .attr("transform", "translate(0," + height + ")")
                .call(d3.axisBottom(x));


            // add the Y gridlines
            svg.append("g")
                .attr("class", "grid axis")
                .call(draw_yAxis_gridlines()
                    .tickSize(-width)
                );

        </script>

        <?php return ob_get_clean();
    }

Upvotes: 1

Views: 960

Answers (1)

Tim Hirst
Tim Hirst

Reputation: 614

JDunken is right, the order in which you draw things will determine what sits on top of what, so you want to do the horizontal lines before the rectangles to make them appear behind the rectangles.

If that's then messing up your labels, it's probably related to one of the points I made in your other post about not using just a "text" selection for your column labels.

Remember that when you add axes on to your <svg> these axes typically include <text> elements, so when you later call svg.selectAll("text") ready to bind for your column labels, there's a good chance that this selection is picking up some <text> elements in your axes, with unpredictable results! svg.selectAll("text") will do just that - select all the <text> elements in svg.

You can instead select on a class that you reserve for your column labels with something like:

svg.selectAll(".column-label")
                .data(data)
                .enter()
                .append("text")
                .attr("class","column-label")

Hope that helps

Upvotes: 3

Related Questions