From: Steinar H. Gunderson Date: Mon, 24 Jul 2023 11:01:54 +0000 (+0200) Subject: Make it possible to filter by gender ratio. X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=0f81e726fbab591d82854facc447cbbb69b59e77;p=pkanalytics Make it possible to filter by gender ratio. --- diff --git a/ultimate.js b/ultimate.js index c0ca1ba..f70426d 100644 --- a/ultimate.js +++ b/ultimate.js @@ -175,6 +175,7 @@ function process_matches(json, filters) { for (const player of json['players']) { players[player['player_id']] = { 'name': player['name'], + 'gender': player['gender'], 'number': player['number'], 'goals': 0, @@ -1102,6 +1103,7 @@ function open_filter_menu() { add_menu_item(menu, 3, 'formation_offense', 'Offense played (any)'); add_menu_item(menu, 4, 'formation_defense', 'Defense played (any)'); add_menu_item(menu, 5, 'starting_on', 'Starting on'); + add_menu_item(menu, 6, 'gender_ratio', 'Gender ratio'); } function add_menu_item(menu, menu_idx, filter_type, title) { @@ -1119,6 +1121,42 @@ function add_menu_item(menu, menu_idx, filter_type, title) { item.addEventListener('click', (e) => { show_submenu(menu_idx, null, filter_type); }); } +function find_all_ratios(json) +{ + let ratios = {}; + let players = {}; + for (const player of json['players']) { + players[player['player_id']] = { + 'gender': player['gender'], + 'last_point_seen': null, + }; + } + for (const match of json['matches']) { + for (const [q,p] of Object.entries(players)) { + p.on_field_since = null; + } + for (const e of match['events']) { + let p = players[e['player']]; + let type = e['type']; + if (type === 'in') { + p.on_field_since = 1; + } else if (type === 'out') { + p.on_field_since = null; + } else if (type === 'pull' || type == 'their_pull') { // We assume no cross-gender subs for now. + let code = find_gender_ratio_code(players); + if (ratios[code] === undefined) { + ratios[code] = code; + if (code !== '4 F, 3 M' && code !== '4 M, 3 F' && code !== '3 M, 2 F' && code !== '3 F, 2 M') { + console.log('Unexpected gender ratio ' + code + ' first seen at: ' + + match['description'] + ', ' + format_time(e['t'])); + } + } + } + } + } + return ratios; +} + function show_submenu(menu_idx, pill, filter_type) { let submenu = document.getElementById('filter-submenu'); let subitems = []; @@ -1174,6 +1212,13 @@ function show_submenu(menu_idx, pill, filter_type) { 'title': 'Defense', 'id': true, // last_pull_was_ours }); + } else if (filter_type === 'gender_ratio') { + for (const [title, id] of Object.entries(find_all_ratios(global_json)).sort()) { + choices.push({ + 'title': title, + 'id': id, + }); + } } for (const choice of choices) { @@ -1355,6 +1400,17 @@ function make_filter_pill(filter) { } else { text += 'Defense'; } + } else if (filter.type === 'gender_ratio') { + text = 'Gender: '; + + let first = true; + for (const name of Array.from(filter.elements).sort()) { + if (!first) { + text += '; '; + } + text += name; + first = false; + } } let text_node = document.createElement('span'); @@ -1461,6 +1517,46 @@ function keep_match(match_id, filters) { return true; } +function find_gender_ratio_code(players) { + let map = {}; + for (const [q,p] of Object.entries(players)) { + if (p.on_field_since === null) { + continue; + } + let gender = p.gender; + if (gender === '' || gender === undefined || gender === null) { + gender = '?'; + } + if (map[gender] === undefined) { + map[gender] = 1; +q } else { + ++map[gender]; + } + } + let all_genders = Array.from(Object.keys(map)).sort( + (a,b) => { + if (map[a] !== map[b]) { + return map[b] - map[a]; // Reverse numeric. + } else if (a < b) { + return -1; + } else if (a > b) { + return 1; + } else { + return 0; + } + }); + let code = ''; + for (const g of all_genders) { + if (code !== '') { + code += ', '; + } + code += map[g]; + code += ' '; + code += g; + } + return code; +} + function filter_passes(players, formations_used_this_point, last_pull_was_ours, filter) { if (filter.type === 'player_any') { for (const p of Array.from(filter.elements)) { @@ -1485,6 +1581,8 @@ function filter_passes(players, formations_used_this_point, last_pull_was_ours, return false; } else if (filter.type === 'starting_on') { return filter.elements.has(last_pull_was_ours); + } else if (filter.type === 'gender_ratio') { + return filter.elements.has(find_gender_ratio_code(players)); } return true; }