diff options
| author | schneefux <schneefux+commit@schneefux.xyz> | 2018-07-26 21:53:13 +0200 |
|---|---|---|
| committer | schneefux <schneefux+commit@schneefux.xyz> | 2018-12-13 17:09:35 +0100 |
| commit | 1c3196ae3436a03668df8559709b50343d68878a (patch) | |
| tree | d96bb8c489549efaeef1e843dddfbc0719890af1 /src | |
| parent | d61fa871d66d6237d7bca28bbd5a4535827abc01 (diff) | |
| download | brokentalents-1c3196ae3436a03668df8559709b50343d68878a.tar.gz brokentalents-1c3196ae3436a03668df8559709b50343d68878a.zip | |
Summaries: Init aggregate statistics
Diffstat (limited to 'src')
| -rw-r--r-- | src/ModeTab.vue | 2 | ||||
| -rw-r--r-- | src/ReportService.js | 63 | ||||
| -rw-r--r-- | src/Summaries.vue | 113 |
3 files changed, 142 insertions, 36 deletions
diff --git a/src/ModeTab.vue b/src/ModeTab.vue index 14bb960..0b57e35 100644 --- a/src/ModeTab.vue +++ b/src/ModeTab.vue @@ -39,7 +39,7 @@ <win-pick-scatter></win-pick-scatter> </div> - <div class="box" v-show="hasTalents"> + <div class="box"> <h2 class="title is-2">Summaries</h2> <summaries></summaries> </div> diff --git a/src/ReportService.js b/src/ReportService.js index f11240c..b8a23fd 100644 --- a/src/ReportService.js +++ b/src/ReportService.js @@ -1,5 +1,6 @@ import * as maps from './maps/maps'; import * as metadata from '../data/5f7773da/metadata.json'; +import * as baseStats from '../data/vainglory.json'; // Thanks to https://github.com/oberocks/vainglory-base-stats import * as R from 'ramda'; const POPULAR_THRESHOLD = 1.0; // percent @@ -23,7 +24,7 @@ const topUnpopularWins = new Map(); const topKillDeathPoints = new Map(); const topObjectivePoints = new Map(); const topBlitzPointsDelta = new Map(); -const summaryTalents = new Map(); +const summaries = new Map(); let totalMatches = 0; let actors = []; const modes = metadata.config.api.modes; @@ -76,8 +77,28 @@ for(let mode of modes) { // r^2 is also correlation coefficient ^ 2 const rsquare = 1 - ssres / sstot; + const hero = maps.getHero(entry.Actor); + const baseStat = baseStats.heroes[hero.toLowerCase()]; + const rateClass = (r) => { + let heroClass = ''; + if (r.team_utility > r.offense) { + if (r.defense > r.team_utility) heroClass += 'Tank'; + else heroClass += 'Healer'; + } else { + if (r.offense > r.defense) heroClass += 'Squishy'; + else heroClass += 'Warrior'; + } + return heroClass; + }; + return Object.assign({}, entry, { _Count: 1, // TODO find a cleaner solution to convert the sum of relatives to absolutes in summaries + Hero: hero, + AttackType: baseStat.attack_type, + Difficulty: baseStat.difficulty, + HeroClass: rateClass(baseStat.ratings), + HeroSpeed: baseStat.ratings.mobility < 3 ? 'Slow' : baseStat.ratings.mobility < 6 ? 'Average' : 'Fast', + PrimaryRole: baseStat.primary_role, Rarity: maps.getTalentRarity(entry.Talent), TalentWinrateBase: intercept || entry.Winner, TalentWinrateScaling: slope || 0, // to 1 = max level @@ -135,11 +156,35 @@ for(let mode of modes) { .filter((entry) => !entry.SampleTooSmall && !entry.VarianceTooLarge && !!entry.BlitzPointsDelta) .sort((entry1, entry2) => entry2.BlitzPointsDelta - entry1.BlitzPointsDelta)[0]); - summaryTalents.set(mode, - new Map(Object.entries( - R.reduceBy(R.mergeWith((a, b) => R.is(String, a) ? a : R.add(a, b) ), 0, R.prop('Rarity'), reports.get(mode)) - )) - ); + const addOrIdentity = (a, b) => R.is(String, a) ? a : R.add(a, b); + const summarizeByProp = (propName) => new Map(Object.entries( + R.reduceBy(R.mergeWith(addOrIdentity), 0, R.prop(propName), reports.get(mode)) + )); + summaries.set(mode, [ { + 'key': 'Rarity', + 'name': 'Talent Rarity', + 'data': [...summarizeByProp('Rarity').values()], + }, { + 'key': 'Difficulty', + 'name': 'Difficulty', + 'data': [...summarizeByProp('Difficulty').values()], + }, { + 'key': 'PrimaryRole', + 'name': 'Primary Role', + 'data': [...summarizeByProp('PrimaryRole').values()], + }, { + 'key': 'AttackType', + 'name': 'Attack Type', + 'data': [...summarizeByProp('AttackType').values()], + }, { + 'key': 'HeroSpeed', + 'name': 'Speed', + 'data': [...summarizeByProp('HeroSpeed').values()], + }, { + 'key': 'HeroClass', + 'name': 'Class', + 'data': [...summarizeByProp('HeroClass').values()], + } ]); if (actors.length == 0) { actors = [...new Set(reports.get(mode).map((entry) => entry.Actor))]; @@ -157,7 +202,7 @@ export default { '\n' + reports.get(mode) .map((entry) => [ - maps.getHero(entry.Actor), + entry.Hero, maps.getTalentName(entry.Talent), maps.getTalentRarity(entry.Talent), entry.Kills, @@ -233,8 +278,8 @@ export default { return topBlitzPointsDelta.get(mode); }, - getSummaryTalents(mode) { - return summaryTalents.get(mode); + getSummaries(mode) { + return summaries.get(mode); }, getActors() { diff --git a/src/Summaries.vue b/src/Summaries.vue index 51bd277..009a36b 100644 --- a/src/Summaries.vue +++ b/src/Summaries.vue @@ -1,30 +1,83 @@ <template> - <b-table :data="talentSummaries" - :mobile-cards="false"> - <template slot-scope="props" slot="header"> - <b-tooltip :active="!!props.column.meta" :label="props.column.meta || ''" position="is-bottom" dashed> - {{ props.column.label }} - </b-tooltip> - </template> + <div> + <div class="block"> + <b-field grouped group-multiline> + <label class="control label">Metrics</label> + <p class="control"> + <b-checkbox v-model="talentsVisible" v-show="hasTalents">Talent Levels</b-checkbox> + </p> + <p class="control"> + <b-checkbox v-model="winrateVisible">Win Rate</b-checkbox> + </p> + <p class="control"> + <b-checkbox v-model="killsDeathsVisible">Kills and Deaths</b-checkbox> + </p> + <p class="control"> + <b-checkbox v-model="objectivesVisible">Objectives</b-checkbox> + </p> + </b-field> + </div> - <template slot-scope="props"> - <b-table-column field="Rarity" label="Rarity"> - {{ props.row.Rarity }} - </b-table-column> + <div class="block"> + <b-field grouped group-multiline> + <label class="control label">Category</label> + <p class="control" + v-for="trait in summaries"> + <b-radio v-model="selectedTrait" + :native-value="trait.key"> + {{ trait.name }} + </b-radio> + </p> + </b-field> + </div> - <b-table-column field="TalentWinrateBase" label="Level 1 Win Rate" meta="Estimated." sortable numeric> - {{ (100 * props.row.TalentWinrateBase / props.row._Count).toFixed(2) }}% - </b-table-column> + <div class="block"> + <label class="label">Data</label> + <b-table :data="summary.data" + :mobile-cards="false" + narrowed> + <template slot-scope="props" slot="header"> + <b-tooltip :active="!!props.column.meta" :label="props.column.meta || ''" position="is-bottom" dashed> + {{ props.column.label }} + </b-tooltip> + </template> - <b-table-column field="TalentWinrateMax" label="Max Level Win Rate" meta="Estimated." sortable numeric> - {{ (100 * props.row.TalentWinrateMax / props.row._Count).toFixed(2) }}% - </b-table-column> + <template slot-scope="props"> + <b-table-column :field="selectedTrait" label=""> + {{ props.row[selectedTrait] }} + </b-table-column> - <b-table-column field="TotalPicks" label="Pick Rate" sortable numeric> - {{ (100 * props.row.TotalPicks / totalPicks).toFixed(2) }}% - </b-table-column> - </template> - </b-table> + <b-table-column field="TotalWinner" label="Win Rate" :visible="winrateVisible" sortable numeric> + {{ (100 * props.row.TotalWinner / props.row._Count).toFixed(2) }}% + </b-table-column> + + <b-table-column field="TalentWinrateBase" label="Level 1 Win Rate" :visible="talentsVisible && hasTalents" meta="Estimated." sortable numeric> + {{ (100 * props.row.TalentWinrateBase / props.row._Count).toFixed(2) }}% + </b-table-column> + + <b-table-column field="TalentWinrateMax" label="Max Level Win Rate" :visible="talentsVisible && hasTalents" meta="Estimated." sortable numeric> + {{ (100 * props.row.TalentWinrateMax / props.row._Count).toFixed(2) }}% + </b-table-column> + + <b-table-column field="Kills" label="Kills" :visible="killsDeathsVisible" sortable numeric> + {{ (props.row.Kills / props.row._Count).toFixed(2) }} + </b-table-column> + + <b-table-column field="Deaths" label="Deaths" :visible="killsDeathsVisible" sortable numeric> + {{ (props.row.Deaths / props.row._Count).toFixed(2) }} + </b-table-column> + + <b-table-column field="TurretKills" label="Turret Kills" :visible="objectivesVisible" sortable numeric> + {{ (props.row.TurretKills / props.row._Count).toFixed(2) }} + </b-table-column> + + <b-table-column field="TotalPicks" label="Pick Rate" sortable numeric> + {{ (100 * props.row.TotalPicks / totalPicks).toFixed(2) }}% + </b-table-column> + </template> + </b-table> + </div> + </div> </template> <script> @@ -37,15 +90,23 @@ export default Vue.component('summaries', { mixins: [ RouterParamMixin ], data: function() { return { + talentsVisible: false, + winrateVisible: true, + killsDeathsVisible: false, + objectivesVisible: false, + selectedTrait: this.hasTalents? 'Rarity' : 'Difficulty', }; }, computed: { - talentSummaries: function() { - return [...ReportService.getSummaryTalents(this.selectedMode).values()] - .sort((entry1, entry2) => maps.getTalentRarityIndex(entry1.Talent) - maps.getTalentRarityIndex(entry2.Talent)); + summaries: function() { + return ReportService.getSummaries(this.selectedMode) + .filter((summary) => this.hasTalents? true : summary.key != 'Rarity'); + }, + summary: function() { + return this.summaries.find((summary) => summary.key == [this.selectedTrait]); }, totalPicks: function() { - return this.talentSummaries.map((entry) => entry.TotalPicks).reduce((agg, cur) => agg + cur, 0); + return this.summary.data.map((entry) => entry.TotalPicks).reduce((agg, cur) => agg + cur, 0); }, }, components: { |
