Revisions: /
URL: http://bbinsomnia.info
Date: 2016-11-17

VISUALIZATIONS OF MINUTES DISTRIBUTION

Distribution of Minutes in ABA League Season 2015-16

Miha Peče

Following previous calculations of average starter and bench players playing time, I will proceed with visualizations. Knowing league and teams average minutes for starters and bench players can help us achieve a bit more telling insight. For instance — as I mentioned before — you can get more structured overview of teams' rosters, or you can even detect specific season goals or strategies.

What we would like to put on chart? One option is that we compare team's minutes distribution with general, average numbers. I will draw charts for every team, with addition of one player example (it's impractical to include charts of all players in the league).

I think these visualizations are effective and quick way to estimate oponnets. Also, worth to mention because you measure average minutes per game, there are outliers at the end of line, as some players didn't play in all games. To visualize this issue, you could make similar chart, but with total minutes instead of averages per game.

I will use 2015-16 season ABA League dataset.

In [1]:
import sqlite3
import pandas as pd
import numpy as np
import texttable as tt

%matplotlib inline
import matplotlib.pyplot as plt
In [2]:
conn = sqlite3.connect('../sql/aba_liga2015.sqlite')
plt.style.use('ggplot')
In [3]:
sql_pd = "SELECT NAME, MP, TM, STARTER, POSITION FROM scr_game_players WHERE ROUND='regular' AND MP<>0"
df_main = pd.read_sql(sql_pd, conn)

Calculating average palying minutes for particular player ...

In [4]:
tmp_means = df_main.groupby("NAME").mean()
tmp_means = tmp_means.drop(["STARTER"], axis=1)
df_means = df_main.join(tmp_means, on='NAME',  rsuffix='_mean')
In [5]:
fig1 = df_means[df_means["NAME"] == "Lešić Sava"].copy()
fig1["LG_ST_AVG"] = 24.28

plt.figure()
plt.subplot(111)
#(start, end, #ofticks)
x_pos = np.linspace(1,len(fig1),len(fig1),endpoint=True)

plt.plot(x_pos, fig1["MP"], 'ro', label='Min./game')
plt.plot(x_pos, fig1["MP_mean"], 'y-', label='Player average')
plt.plot(x_pos, fig1["LG_ST_AVG"], 'b-', label='League starter average')

xlabels =[('Game '+ str(x)) for x in list(range(1, len(fig1)+1))]
plt.xticks(x_pos, xlabels, rotation=90)

# Set y limits (start, end)
plt.ylim(0, fig1["MP"].max()*1.1)

plt.title('Lešić Sava min. distribution')
plt.legend(loc=9, ncol=2,prop={'size':8})
plt.ylabel("Minutes")
plt.xlabel('# games')

plt.show()

Here we see rather steady distribution, which is quite normal for 1st player of the team. Important remark: last game in season had 4 overtimes.

For teams, I will first visualize two teams in parallel.

In [6]:
# First chart data
fig2 = df_main[df_main["TM"] == "Union Olimpija"]
fig2 = fig2.groupby("NAME").mean()
fig2.drop(fig2.index[[0]])
fig2 = fig2.sort_values('MP', ascending=False)
fig2["LG_ST_AVG"] = 24.28
fig2["LG_BN_AVG"] = 14.56
# 2nd chart data
fig3 = df_main[df_main["TM"] == "Cibona"]
fig3 = fig3.groupby("NAME").mean()
fig3.drop(fig3.index[[0]])
fig3 = fig3.sort_values('MP', ascending=False)
fig3["LG_ST_AVG"] = 24.28
fig3["LG_BN_AVG"] = 14.56

plt.figure(figsize=(14,4), dpi=80)
plt.subplot(121)

x_pos = np.arange(len(fig2))
Y1ch1 = fig2['MP']
Y2ch1 = fig2["LG_ST_AVG"]
Y3ch1 = fig2["LG_BN_AVG"]

plt.bar(x_pos, Y1ch1, facecolor='red', align="center")
# Average line: Starters
plt.plot(x_pos, Y2ch1, 'b-', label='Average lg. starter min.')
# Average line: Bench
plt.plot(x_pos, Y3ch1, 'g-', label='Average lg. bench min.')

xlabels1 = fig2.index

plt.xticks(x_pos, xlabels1, rotation=90)
plt.ylim(0, 35)

plt.title('Union Olimpija min. distribution')
plt.legend(loc=9, ncol=2,prop={'size':8})
plt.ylabel("Minutes")

#Let's be efficient aand add 2nd chart in a row
plt.subplot(122)

x_pos2 = np.arange(len(fig3))
Y1ch2 = fig3['MP']
Y2ch2 = fig3["LG_ST_AVG"]
Y3ch2 = fig3["LG_BN_AVG"]

plt.bar(x_pos2, Y1ch2, facecolor='red')
# Average line: Starters
plt.plot(x_pos2, Y2ch2, 'b-', label='Average lg. starter min.')
# Average line: Bench
plt.plot(x_pos2, Y3ch2, 'g-', label='Average lg. bench min.')

xlabels2 = fig3.index
tick_pos = [(x + 0.4) for x in x_pos2]
plt.xticks(tick_pos, xlabels2, rotation=90)
plt.ylim(0, 35)

plt.title('Cibona min. distribution')

plt.show()

I will repeat, some players were also traded during season, which means the depth of roster is misleading. We could combine this charts with charts plotting total minutes, to get alternative view.

And now let's draw the rest of teams separately.

In [7]:
teams = ('Union Olimpija', 'Cibona', 'Zadar', 'Budućnost', 'Cedevita', 'Crvena Zvezda', 'Igokea', 'Krka',
          'Mega Leks', 'Sutjeska', 'MZT Skopje', 'Partizan', 'Tajfun', 'Metalac')

for team in teams:
    # First chart data
    fig2 = df_main[df_main["TM"] == team]
    fig2 = fig2.groupby("NAME").mean()
    fig2.drop(fig2.index[[0]])
    fig2 = fig2.sort_values('MP', ascending=False)
    fig2["LG_ST_AVG"] = 24.28
    fig2["LG_BN_AVG"] = 14.56

    plt.figure(figsize=(8,6), dpi=80)

    x_pos = np.arange(len(fig2))
    Y1ch1 = fig2['MP']
    Y2ch1 = fig2["LG_ST_AVG"]
    Y3ch1 = fig2["LG_BN_AVG"]

    plt.bar(x_pos, Y1ch1, facecolor='red')
    plt.plot(x_pos, Y2ch1, 'b-', label='Average lg. starter min.')
    plt.plot(x_pos, Y3ch1, 'g-', label='Average lg. bench min.')

    xlabels1 = fig2.index
    tick_pos = [(x + 0.4) for x in x_pos]
    plt.xticks(tick_pos, xlabels1, rotation=90)

    plt.title(team + ' min. distribution')
    plt.legend(loc=9, ncol=2,prop={'size':8})
    plt.ylabel("Minutes")

    plt.show()