League of Legends World Championship 2019
Preamble¶
import numpy as np # for multi-dimensional containers
import pandas as pd # for DataFrames
import itertools
from chord import Chord
Introduction¶
In previous sections, we visualised co-occurrences of Pokémon type. Whilst it was interesting to look at, the dataset only contained Pokémon from the first six geerations. In this section, we're going to use the Pokemon with stats Generation 8 dataset to visualise the co-occurrence of Pokémon types from generations one to eight.
The Dataset¶
The dataset documentation states that we can expect 13 variables per each of the 1017 Pokémon of the first eight generations.
Let's download the mirrored dataset and have a look for ourselves.
data_url = 'https://shahinrostami.com/datasets/lol/wc_matches.csv'
data = pd.read_csv(data_url)
data['date'] = pd.to_datetime(data['date'])
data.head()
It looks good so far, but let's confirm the 13 variables against 1017 samples from the documentation.
data.shape
Perfect, that's exactly what we were expecting.
Data Wrangling¶
We need to do a bit of data wrangling before we can visualise our data. We can see from the columns names that the Pokémon types are split between the columns Type 1
and Type 2
.
pd.DataFrame(data.columns.values.tolist())
So let's select just these two columns and work with a list containing only them as we move forward.
types = pd.DataFrame(data[['team1', 'team2']].values)
types
Without further investigation, we can see that we have at least a few NaN
values in the table above. We are only interested in co-occurrence of types, so we can remove all samples which contain a NaN
value.
types = types.dropna()
We can also see an instance where the type Fighting
at index $1014$ is followed by \n
. We'll strip all these out before continuing.
types = types.replace('\n','', regex=True)
types
Our chord diagram will need two inputs: the co-occurrence matrix, and a list of names to label the segments.
First we'll populate our list of type names by looking for the unique ones.
names = np.unique(types).tolist()
pd.DataFrame(names)
Now we can create our empty co-occurrence matrix using these type names for the row and column indeces.
We can populate a co-occurrence matrix with the following approach. We'll start by creating a list with every type pairing in its original and reversed form.
Which we can now use to create the matrix.
matrix = pd.DataFrame(0, index=names, columns=names)
details = pd.DataFrame([], index=names, columns=names).astype('object')
for index, x in details.iterrows():
for k in details.columns.values:
x[k] = []
for index, x in data.iterrows():
if(x['winner'] == x['team1']):
matrix.at[x['team1'], x['team2']] += 1
temp = details.at[x['team1'], x['team2']]
if(x['team1'] == x['blue']):
color = '#00bbf9'
else:
color = '#fe5f55'
temp.append(f"{x['date'].strftime('%b-%d %H:%M')} <span style='color:{color}!important; font-style: normal;'>⬤</span> {x['team1']} 🥇 {x['mvp']}")
details.at[x['team1'], x['team2']] = temp
else:
matrix.at[x['team2'], x['team1']] += 1
temp = details.at[x['team2'], x['team1']]
if(x['team2'] == x['blue']):
color = '#00bbf9'
else:
color = '#fe5f55'
temp.append(f"{x['date'].strftime('%b-%d %H:%M')} <span style='color:{color}!important; font-style: normal;'>⬤</span> {x['team2']} 🥇 {x['mvp']}")
matrix = matrix.values.tolist()
details = pd.DataFrame(details)
We can list DataFrame
for better presentation.
x['blue']
Chord Diagram¶
Time to visualise the co-occurrence of types using a chord diagram. We are going to use a list of custom colours that represent the types.
colors = ["#A6B91A", "#705746", "#6F35FC", "#F7D02C", "#D685AD",
"#C22E28", "#EE8130", "#A98FF3", "#735797", "#7AC74C",
"#E2BF65", "#96D9D6", "#A8A77A", "#A33EA1", "#F95587",
"#B6A136", "#B7B7CE", "#6390F0"];
Finally, we can put it all together.
Chord(matrix, names, symmetric=False,popup_width=700,
verb="battled together in",noun="matches",details=details.values.tolist(),
details_separator='<br>',colors=colors,
margin=75,font_size_large="12px",font_size="12px", credit=True, padding=0.04).show()