How to make an NBA game player rotation graph

How to make an NBA game player rotation timeline graph using the NBA API and Apexcharts.

NBA game rotation graph
NBA player game rotation graph

CodePen example here

Getting the rotation data

The NBA API endpoint for a games player rotation:

https://stats.nba.com/stats/gamerotation?GameID=0022100604

This example uses the game id from the CLE @ GWS game.

To fetch this data you will need to do a GET request with cURL including a user agent and HTTP referrer.

Making sense and formatting

The data is in typical NBA API format which is nested arrays with headers telling you what each index represents.

An example is the first entry which represents 1 rotation:

[
    "0022100604",
    1610612739,
    "Cleveland",
    "Cavaliers",
    200765,
    "Rajon",
    "Rondo",
    4780,
    10970,
    null,
    null,
    0
]

The keys are:

[
    "GAME_ID",
    "TEAM_ID",
    "TEAM_CITY",
    "TEAM_NAME",
    "PERSON_ID",
    "PLAYER_FIRST",
    "PLAYER_LAST",
    "IN_TIME_REAL",
    "OUT_TIME_REAL",
    "PLAYER_PTS",
    "PT_DIFF",
    "USG_PCT"
]

Note Each team gets its own index (see in the full PHP example below), the points and usage percentage are never filled.

You can piece a lot of it together without the keys. The game id, team id, team location, team name, player id, the player first and last name.

The next two values are the in time and out time. These two values carry an extra 0 digit so to get this value as a pure seconds divide by 10.

4780 / 10 = 478
10970 / 10 = 1097

To get these two-game times in seconds as a string in minutes and seconds format using PHP:

gmdate("i:s", $seconds);

This makes the above values

07:58 in
18:17 out

Now to create the date-time strings for the graph. As it’s a true timeline and will not work with the minutes:seconds strings above they must be converted into Unix time.

Unix time is the number of seconds elapsed since Unix Epoch.

Here is the actual date doesn’t matter…

strtotime("2000-01-01 00:{$row1['in_string']}");//works
strtotime("2015-02-08 00:{$row1['in_string']}");//works too

Only the time (minutes and seconds) matter because the graph will be formatting the x-axis ticks to only show minutes anyway.

strtotime() creates a Unix format timestamp.

Getting the players name from the data uses the 5th and 6th indexes. Here it is formatted to be the first letter of the first name with a “.” and then the last name:

$player = substr($p[5], 0, 1).'.'.$p[6];

Build an array for each rotation, with the colour. The colour will get changed for teams.

$team1[] = array('x' => $player, 'y' => [$in_string, $out_string], 'fillColor' => '#008FFB');

This as an output example is:

{
  "x": "R.Rondo",
  "y": [
    946645678,
    946646297
  ],
  "fillColor": "#008FFB"
},

Players name, in time as Unix, out time as Unix and then the colour for the bar. This format is what the timeline graph uses.

The full PHP code to generate the graph data:

<?php
$data = json_decode(file_get_contents("theRotationFile.json"), true);

$team1 = $team2 = array();

foreach ($data['resultSets'][0]['rowSet'] as $p) {//visit team
    $in_time_string = gmdate("i:s", ($p[7] / 10));
    $out_time_string = gmdate("i:s", ($p[8] / 10));

    $player = substr($p[5], 0, 1) . '.' . $p[6];

    $in_string = strtotime("2000-01-01 00:{$in_time_string}");
    $out_string = strtotime("2000-01-01 00:{$out_time_string}");

    $team1[] = array('x' => $player, 'y' => [$in_string, $out_string], 'fillColor' => '#008FFB');
}
foreach ($data['resultSets'][1]['rowSet'] as $p) {//home team
    $in_time_string = gmdate("i:s", ($p[7] / 10));
    $out_time_string = gmdate("i:s", ($p[8] / 10));

    $player = substr($p[5], 0, 1) . '.' . $p[6];

    $in_string = strtotime("2000-01-01 00:{$in_time_string}");
    $out_string = strtotime("2000-01-01 00:{$out_time_string}");

    $team2[] = array('x' => $player, 'y' => [$in_string, $out_string], 'fillColor' => '#00E396');
}

$rotation_graph = array_merge($team1, $team2);//Output for graph

The timeline graph

Output this graph data with the timeline graph config, this also includes a DateTime formatter for minutes and seconds only along with min and max ticks simulating a regular length NBA game (48 minutes):

let options = {
    series: [
        {
            data: <?= json_encode($rotation_graph) ?>
        }
    ],
    chart: {
        height: 420,
        width: 850,
        type: 'rangeBar'
    },
    plotOptions: {
        bar: {
            horizontal: true
        }
    }, tooltip: {
        enabled: true,
        x: {
            show: true,
            formatter: function (value, timestamp) {
                function format_time(s) {
                    return new Date(s * 1e3).toISOString().slice(-10, -5);
                }

                let date = new Date(value);
                if (date instanceof Date && !isNaN(date.valueOf())) {
                    return format_time(value);
                }
            }
        }
    },
    xaxis: {
        min: '946645200',//00:00:00
        max: '946648080',//00:48:00
        tickAmount: 12,
        type: 'datetime',
        labels: {
            formatter: function (value, timestamp) {
                function format_time(s) {
                    return new Date(s * 1e3).toISOString().slice(-10, -8);
                }

                return format_time(value) + "m";
            }
        }
    }
};

let chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();

The last part is to set the chart HTML div

<div id="chart" style="min-height: 480px;"></div>