Skip to content

Instantly share code, notes, and snippets.

@jonohayon
Created March 17, 2018 11:47
Show Gist options
  • Save jonohayon/f1ea898cde6fb7a148b721c92a3f25fd to your computer and use it in GitHub Desktop.
Save jonohayon/f1ea898cde6fb7a148b721c92a3f25fd to your computer and use it in GitHub Desktop.
Barak's Charts
import os
import re
import csv
import sys
from collections import defaultdict
import matplotlib.pyplot as plt
from math import ceil
MATCH_REGEX = re.compile('(?P<type>PM|QM|QF|SF|F)[ -]?(?P<num>[0-9]+)')a
TRUE_STRING = 'TRUE'
SUCCESS = 'Successful'
FAIL = 'Failed'
class Data(object):
def __init__(self, data):
self.full_name = data[0]
self.team_number = int(data[1])
stripped_name = data[2].strip().upper()
parsed_match_id = MATCH_REGEX.match(stripped_name)
if parsed_match_id is None:
print "Failed to parse match id: {}".format(stripped_name)
self._match_id = {'type': None, 'num': None}
else:
self._match_id = parsed_match_id.groupdict()
self.auto_run = data[3] == TRUE_STRING
self.auto_exchange = data[4] == TRUE_STRING
self.auto_switch = int(data[5] or 0)
self.auto_switch_fail = int(data[6] or 0)
self.auto_scale = int(data[7] or 0)
self.auto_scale_fail = int(data[8] or 0)
self.collection = data[9]
self.tele_switch = int(data[10] or 0)
self.tele_switch_fail = int(data[11] or 0)
self.tele_scale = int(data[12] or 0)
self.tele_scale_fail = int(data[13] or 0)
self.tele_exchange = int(data[14] or 0)
self.tele_exchange_fail = int(data[15] or 0)
self.platform = data[16] == TRUE_STRING
self.climb = data[17]
self.partner_climb = data[18]
self.tech_foul = data[19] == TRUE_STRING
self.defence_comments = data[20]
self.comments = data[21]
def __repr__(self):
return "<Data Team {} | Match {}>".format(self.team_number, self.match_name)
@property
def match_name(self):
return "{type} {num}".format(**self._match_id)
@property
def match_key(self):
if self._match_id['type'] == 'PM':
return int(self._match_id['num']) - 100
elif self._match_id['type'] == 'QM':
return int(self._match_id['num'])
elif self._match_id['type'] == 'QF':
return 1000 + int(self._match_id['num'])
elif self._match_id['type'] == 'SF':
return 2000 + int(self._match_id['num'])
elif self._match_id['type'] == 'F':
return 3000 + int(self._match_id['num'])
else:
return 4000
@property
def exchange(self):
return self.tele_exchange
@property
def switch(self):
return self.tele_switch + self.auto_switch
@property
def scale(self):
return self.tele_scale + self.auto_scale
def get_data():
with open(sys.argv[1]) as fh:
rd = csv.reader(fh)
rd.next() # ignore headers
return map(Data, rd)
def keep_data(data, top_pct=0.75):
return int(ceil(len(data) * top_pct))
def average(data, keep=None):
# Keep all.
if keep is None:
keep = len(data)
# Average over that data
data_sum = sum(sorted(data, reverse=True)[:keep])
return float(data_sum) / keep
def plot_cube_handling(team_number):
records = data_by_team[team_number]
x = range(len(records))
matches = [d.match_name for d in records]
exchange = [d.exchange for d in records]
switch = [d.switch for d in records]
scale = [d.scale for d in records]
total = map(sum, zip(exchange, switch, scale))
keep = keep_data(total)
total_average = average(total, keep)
if keep < len(total):
ignored_x = zip(*sorted(enumerate(total), key=lambda d: d[1])[:-keep])[0]
else:
ignored_x = []
auto_run = [(1 if d.auto_run else 0) for d in records]
auto_run_fail = [(1 if not d.auto_run else 0) for d in records]
auto_switch = [(2 if d.auto_switch > 0 else 0) for d in records]
auto_switch_fail = [(2 if d.auto_switch_fail > 0 else 0) for d in records]
auto_scale = [(3 if d.auto_scale > 0 else 0) for d in records]
auto_scale_fail = [(3 if d.auto_scale_fail > 0 else 0) for d in records]
platform = [(6 if d.platform else 0) for d in records]
climb = [(5 if d.climb == SUCCESS else 0) for d in records]
climb_fail = [(5 if d.climb == FAIL else 0) for d in records]
partner_climb = [(4 if d.partner_climb == SUCCESS else 0) for d in records]
partner_climb_fail = [(4 if d.partner_climb == FAIL else 0) for d in records]
plt.subplot(211)
plt.title('Team {}'.format(team_number))
lines = plt.stackplot(x, exchange, switch, scale)
plt.plot([x[0], x[-1]], [total_average, total_average], 'r--', ignored_x, [5 for _ in ignored_x], 'rx')
plt.xticks([], [])
plt.xlim(x[0], x[-1])
plt.yticks(range(13))
plt.ylabel('Number of Cubes')
plt.figlegend(lines, ['Exchange', 'Switch', 'Scale'])
plt.grid(True)
plt.subplot(212)
plt.plot(x, auto_run, 'gv', x, auto_run_fail, 'rx',
x, auto_switch, 'gv', x, auto_switch_fail, 'rx',
x, auto_scale, 'gv', x, auto_scale_fail, 'rx',
x, platform, 'bo',
x, climb, 'gv', x, climb_fail, 'rx',
x, partner_climb, 'gv', x, partner_climb_fail, 'rx')
plt.yticks([1,2,3,4,5,6], ['[A] Run', '[A] Switch', '[A] Scale', 'Partner', 'Climb', 'Platform'])
plt.ylim(0.5, 7.0)
plt.xticks(x, matches, rotation=90)
plt.xlim(x[0], x[-1])
plt.grid(True)
if not os.path.isdir('graphs'):
os.mkdir('graphs')
plt.savefig('graphs\\{}.png'.format(team_number))
fig.clear()
with open('graphs\\{}.txt'.format(team_number), 'wb') as fh:
fh.write("Team {}\r\n".format(team_number))
for record in records:
fh.write("Match {}:\r\n".format(record.match_name))
fh.write("Tech Fouls? {}\r\n".format(record.tech_foul))
fh.write("{}\r\n".format(record.defence_comments))
fh.write("{}\r\n\r\n".format(record.comments))
data_by_team = defaultdict(list)
if __name__ == "__main__":
all_data = get_data()
[data_by_team[data.team_number].append(data) for data in all_data]
sorted_teams = []
fig = plt.figure()
fig.set_size_inches(9, 6)
for team in sorted(data_by_team.keys()):
data_by_team[team].sort(key=lambda data: data.match_key)
records = data_by_team[team]
exchange = [d.exchange for d in records]
switch = [d.switch for d in records]
scale = [d.scale for d in records]
total = map(sum, zip(exchange, switch, scale))
keep = keep_data(total)
exchange = average(exchange, keep)
switch = average(switch, keep)
scale = average(scale, keep)
total = average(total, keep)
sorted_teams.append((team, exchange, switch, scale, total))
matches = [d.match_name for d in records]
if len(records) == 1:
print "WARNING: only one record for team {}! typo?".format(team)
elif len(set(matches)) < len(records):
dupes = {match for match in matches if matches.count(match) > 1}
print "WARNING: Duplicates for team {}: {}".format(team, dupes)
else:
print "Parsed team {}.".format(team)
plot_cube_handling(team)
with open("Results.txt", 'w') as fh:
fh.write("Top Exchange Teams:\n")
for i, (team, exchange, _, _, _) in enumerate(sorted(sorted_teams, key=lambda x: x[1], reverse=True)[:16]):
fh.write("{:2}. {} - {:.2f}\n".format(i+1, team, exchange))
fh.write("\nTop Switch Teams:\n")
for i, (team, _, switch, _, _) in enumerate(sorted(sorted_teams, key=lambda x: x[2], reverse=True)[:16]):
fh.write("{:2}. {} - {:.2f}\n".format(i+1, team, switch))
fh.write("\nTop Scale Teams:\n")
for i, (team, _, _, scale, _) in enumerate(sorted(sorted_teams, key=lambda x: x[3], reverse=True)[:16]):
fh.write("{:2}. {} - {:.2f}\n".format(i+1, team, scale))
fh.write("\nTop Total Teams:\n")
for i, (team, _, _, _, total) in enumerate(sorted(sorted_teams, key=lambda x: x[4], reverse=True)[:16]):
fh.write("{:2}. {} - {:.2f}\n".format(i+1, team, total))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment