In [1]:
import pandas as pd
import altair as alt
from load_decks import load_decks, deck_card_colors
In [2]:
raw_decks = load_decks()
0
25
50
75
100
125
150
175
200
225
250
275
300
325
350
375
400
425
450
475
500
525
550
575
600
625
650
675
In [3]:
decks = pd.DataFrame([deck_card_colors(d) for d in raw_decks if d['cards'] is not None]).set_index('id')
In [4]:
for c in 'WUBRG':
    decks[c + 'd'] = decks[c] >= 5
In [5]:
decks['player'].nunique()
Out[5]:
166
In [6]:
decks['primary_color'] = decks[list('WUBRG')].idxmax(axis=1)
In [7]:
def has_card(deck_id, card_name):
    deck = next(deck for deck in raw_decks if deck['id'] == deck_id)
    return any(card['card']['name'] == card_name for card in deck['cards'])
In [8]:
decks['hoof?'] = decks.apply(lambda row: has_card(row.name, 'Craterhoof Behemoth'), axis=1)
decks['shatter?'] = decks.apply(lambda row: has_card(row.name, 'Shatter the Sky'), axis=1)
decks['cast?'] = decks.apply(lambda row: has_card(row.name, 'Cast Down'), axis=1)
decks['ecd?'] = decks.apply(lambda row: has_card(row.name, 'Elspeth Conquers Death'), axis=1)
In [9]:
completed_decks = decks[(decks['match_wins'] + decks['match_losses']) == 5]
In [10]:
completed_decks.count()
Out[10]:
match_wins       416
match_losses     416
player           416
resigned         416
creation_date    416
W                416
U                416
B                416
R                416
G                416
Wd               416
Ud               416
Bd               416
Rd               416
Gd               416
primary_color    416
hoof?            416
shatter?         416
cast?            416
ecd?             416
dtype: int64
In [11]:
416 / (4 * 7 - 1)
Out[11]:
15.407407407407407
In [12]:
matches = set((match['winner']['id'], match['loser']['id']) for deck in raw_decks for match in deck['matches'])
In [13]:
def mtg_colors(name, color_names=list('WUBRG')):
    return alt.Color(name, scale={'domain': color_names, 'range': ['#fffcda', '#ace2fa', '#ccc2c0', '#f8aa92', '#9dd2af']}, legend=None)
In [116]:
alt.Chart(completed_decks[['player', 'primary_color']]).mark_bar().encode(
    x=alt.X('player:N', sort='-y', axis=None),
    y=alt.Y('count():Q', title='Completed League Runs'),
    color=mtg_colors('primary_color:N')
).properties(width='container', title='Completed League Runs per Player (with Primary Color)').save('jmp_league_completions.json')
In [15]:
(completed_decks.groupby('player').count()['resigned'] >= 10).sum()
Out[15]:
13
In [16]:
deck_colors_weekly = completed_decks.groupby(pd.Grouper(key='creation_date', freq='7d'))[[c + 'd' for c in 'WUBRG']].apply(lambda group: group.sum() / group.count()).reset_index().melt(id_vars=['creation_date'])

alt.Chart(deck_colors_weekly).mark_bar().encode(
    x=alt.X('variable:N', axis=None),
    y=alt.Y('value:Q', title='Fraction of Decks'),
    color=mtg_colors('variable:N', color_names=['Wd', 'Ud', 'Bd', 'Rd', 'Gd']),
    column=alt.Column('creation_date:O', title='Week Start', header=alt.Header(format='%d %b', formatType='time', orient='bottom', titlePadding=0))
).properties(
    width=155,
    height=200,
    title='Weekly Breakdown of Colors in All Completed Runs',
).configure_title(anchor='middle').save('jmp_weekly_breakdown_completed.json')
In [17]:
deck_colors_weekly = completed_decks[completed_decks['match_wins'] >= 3].groupby(pd.Grouper(key='creation_date', freq='7d'))[[c + 'd' for c in 'WUBRG']].apply(lambda group: group.sum() / group.count()).reset_index().melt(id_vars=['creation_date'])

alt.Chart(deck_colors_weekly).mark_bar().encode(
    x=alt.X('variable:N', axis=None),
    y=alt.Y('value:Q', title='Fraction of Decks'),
    color=mtg_colors('variable:N', color_names=['Wd', 'Ud', 'Bd', 'Rd', 'Gd']),
    column=alt.Column('creation_date:O', title='Week Start', header=alt.Header(format='%d %b', formatType='time', orient='bottom', titlePadding=0))
).properties(
    width=155,
    height=200,
    title='Weekly Breakdown of Colors in w/ 3+ Wins',
).configure_title(anchor='middle').save('jmp_weekly_breakdown_winning.json')
In [18]:
deck_cards_weekly = completed_decks[completed_decks['match_wins'] >= 3].groupby(pd.Grouper(key='creation_date', freq='7d'))[['ecd?', 'hoof?', 'shatter?', 'cast?']].apply(lambda group: group.sum() / group.count()).reset_index().melt(id_vars=['creation_date'])

alt.Chart(deck_cards_weekly.replace({
    'ecd?': "Elspeth Conquers Death",
    'hoof?': "Craterhoof Behemoth",
    'cast?': "Cast Down",
    'shatter?': "Shatter the Sky"
})).mark_bar().encode(
    x=alt.X('variable:N', title=None),
    y=alt.Y('value:Q', title='Fraction of Decks'),
    column=alt.Column('creation_date:O', title='Week Start', header=alt.Header(format='%d %b', formatType='time', orient='bottom', titlePadding=0))
).properties(
    width=155,
    height=200,
    title='Weekly Breakdown of Hoof and Removal',
).configure_title(anchor='middle')#.save('jmp_weekly_breakdown_removal.json')
Out[18]:
In [91]:
matches = set((match['winner']['id'], match['loser']['id'], match['date']) for deck in raw_decks for match in deck['matches'])

matches = pd.DataFrame(matches, columns=['winner', 'loser', 'date'])
matches['date'] = pd.to_datetime(matches['date'])
In [93]:
matches.dtypes
Out[93]:
winner                  int64
loser                   int64
date      datetime64[ns, UTC]
dtype: object
In [103]:
alt.Chart(matches).mark_bar(tooltip=True).encode(
    x=alt.X('date:T', timeUnit='hours', title="Time of Day (Local Time)"),
    y=alt.Y('count()', title="# of Matches")
).properties(
    width='container',
    title='League Match Play Times'
).save('jmp_play_hours.json')
In [112]:
alt.Chart(matches).mark_bar(tooltip=True).encode(
    x=alt.X('monthdate(date)', title="Date"),
    y=alt.Y('count()', title="# of Matches Played"),
).properties(
    width='container',
    title='League Match Play Dates'
).save('jmp_play_dates.json')