Animated Bar Graphs

In recent times there has been a surge in animated bar graphs visualization. They are mainly used to show how certain events changed overtime. At Hepta Analytics, we used them to showcase how the premier league table changed over time during the just completed season. I will work you through how you can do it on your own.

Prerequisites

  • D3.js

First you will create the page using HTML and CSS.

NB: I am not good with design. So anyone looking for something pretty, this is where you lower your expectation. The goal here is to get something that works.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>bars</title>
</head>

<body>
        <div class="wrapper">
                <center><p><h4 class="chart-title">Week  <span class="week"></span> </h4></p>
                  <p><h4><span class="ole"></span></h4></p>
                </center>
                <div class="chart"></div>
                
                <p class="source">
                  <span >Title Battle Premier League 2018/2019</span>
                  <div class="item" >
                      <img src="favicon.ico"/>
                      <span class="caption">@heptanalytics</span>
                  </div>
                </p>
                
              </div>
              <script src="https://d3js.org/d3.v4.min.js"></script>
              <script src="https://d3js.org/d3-scale.v3.min.js"></script>
    </body>
</html>

Now we are going to load the data which is in csv format.

d3.csv("datafull.csv", function(d) {
      return {
        games : d.games,
        position : d.position,
        teamname : d.teamname,
        points : d.points
      };
    },function(data) {
// all the logic goes here
});

The above code loads data with particular columns. The resulting selection is what will be parsed to the function for logic. You can change name of the column to whatever you want. Next we are going to select all the matches in the first matchday. Then we sort the teams .

function sortData(data) {
      data.sort(function(a,b) {
        return b.points - a.points;
      });
    }

const lastMatch = 38;
let startMatch = 1;
var filtereddata = data.filter(function(d) { return d.games == startMatch.toString(); });
var selectedData = filtereddata.sort(function(a,b) {  return b.points - a.points;});

After that, we need to draw the bar graph for the first match day. The x-axis will have points, y axis will have the team names. The drawBars() is where you will need to make changes if you want to alter the look and feel of the bars. You can change the color with the fill function. You can also change the width and height of the bars.

function drawBars(el, data, t) {
      let barsG = el.select('.bars-g');
      if (barsG.empty()) {
        barsG = el.append('g')
        .attr('class', 'bars-g');
      }
      
      const bars = barsG
      .selectAll('.bar')
      .data(data, yAccessor);
      bars.exit()
      .remove();
      bars.enter()
      .append('rect')
      
      
      .attr('x', leftPadding)
      .merge(bars).transition(t)
      .attr('y', d => yScale(yAccessor(d)))
      .attr("fill", function(d) {
              
        return "#000";
        
        
      })
      .attr('width', d => xScale(xAccessor(d)))
      .attr('height', yScale.bandwidth())
      
      .delay(delay);
    
    }
function drawXAxis(el) {
      el.append('g')
      .attr('class', 'axis axis--x')
      .attr('transform', `translate(${leftPadding},${height})`)
      .call(d3.axisBottom(xScale));
    }
    
 function drawYAxis(el, data, t) {
      let axis = el.select('.axis--y');
      if (axis.empty()) {
        axis = el.append('g')
        .attr('class', 'axis axis--y');
      }

const yScale = d3.scaleBand()
    .rangeRound([0, height], 0.1)
    .padding(0.1);

yScale.domain(geoAreas);
drawXAxis(svg, selectedData.points);  
drawYAxis(svg, selectedData.teamname);
drawBars(svg, selectedData);

This will work for only on match. If you want to animate throughout the season, we need to have a loop that will keep changing the match day. This will continue until the last day of the season. The code below does that.

const interval = d3.interval(() => {
          const t = d3.transition().duration(400);
          
          startMatch += 1;
          filtereddata = data.filter(function(d) { return d.games == startYear.toString(); });
          selectedData = filtereddata.sort(function(a,b) {  return b.points - a.points;});
          
          d3.select('.week').text(startMatch.toString());

          
          
          yScale.domain(selectedData.map(yAccessor));
          drawYAxis(svg, selectedData, t);
          drawBars(svg, selectedData, t);
          
          if (startMatch === lastMatch) {
            interval.stop();
          }
        }, 1000);

This will give you the animation of the teams throughout the season. If you want to make certain events notable, you will alter the drawBars() by adding a class attribute. If you want to change the color of the This can be seen it the fill attribute. Below is the code to do that.

.attr('class', d => d.games === '18' ? 'bar wld' : 'bar') //when the matchday is 18

.attr("fill", function(d) {
        if (d.teamname=='Liverpool' ){
          
          return 'Red';
        }else if (d.teamname=='Man City'){
          return '#3182bd';
        }
        
        else  {
          return "#000";
        } 
        
      })

The above code will customize the bar colors of the Liverpool and Man City.

After completing the code, the final result should be as below:

To improve this, one can use logos instead of names and add the total points next to the bars. Cannot wait to see you all being creative. The full code and data can be found on my github account https://github.com/yvonnegitau/Animated-Bar-Graphs