League of Legends players by rank - a simple bar chart with D3.js

Sep 3, 2019

Still experimenting with D3.js, this time I wanted to make a simple bar chart. Since it’s always nice to show actual, informative data, I decided to reproduce the distribution of players in the different ranks in League of Legends as shown on this website: https://www.esportstales.com/league-of-legends/rank-distribution-percentage-of-players-by-tier.

Like last time, here is the result:

League of Legends: players by rank

Whenever I find the time, I’ll have to do this again in D3.js v4 or v5. Anyway, you probably already know how to extract the HTML and JavaScript code from this website but I’ll make it easier and post it below. Please excuse the vague and potentially incorrect comments, I’m still in the process of learning the D3.js framework.

<html>
  <head>
    <meta charset="utf-8">
    <title>League of Legends: players by rank</title>
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <style>
      body {
        font: 11px sans-serif;
      }
      .axis {
        font-size: 12px;
      }
      .axis path,
      .axis line {
        fill: none;
        stroke: #000;
        shape-rendering: crispEdges;
      }
      .dot {
        stroke: #000;
      }
      .tooltip {
        position: absolute;
        text-align: center;
        width: auto;
        height: auto;
        padding: 2px;
        background: white;
        border: 1px;
        border-radius: 2px;
        pointer-events: none;
      }
    </style>
  </head>
  <body>
    <div id="graphic"></div>
    <script>
      // define data
      var data = [
        {group: "Iron", rank: "Iron IV", percentage: 0.07},
        {group: "Iron", rank: "Iron III", percentage: 0.38},
        {group: "Iron", rank: "Iron II", percentage: 0.84},
        {group: "Iron", rank: "Iron I", percentage: 1.13},
        {group: "Bronze", rank: "Bronze IV", percentage: 2.84},
        {group: "Bronze", rank: "Bronze III", percentage: 3.23},
        {group: "Bronze", rank: "Bronze II", percentage: 4.38},
        {group: "Bronze", rank: "Bronze I", percentage: 6.09},
        {group: "Silver", rank: "Silver IV", percentage: 9.56},
        {group: "Silver", rank: "Silver III", percentage: 7.91},
        {group: "Silver", rank: "Silver II", percentage: 9.01},
        {group: "Silver", rank: "Silver I", percentage: 7.17},
        {group: "Gold", rank: "Gold IV", percentage: 12.52},
        {group: "Gold", rank: "Gold III", percentage: 7.31},
        {group: "Gold", rank: "Gold II", percentage: 6.31},
        {group: "Gold", rank: "Gold I", percentage: 3.95},
        {group: "Platinum", rank: "Platinum IV", percentage: 6.98},
        {group: "Platinum", rank: "Platinum III", percentage: 2.82},
        {group: "Platinum", rank: "Platinum II", percentage: 1.96},
        {group: "Platinum", rank: "Platinum I", percentage: 1.85},
        {group: "Diamond", rank: "Diamond IV", percentage: 2.23},
        {group: "Diamond", rank: "Diamond III", percentage: 0.77},
        {group: "Diamond", rank: "Diamond II", percentage: 0.37},
        {group: "Diamond", rank: "Diamond I", percentage: 0.21},
        {group: "Top", rank: "Master", percentage: 0.05},
        {group: "Top", rank: "GrandMaster", percentage: 0.04},
        {group: "Top", rank: "Challenger", percentage: 0.02}
      ];
      // define margins and size of plotting area
      var margin = {top: 20, right: 20, bottom: 80, left: 40},
          width = 960 - margin.left - margin.right,
          height = 500 - margin.top - margin.bottom;
      // define X and Y axes as well as the scales
      var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
      var y = d3.scale.linear().range([height, 0]);
      x.domain(data.map(function(d) { return d["rank"] }));
      y.domain([0, d3.max(data, function(d) { return d["percentage"]} )+1]);
      var xAxis = d3.svg.axis()
          .scale(x)
          .orient("bottom")
      var yAxis = d3.svg.axis()
          .scale(y)
          .orient("left")
          .ticks(10)
          .tickFormat( function(d) { return d + "%" } );
      // create plotting area
      var svg = d3.select("#graphic")
        .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 + ")");
      // create function which assign colors to tiers
      var color = d3.scale.ordinal()
        .domain(["Iron","Bronze","Silver","Gold","Platinum","Diamond","Top"])
        .range(["#3b3c40","#523233","#7f7f7f","#fed800","#e5e4e4","#9bc5db","#826f93"]);
      // create tooltip box
      var div = d3.select("body").append("div")
        .attr("class", "tooltip")
        .style("opacity", 0);
      // draw X axis
      svg.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + height + ")")
          .call(xAxis)
        .selectAll("text")
          .style("text-anchor", "end")
          .attr("dx", "-.8em")
          .attr("dy", "0.5em")
          .attr("transform", "rotate(-45)" );
      // draw Y axis
      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("Percentage of players");
      // draw bars
      svg.selectAll("bar")
          .data(data)
        .enter().append("rect")
          .attr("x", function(d) { return x(d["rank"]); })
          .attr("width", x.rangeBand())
          .attr("y", function(d) { return y(d["percentage"]); })
          .attr("height", function(d) { return height - y(d["percentage"]); })
          .style("fill", function(d) { return color(d["group"]); })
          .style("stroke", "black")
          .style("stroke-width", 0.5)
          .on("mouseover", function(d) {
            div.transition()
                .duration(200)
                .style("opacity", .9);
            div.html(d["rank"] + ": " + d["percentage"] + "%")
                .style("left", (d3.event.pageX) + "px")
                .style("top", (d3.event.pageY - 28) + "px");
          })
          .on("mouseout", function(d) {
              div.transition()
                .duration(500)
                .style("opacity", 0);
          });
    </script>
  </body>
</html>