11<template >
22 <div class =" main" >
3- <OverlayLoader :show =" loading" solid absolute no-fade />
4- <v-container class =" text-center" >
5- <v-row
6- v-if ="
7- Object.keys(fullExplanations).length !== 0 &&
8- fullExplanations.constructor === Object
9- "
10- >
3+ <LoadingFullscreen v-show =" loading" name =" explanation" class =" pb-6" />
4+ <v-container class =" text-center" v-show =" !loading" >
5+ <v-row v-if =" Object.keys(fullExplanations).length !== 0 &&
6+ fullExplanations.constructor === Object
7+ " >
118 <v-col >
12- <v-chart
13- v-if =" predictionTask === ModelType.REGRESSION"
14- class =" chart"
15- :option =" chartOptionsRegression"
16- autoresize
17- />
18- <v-chart
19- v-if =" predictionTask === ModelType.CLASSIFICATION && classificationLabels.length === 2"
20- class =" chart"
21- :option =" chartOptionsBinaryClassification"
22- autoresize
23- />
24- <v-chart
25- v-if =" predictionTask === ModelType.CLASSIFICATION && classificationLabels.length > 2"
26- class =" chart"
27- :option =" chartOptionsMultiClassification"
28- autoresize
29- />
9+ <v-chart v-if =" predictionTask === ModelType.REGRESSION" class =" chart" :option =" chartOptionsRegression" autoresize />
10+ <v-chart v-if =" predictionTask === ModelType.CLASSIFICATION && classificationLabels.length === 2" class =" chart" :option =" chartOptionsBinaryClassification" autoresize />
11+ <v-chart v-if =" predictionTask === ModelType.CLASSIFICATION && classificationLabels.length > 2" class =" chart" :option =" chartOptionsMultiClassification" autoresize />
3012 </v-col >
3113 </v-row >
3214 <p v-if =" errorMsg" class =" error--text" >
3719</template >
3820
3921<script lang="ts">
40- import {Component , Prop , Vue , Watch } from " vue-property-decorator" ;
41- import OverlayLoader from " @/components/OverlayLoader .vue" ;
42- import {api } from " @/api" ;
22+ import { Component , Prop , Vue , Watch } from " vue-property-decorator" ;
23+ import LoadingFullscreen from " @/components/LoadingFullscreen .vue" ;
24+ import { api } from " @/api" ;
4325import ECharts from " vue-echarts" ;
44- import {use } from " echarts/core" ;
45- import {BarChart } from " echarts/charts" ;
46- import {CanvasRenderer } from " echarts/renderers" ;
47- import {GridComponent } from " echarts/components" ;
26+ import { use } from " echarts/core" ;
27+ import { BarChart } from " echarts/charts" ;
28+ import { CanvasRenderer } from " echarts/renderers" ;
29+ import { GridComponent } from " echarts/components" ;
4830import " echarts/lib/component/legend" ;
49- import {ModelType } from " @/generated-sources" ;
31+ import { ModelType } from " @/generated-sources" ;
5032import _ from " lodash" ;
51- import {CanceledError } from " axios" ;
33+ import { CanceledError } from " axios" ;
5234
5335use ([CanvasRenderer , BarChart , GridComponent ]);
5436Vue .component (" v-chart" , ECharts );
5537
5638@Component ({
57- components: {OverlayLoader },
39+ components: { LoadingFullscreen },
5840})
5941export default class PredictionExplanations extends Vue {
60- @Prop ({required: true }) modelId! : string ;
61- @Prop ({required: true }) datasetId! : string ;
62- @Prop ({required: true }) predictionTask! : string ;
42+ @Prop ({ required: true }) modelId! : string ;
43+ @Prop ({ required: true }) datasetId! : string ;
44+ @Prop ({ required: true }) predictionTask! : string ;
6345 @Prop () targetFeature! : string ;
6446 @Prop () classificationLabels! : string [];
65- @Prop ({default: {}}) inputData! : object ;
47+ @Prop ({ default: {} }) inputData! : object ;
6648 @Prop () modelFeatures! : string [];
67- @Prop ({default: 250 }) debounceTime! : number ;
49+ @Prop ({ default: 250 }) debounceTime! : number ;
6850
6951
7052 loading: boolean = false ;
@@ -77,7 +59,7 @@ export default class PredictionExplanations extends Vue {
7759 await this .getExplanation ()
7860 }
7961
80- @Watch (" inputData" , {deep: true })
62+ @Watch (" inputData" , { deep: true })
8163 private async onInputDataChange() {
8264 await this .debouncedGetExplanation ();
8365 }
@@ -96,10 +78,10 @@ export default class PredictionExplanations extends Vue {
9678 this .loading = true ;
9779 this .errorMsg = " " ;
9880 const explainResponse = await api .explain (
99- this .modelId ,
100- this .datasetId ,
101- _ .pick (this .inputData , this .modelFeatures ),
102- this .controller
81+ this .modelId ,
82+ this .datasetId ,
83+ _ .pick (this .inputData , this .modelFeatures ),
84+ this .controller
10385 )
10486 this .fullExplanations = explainResponse .explanations ;
10587 this .loading = false ;
@@ -138,9 +120,9 @@ export default class PredictionExplanations extends Vue {
138120 show: true ,
139121 position: " right" ,
140122 formatter : (params ) =>
141- params .value > 0.02
142- ? params .value .toFixed (2 ).toLocaleString ()
143- : " " ,
123+ params .value > 0.02
124+ ? params .value .toFixed (2 ).toLocaleString ()
125+ : " " ,
144126 },
145127 labelLayout: {
146128 hideOverlap: true ,
@@ -166,30 +148,30 @@ export default class PredictionExplanations extends Vue {
166148
167149 get chartOptionsBinaryClassification() {
168150 const lastExplanations =
169- this .fullExplanations [Object .keys (this .fullExplanations )[Object .keys (this .fullExplanations ).length - 1 ]];
151+ this .fullExplanations [Object .keys (this .fullExplanations )[Object .keys (this .fullExplanations ).length - 1 ]];
170152 return this .createSimpleExplanationChart (lastExplanations );
171153 }
172154
173155 get chartOptionsMultiClassification() {
174156 const explanationSumByFeature: { [name : string ]: number ; } = _ .reduce (
175- _ .values (this .fullExplanations ),
176- (acc , labelExplanations ) => {
177- _ .forOwn (labelExplanations , (featureName , explainValue ) => {
178- acc [explainValue ] = (acc [explainValue ] || 0 ) + featureName ;
179- });
180- return acc ;
181- }, {});
157+ _ .values (this .fullExplanations ),
158+ (acc , labelExplanations ) => {
159+ _ .forOwn (labelExplanations , (featureName , explainValue ) => {
160+ acc [explainValue ] = (acc [explainValue ] || 0 ) + featureName ;
161+ });
162+ return acc ;
163+ }, {});
182164
183165 // Array of features sorted by sum of SHAP explanations
184166 // Bonus: sort by feature name to guarantee same order if the explanation sum is the same
185167 const sortedTopFeatures: Array <string > = Object .entries (
186- explanationSumByFeature
168+ explanationSumByFeature
187169 ).sort ((a , b ) => a [1 ] - b [1 ] || b [0 ].localeCompare (a [0 ])
188170 ).map (el => el [0 ])
189171 let chartSeries: object [] = [];
190172
191173 for (const [className, explanation] of Object .entries (
192- this .fullExplanations
174+ this .fullExplanations
193175 )) {
194176 // Guarantee that the explanation object follows the same feature order
195177 let explanationSortedByFeature: object = {}
@@ -209,7 +191,7 @@ export default class PredictionExplanations extends Vue {
209191 fontSize: " 10" ,
210192 },
211193 formatter : (params ) =>
212- params .value > 0.02 ? params .value .toFixed (2 ).toLocaleString () : " " ,
194+ params .value > 0.02 ? params .value .toFixed (2 ).toLocaleString () : " " ,
213195 },
214196 labelLayout: {
215197 hideOverlap: true ,
0 commit comments