FeatureEnVi: Visual Analytics for Feature Engineering Using Stepwise Selection and Semi-Automatic Extraction Approaches https://doi.org/10.1109/TVCG.2022.3141040
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
FeatureEnVi/frontend/src/components/Results.vue

537 lines
17 KiB

<template>
<div>
<div id="HistoryPlot" ></div>
<div id="LinePlot"></div>
</div>
</template>
<script>
import { EventBus } from '../main.js'
import * as Plotly from 'plotly.js'
export default {
name: 'Results',
data () {
return {
ValidResultsVar: [],
globalStep: 0,
featuresReceived: [],
scoresMean: [],
scoresSTD: [],
scoresMeanBest: [],
scoresSTDBest: [],
xaxis: [],
valuesGlobal: [],
historyKey: -1,
whereIsChange: -1,
previousState: [],
storeBestSoFarAV: [],
flag: true,
onHold: 0,
keepFeaturesAddedGenRemoved: 0
}
},
methods: {
HistoryPun() {
this.globalStep = this.globalStep + 1
var state = this.globalStep
//console.log('Current Step: ', state)
if (state == 1) {
this.storeBestSoFarAV = parseFloat(this.scoresMean[0]) + parseFloat(this.scoresMean[1]) + parseFloat(this.scoresMean[2]) - parseFloat(this.scoresSTD[0]) - parseFloat(this.scoresSTD[1]) - parseFloat(this.scoresSTD[2])
}
var svg = d3.select("#HistoryPlot");
svg.selectAll("*").remove();
var data = []
var features = this.featuresReceived[33]
if (this.historyKey == 5) {
this.onHold = 0
}
if (this.historyKey == 3) {
if (this.onHold > 0) {
for ( var i = 0; i < this.onHold; i++ ) {
features.pop();
}
}
}
if (this.historyKey == -1) {
for (let i = 0; i < features.length; i++) {
this.valuesGlobal.push([state,0,0,0])
}
} else if (this.historyKey == 0) {
this.valuesGlobal[this.whereIsChange][this.historyKey] = state
} else if (this.historyKey == 1) {
this.valuesGlobal[this.whereIsChange][this.historyKey] = state
} else if (this.historyKey == 2) {
this.valuesGlobal[this.whereIsChange][this.historyKey] = state
} else if (this.historyKey == 3) {
for (let j = 0; j < this.whereIsChange.length; j++) {
this.valuesGlobal[this.whereIsChange[j]][this.historyKey] = state
}
} else if (this.historyKey == 4) {
for (let j = 0; j < this.whereIsChange.length; j++) {
this.valuesGlobal[this.whereIsChange[j]][0] = state
}
} else if (this.historyKey == 5) {
for (let k = 0; k < this.keepFeaturesAddedGenRemoved ; k++) {
this.valuesGlobal.push([state,0,0,0])
}
} else {
}
var toWhichTrans = this.historyKey
var toWhichPosition = this.whereIsChange
var counterSet = -1
var labelsX = ['Include', 'Exclude', 'Transform', 'Generate']
for (let i=0; i< features.length; i++) {
data.push({
label: features[i],
values: this.valuesGlobal[i]
})
}
if (data.length <= 7) {
var heightFinal = 578
} else {
var heightFinal = data.length * 80
}
var margin = {top: 0, right: 0, bottom: 0, left: 0}
var width = 390 - margin.left - margin.right
var height = heightFinal - margin.top - margin.bottom
var padding = 3
var xLabelHeight = 30
var yLabelWidth = 80
var borderWidth = 0
var duration = 50
var chart = d3.select('#HistoryPlot').append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + 0 + ',' + 0 + ')')
var border = chart.append('rect')
.attr('x', yLabelWidth)
.attr('y', xLabelHeight)
.style('fill-opacity', 0)
.style('stroke', '#000')
.style('stroke-width', borderWidth)
.style('shape-rendering', 'crispEdges')
var color = JSON.parse(this.ValidResultsVar[12])
var allValues = Array.prototype.concat.apply([], data.map(function(d) { return d.values }))
var maxWidth = d3.max(data.map(function(d) { return d.values.length }))
var maxR = d3.min([(width - yLabelWidth) / maxWidth, (height - xLabelHeight) / 5]) / 2 // Changed to 4 from data.length
// var r = function(d) {
// var f = d3.scale.sqrt()
// .domain([d3.min(allValues), d3.max(allValues)])
// .rangeRound([0, maxR - padding])
// return f(d)
// }
var c = d3.scale.linear()
.domain([d3.min(allValues), d3.max(allValues)])
.rangeRound([255 * 0.8, 0])
var rows = chart.selectAll('.row')
.data(data, function(d){ return d.label })
rows.enter().append('g')
.attr('class', 'row')
rows.exit()
.transition()
.duration(duration)
.style('fill-opacity', 0)
.remove()
rows.transition()
.duration(duration)
.attr('transform', function(d, i){ return 'translate(' + yLabelWidth + ',' + (maxR * i * 2 + maxR + xLabelHeight) + ')' })
var dots = rows.selectAll('circle')
.data(function(d){ return d.values })
dots.enter().append('circle')
.attr('cy', 0)
.attr('r', 0)
.style('fill', '#ffffff')
.text(function(d){ return d })
dots.exit()
.transition()
.duration(duration)
.attr('r', 0)
.remove()
if (this.storeBestSoFarAV <= (parseFloat(this.scoresMean[0]) + parseFloat(this.scoresMean[1]) + parseFloat(this.scoresMean[2]) - parseFloat(this.scoresSTD[0]) - parseFloat(this.scoresSTD[1]) - parseFloat(this.scoresSTD[2]))) {
this.flag = true
this.storeBestSoFarAV = parseFloat(this.scoresMean[0]) + parseFloat(this.scoresMean[1]) + parseFloat(this.scoresMean[2]) - parseFloat(this.scoresSTD[0]) - parseFloat(this.scoresSTD[1]) - parseFloat(this.scoresSTD[2])
}
var previously = this.previousState
if (toWhichTrans == 5) {
previously.push("black")
previously.push("black")
previously.push("black")
previously.push("black")
}
var lengthFeatures = this.valuesGlobal.length
var testLoc = this.flag
dots.transition()
.duration(duration)
.attr('r', function(d){ return d*2 })
.attr('cx', function(d, i){ return i * maxR * 2 + maxR })
.style('fill', function(d){
counterSet = counterSet + 1
if (testLoc) {
if (toWhichTrans == -1) {
previously.push("black")
}
if (d == state) {
previously[counterSet] = '#B15928'
return previously[counterSet]
} else if (toWhichTrans == 3 || toWhichTrans == 4) {
var found = false
for (let i = 0; i < toWhichPosition.length; i++) {
if (counterSet == (4*toWhichPosition[i] + 0) || counterSet == (4*toWhichPosition[i] + 1) || counterSet == (4*toWhichPosition[i] + 2) || counterSet == (4*toWhichPosition[i] + 3)) {
previously[counterSet] = 'black'
found = true
return previously[counterSet]
}
}
if (!found) {
return previously[counterSet]
}
} else if (counterSet == (4*toWhichPosition + 0) || counterSet == (4*toWhichPosition + 1) || counterSet == (4*toWhichPosition + 2) || counterSet == (4*toWhichPosition + 3)) {
previously[counterSet] = 'black'
return previously[counterSet]
} else {
return previously[counterSet]
}
} else {
if (d == state) {
previously[counterSet] = "black"
return previously[counterSet]
} else {
return previously[counterSet]
}
}
})
this.flag = false
this.previousState = previously
var dotLabels = rows.selectAll('.dot-label')
.data(function(d){ return d.values })
var dotLabelEnter = dotLabels.enter().append('g')
.attr('class', 'dot-label')
.on('mouseover', function(d){
var selection = d3.select(this)
selection.select('rect').transition().duration(100).style('opacity', 1)
selection.select("text").transition().duration(100).style('opacity', 1)
})
.on('mouseout', function(d){
var selection = d3.select(this)
selection.select('rect').transition().style('opacity', 0)
selection.select("text").transition().style('opacity', 0)
})
dotLabelEnter.append('rect')
.style('fill', '#000000')
.style('opacity', 0)
dotLabelEnter.append('text')
.style('text-anchor', 'middle')
.style('fill', '#ffffff')
.style('opacity', 0)
dotLabels.exit().remove()
dotLabels
.attr('transform', function(d, i){ return 'translate(' + (i * maxR * 2) + ',' + (-maxR) + ')' })
.select('text')
.text(function(d){ return 'Step: '+d })
.attr('y', maxR + 4)
.attr('x', maxR)
dotLabels
.select('rect')
.attr('width', maxR * 2)
.attr('height', maxR * 2)
var xLabels = chart.selectAll('.xLabel')
.data(labelsX)
xLabels.enter().append('text')
.attr('y', xLabelHeight)
.attr('transform', 'translate(0,-6)')
.attr('class', 'xLabel')
.style('text-anchor', 'middle')
.style('fill-opacity', 0)
xLabels.exit()
.transition()
.duration(duration)
.style('fill-opacity', 0)
.remove()
xLabels.transition()
.text(function (d) { return d })
.duration(duration)
.attr('x', function(d, i){ return maxR * i * 2 + maxR + yLabelWidth - 2})
.style('fill-opacity', 1)
var yLabels = chart.selectAll('.yLabel')
.data(data, function(d){ return d.label })
yLabels.enter().append('text')
.text(function (d) { return d.label })
.attr('x', yLabelWidth)
.attr('class', 'yLabel')
.style('text-anchor', 'end')
.style('fill-opacity', 0)
yLabels.exit()
.transition()
.duration(duration)
.style('fill-opacity', 0)
.remove()
yLabels.transition()
.duration(duration)
.attr('y', function(d, i){ return maxR * i * 2 + maxR + xLabelHeight - 9 })
.attr('transform', 'translate(-6,' + maxR / 2.5 + ')')
.style('fill-opacity', 1)
var vert = chart.selectAll('.vert')
.data(labelsX)
vert.enter().append('line')
.attr('class', 'vert')
.attr('y1', xLabelHeight + borderWidth / 2)
.attr('stroke', '#888')
.attr('stroke-width', 1)
.style('shape-rendering', 'crispEdges')
.style('stroke-opacity', 0)
vert.exit()
.transition()
.duration(duration)
.style('stroke-opacity', 0)
.remove()
vert.transition()
.duration(duration)
.attr('x1', function(d, i){ return maxR * i * 2 + yLabelWidth })
.attr('x2', function(d, i){ return maxR * i * 2 + yLabelWidth })
.attr('y2', maxR * 2 * data.length + xLabelHeight - borderWidth / 2)
.style('stroke-opacity', function(d, i){ return i ? 1 : 0 })
var horiz = chart.selectAll('.horiz').
data(data, function(d){ return d.label })
horiz.enter().append('line')
.attr('class', 'horiz')
.attr('x1', yLabelWidth + borderWidth / 2)
.attr('stroke', '#888')
.attr('stroke-width', 1)
.style('shape-rendering', 'crispEdges')
.style('stroke-opacity', 0)
horiz.exit()
.transition()
.duration(duration)
.style('stroke-opacity', 0)
.remove()
horiz.transition()
.duration(duration)
.attr('x2', maxR * 2 * labelsX.length + yLabelWidth - borderWidth / 2)
.attr('y1', function(d, i){ return i * maxR * 2 + xLabelHeight })
.attr('y2', function(d, i){ return i * maxR * 2 + xLabelHeight })
.style('stroke-opacity', function(d, i){ return i ? 1 : 0 })
border.transition()
.duration(duration)
.attr('width', maxR * 2 * labelsX.length)
.attr('height', maxR * 2 * data.length)
},
initializeLinePLot () {
Plotly.purge('LinePlot')
this.scoresMean = []
this.scoresSTD = []
this.scoresMeanBest = []
this.scoresSTDBest = []
this.xaxis.push('Accuracy')
this.xaxis.push('Precision')
this.xaxis.push('Recall')
this.scoresMean.push((JSON.parse(this.ValidResultsVar[0])*100).toFixed(2))
this.scoresSTD.push((JSON.parse(this.ValidResultsVar[1])*100).toFixed(2))
this.scoresMean.push((JSON.parse(this.ValidResultsVar[2])*100).toFixed(2))
this.scoresSTD.push((JSON.parse(this.ValidResultsVar[3])*100).toFixed(2))
this.scoresMean.push((JSON.parse(this.ValidResultsVar[4])*100).toFixed(2))
this.scoresSTD.push((JSON.parse(this.ValidResultsVar[5])*100).toFixed(2))
this.scoresMeanBest.push((JSON.parse(this.ValidResultsVar[6])*100).toFixed(2))
this.scoresSTDBest.push((JSON.parse(this.ValidResultsVar[7])*100).toFixed(2))
this.scoresMeanBest.push((JSON.parse(this.ValidResultsVar[8])*100).toFixed(2))
this.scoresSTDBest.push((JSON.parse(this.ValidResultsVar[9])*100).toFixed(2))
this.scoresMeanBest.push((JSON.parse(this.ValidResultsVar[10])*100).toFixed(2))
this.scoresSTDBest.push((JSON.parse(this.ValidResultsVar[11])*100).toFixed(2))
var trace1 = {
x: this.xaxis,
y: this.scoresMean,
error_y: {
type: 'data',
array: this.scoresSTD,
visible: true
},
marker: {
color: "rgb(64,224,208)"
},
name: "Current",
type: "bar",
}
var trace2 = {
x: this.xaxis,
y: this.scoresMeanBest,
error_y: {
type: 'data',
array: this.scoresSTDBest,
visible: true
},
marker: {
color: "rgb(177,89,40)"
},
name: "Best",
type: "bar"
}
var DataforLinePlot = [trace1, trace2];
var layout = {
xaxis: {
gridcolor: "rgb(230,230,230)",
title: 'Validation metric',
tickformat: '.0f',
showgrid: true,
showline: false,
showticklabels: true,
tickcolor: "rgb(230,230,230)",
ticks: "outside",
zeroline: false
},
yaxis: {
gridcolor: "rgb(230,230,230)",
title: 'Performance (%)',
showgrid: true,
showline: false,
showticklabels: true,
tickcolor: "rgb(230,230,230)",
ticks: "outside",
zeroline: false
},
barmode: 'group',
autosize: false,
width: '395',
height: '300',
margin: {
l: 55,
r: 5,
b: 50,
t: 5,
pad: 5
},
legend:{
xanchor:"center",
yanchor:"top",
y:-0.3, // play with it
x:0.5, // play with it
orientation: "h"
}
}
var config = {displayModeBar: false, scrollZoom: true, displaylogo: false, showLink: false, showSendToCloud: false, modeBarButtonsToRemove: ['toImage'], responsive: true}
Plotly.newPlot('LinePlot', DataforLinePlot, layout, config)
},
reset () {
var svg = d3.select("#HistoryPlot");
svg.selectAll("*").remove();
Plotly.purge('LinePlot')
},
},
mounted () {
EventBus.$on('updateHistoryKey', data => { this.historyKey = data })
EventBus.$on('updateValuesofHistory', data => { this.whereIsChange = data })
EventBus.$on('addFeatureGen', data => { this.onHold = Object.values(data).length })
EventBus.$on('finalResults', data => { this.ValidResultsVar = data })
EventBus.$on('finalResults', this.initializeLinePLot)
EventBus.$on('quad', data => { this.featuresReceived = data })
EventBus.$on('finalResults', this.HistoryPun)
EventBus.$on('addFeatureGen', data => { this.keepFeaturesAddedGenRemoved = Object.values(data).length })
EventBus.$on('reset', this.reset)
}
}
</script>
<style>
text {
font-family: sans-serif;
fill: black;
font: 16px sans-serif;
cursor: default;
}
svg {
display: block;
}
.nodeHighlighted {
stroke: 'orange'
}
.modebar{
display: none !important;
}
body {
background-color: #fff;
}
.dot-label text {
font-size: 12px;
}
div#HistoryPlot {
height: 578px;
overflow: scroll;
}
</style>