diff --git a/__pycache__/run.cpython-38.pyc b/__pycache__/run.cpython-38.pyc index cc836d4..9fa50b8 100644 Binary files a/__pycache__/run.cpython-38.pyc and b/__pycache__/run.cpython-38.pyc differ diff --git a/frontend/src/components/FeatureSpaceDetail.vue b/frontend/src/components/FeatureSpaceDetail.vue index 17a84e6..fde7ee5 100644 --- a/frontend/src/components/FeatureSpaceDetail.vue +++ b/frontend/src/components/FeatureSpaceDetail.vue @@ -509,6 +509,7 @@ export default { var modeLoc = this.mode var selectionCounter = 0 + var IDsGather = [] var node = svg.append('g') .attr('class', 'nodes') @@ -521,7 +522,6 @@ export default { var numb = graph.nodes[i]['group'].match(/\d/g) numb = parseInt(numb.join("")) var items = document.getElementsByClassName(numb) - console.log(items) items.forEach( function (it) { it.childNodes[0].style.visibility = "hidden"; it.childNodes[1].setAttribute("transform", "translate(50,50) scale(0.3) rotate(180)"); @@ -547,15 +547,32 @@ export default { EventBus.$emit('brushLink', groupLoc-1) } else { var groupsColor = d3.select('#svg'+index)._groups['0'][0].childNodes[0].childNodes[1] + var regex = /\d+/g + var idLocal = parseInt(d3.select('#svg'+index)._groups['0'][0].getAttribute("id").match(regex)) if (groupsColor.getAttribute('fill') == "black") { if (selectionCounter < 3) { // add here the different states of comparison! (=2 and =3) groupsColor.setAttribute('fill', 'yellow') selectionCounter = selectionCounter + 1 + IDsGather.push(idLocal); + if (selectionCounter == 2) { + EventBus.$emit('CompareTwo', IDsGather) + } else if (selectionCounter == 3) { + EventBus.$emit('CompareThree', IDsGather) + } else { + + } } } else { groupsColor.setAttribute('fill', 'black') selectionCounter = selectionCounter - 1 + var index = IDsGather.indexOf(idLocal); + if (index > -1) { + IDsGather.splice(index, 1); + } + if (selectionCounter == 1) { + EventBus.$emit('Default') + } } } }) @@ -770,7 +787,6 @@ export default { .attr("fill", function(d) { return d.color}) .on("mouseover", function(d) { document.getElementsByClassName("bar"+d.class).forEach (function (element) { - console.log(element) element.setAttribute("fill", "yellow") }) d3.select(this) diff --git a/frontend/src/components/FeatureSpaceOverview.vue b/frontend/src/components/FeatureSpaceOverview.vue index 3808ef0..c8066d6 100644 --- a/frontend/src/components/FeatureSpaceOverview.vue +++ b/frontend/src/components/FeatureSpaceOverview.vue @@ -83,7 +83,7 @@ export default { var features = this.colorsReceive var activeLeafLoc = this.activeLeaf - var listofNodes = this.overallData[0] + var listofNodes = this.overallData[34] var featuresQuad1 = [] var featuresQuad2 = [] @@ -182,7 +182,7 @@ export default { var DURATION = 700; // d3 animation duration var STAGGERN = 4; // delay for each node var STAGGERD = 200; // delay for each depth - var NODE_DIAMETER = 4; // diameter of circular nodes + var NODE_DIAMETER = 6; // diameter of circular nodes var MIN_ZOOM = 0.5; // minimum zoom allowed var MAX_ZOOM = 10; // maximum zoom allowed var HAS_CHILDREN_COLOR = 'lightsteelblue'; diff --git a/frontend/src/components/Heatmap.vue b/frontend/src/components/Heatmap.vue index 93081a4..a1ee8a0 100644 --- a/frontend/src/components/Heatmap.vue +++ b/frontend/src/components/Heatmap.vue @@ -39,6 +39,7 @@ export default { smallScreenMode: '0px', dataFI: [], featureData: [], + generKey: [], } }, methods: { @@ -67,6 +68,7 @@ export default { // Clear Heatmap first var svg = d3.select("#Heatmap"); svg.selectAll("*").remove(); + var featureUni = JSON.parse(this.dataFI[0]) var algorithms = [] @@ -78,7 +80,12 @@ export default { var PermImpEli = JSON.parse(this.dataFI[1]) var FeaturesAccuracy = JSON.parse(this.dataFI[2]) - var Features = this.featureData[0] + + if (Object.entries(this.generKey).length == 0) { + var Features = this.featureData[0] + } else { + var Features = this.generKey + } let arr = Object.values(featureUni.Score); let minUni = Math.min(...arr); @@ -114,7 +121,16 @@ export default { } else if (algorithms[j] == "Average") { values[j] = ((((Object.values(featureUni.Score)[i]-minUni)/(maxUni-minUni)))+(PermImpEli[i][0])+(FeaturesAccuracy[i][0]))/(len-2) } else { - values[j] = -2 + if (Object.entries(this.generKey).length == 0) { + values[j] = -2 + } else { + if (i == 0 || i == 1) { + values[j] = -3 + } + else { + values[j] = -4 + } + } } data.push(values[j]) } @@ -288,7 +304,7 @@ export default { }) .attr("class", "row"); svg.append("text").attr("x", 10).attr("y", -65).text("Technique").style("font-size", "16px").attr("alignment-baseline","top") - svg.append("text").attr("transform", "rotate(-90)").attr("x", -33).attr("y", -50).style("text-anchor", "middle").style("font-size", "16px").text("Feature"); // -130 before for HeartC + svg.append("text").attr("transform", "rotate(-90)").attr("x", -33).attr("y", -75).style("text-anchor", "middle").style("font-size", "16px").text("Feature"); // -130 before for HeartC var heatMap = row.selectAll(".cell") .data(function(d) { return d; @@ -323,6 +339,8 @@ export default { .style("fill", function(d) { if (d == -1) return "url(#diagonalHatch)" else if (d == -2) return "yellow" + else if (d == -3) return "white" + else if (d == -4) return "url(#diagonalHatch)" else return colorScale(d) }) .on('mouseover', function(d, i, j) { @@ -346,6 +364,16 @@ export default { } EventBus.$emit('addFeature', featuresAddRem) return 'yellow' + } else if (d == -3) { + return 'white' + } else if (d == -4) { + svg.selectAll("rect").each(function(d){ + if (d == -4) { + d3.select(this).style("fill", "url(#diagonalHatch)") + } + }) + EventBus.$emit('addFeatureGen', [k]) + return 'yellow' } else { return colorScale(d) } @@ -355,7 +383,11 @@ export default { return "url(#diagonalHatch)" } } else { - return colorScale(d) + if (d == -3) { + return 'white' + } else { + return colorScale(d) + } } }) }); @@ -552,6 +584,8 @@ export default { } }, mounted () { + EventBus.$on('Generation', data => { this.generKey = data }) + EventBus.$on('HeatmapCall', data => { this.dataFI = data }) EventBus.$on('HeatmapCall', this.Heatmap) diff --git a/frontend/src/components/Main.vue b/frontend/src/components/Main.vue index 6143ff6..4abbfda 100755 --- a/frontend/src/components/Main.vue +++ b/frontend/src/components/Main.vue @@ -104,9 +104,14 @@ export default Vue.extend({ }, data () { return { + compareNumber: 0, + IDToCompare: [], + ImportanceCompare: [], + featureNames: [], initAuto: true, keySlider: true, featureAddRem: [], + featureAddRemGen: [], ValidResults: [], correlResulTranformed: [], PositiveValue: 75, @@ -114,13 +119,10 @@ export default Vue.extend({ unselectedRemainingPoints: [], Collection: 0, OverviewResults: 0, - preDataResults: '', DataResults: '', keyNow: 1, instancesImportance: '', RetrieveValueFile: 'IrisC', // this is for the default data set - ClassifierIDsList: [], - ClassifierIDsListCM: [], SelectedFeaturesPerClassifier: '', FinalResults: 0, selectedAlgorithm: '', @@ -426,7 +428,7 @@ export default Vue.extend({ EventBus.$emit('SlidersCall') this.keySlider = false } - //EventBus.$emit('ConfirmDataSet') // REMOVE THAT! + EventBus.$emit('ConfirmDataSet') // REMOVE THAT! } else { EventBus.$emit('dataSpace', this.correlResul) EventBus.$emit('quad', this.correlResul) @@ -455,8 +457,10 @@ export default Vue.extend({ } axios.get(path, axiosConfig) .then(response => { - console.log('Server successfully send the predictive results!') + console.log('Server successfully send the importances!') this.Importance = response.data.Importance + this.featureNames = [] + EventBus.$emit('Generation', this.featureNames) EventBus.$emit('HeatmapCall', this.Importance) this.returnResults() }) @@ -507,6 +511,74 @@ export default Vue.extend({ console.log(error) }) }, + ManipulFeatureGen () { + const path = `http://127.0.0.1:5000/data/AddRemGenFun` + const postData = { + featureAddRemGen: this.featureAddRemGen, + } + const axiosConfig = { + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token', + 'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE, OPTIONS' + } + } + axios.post(path, postData, axiosConfig) + .then(response => { + console.log('Sent an order to add or remove features!') + this.threshold() + }) + .catch(error => { + console.log(error) + }) + }, + Compare () { + const path = `http://127.0.0.1:5000/data/compareFun` + const postData = { + getIDs: this.IDToCompare, + compareNumber: this.compareNumber + } + const axiosConfig = { + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token', + 'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE, OPTIONS' + } + } + axios.post(path, postData, axiosConfig) + .then(response => { + console.log('Sent the features to compare!') + this.returnImportanceComp() + }) + .catch(error => { + console.log(error) + }) + }, + returnImportanceComp () { + const path = `http://127.0.0.1:5000/data/sendFeatImpComp` + + const axiosConfig = { + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token', + 'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE, OPTIONS' + } + } + axios.get(path, axiosConfig) + .then(response => { + console.log('Server successfully send the importances for comparison!') + this.ImportanceCompare = response.data.ImportanceCompare + this.featureNames = response.data.FeatureNames + EventBus.$emit('Generation', this.featureNames) + EventBus.$emit('HeatmapCall', this.ImportanceCompare) + }) + .catch(error => { + console.log(error) + }) + }, }, created () { // does the browser support the Navigation Timing API? @@ -538,6 +610,15 @@ export default Vue.extend({ alert('Handler for .unload() called.'); }) + EventBus.$on('CompareTwo', data => { this.IDToCompare = data }) + EventBus.$on('CompareTwo', data => { this.compareNumber = 1 }) + EventBus.$on('CompareTwo', this.Compare) + + EventBus.$on('CompareThree', data => { this.IDToCompare = data }) + EventBus.$on('CompareThree', data => { this.compareNumber = 2 }) + EventBus.$on('CompareThree', this.Compare) + + EventBus.$on('Default', this.returnImportance) EventBus.$on('ReturningBrushedPointsIDs', data => { this.modelsUpdate = data }) //EventBus.$on('ReturningBrushedPointsIDs', this.UpdateBarChartFeatures ) @@ -553,13 +634,8 @@ export default Vue.extend({ EventBus.$on('InitializeCrossoverMutation', this.sendPointsCrossMutat) EventBus.$on('ChangeKey', data => { this.keyNow = data }) - EventBus.$on('SendSelectedPointsUpdateIndicator', data => { this.ClassifierIDsList = data }) - EventBus.$on('SendSelectedPointsUpdateIndicator', this.SelectedPoints) EventBus.$on('sendToServerSelectedScatter', this.SendSelectedPointsToServer) - EventBus.$on('SendSelectedPointsUpdateIndicatorCM', data => { this.ClassifierIDsListCM = data }) - EventBus.$on('SendSelectedPointsUpdateIndicatorCM', this.SelectedPointsCM) - EventBus.$on('SendSelectedDataPointsToServerEvent', data => { this.DataPointsSel = data }) EventBus.$on('SendSelectedDataPointsToServerEvent', this.SendSelectedDataPointsToServer) EventBus.$on('SendSelectedFeaturesEvent', data => { this.SelectedFeaturesPerClassifier = data }) @@ -598,6 +674,9 @@ export default Vue.extend({ EventBus.$on('addFeature', this.ManipulFeature) EventBus.$on('removeFeatures', this.ManipulFeature) + EventBus.$on('addFeatureGen', data => { this.featureAddRemGen = data }) + EventBus.$on('addFeatureGen', this.ManipulFeatureGen) + //Prevent double click to search for a word. document.addEventListener('mousedown', function (event) { if (event.detail > 1) { diff --git a/frontend/src/components/Results.vue b/frontend/src/components/Results.vue index f28f982..a9ded34 100644 --- a/frontend/src/components/Results.vue +++ b/frontend/src/components/Results.vue @@ -60,7 +60,7 @@ export default { var color = JSON.parse(this.ValidResultsVar[12]) var data = [] - var features = this.featuresReceived[33] + var features = this.featuresReceived[35] var labelsX = ['Add', 'Remove', 'Combine', 'Round'] for (let i=0; i< features.length; i++) { data.push({ @@ -82,9 +82,9 @@ export default { // return f(d) // } - var c = d3.scale.ordinal() - .domain([0, 1]) - .range(["#D3D3D3", "#b15928"]); + 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 }) @@ -129,13 +129,13 @@ export default { if (testLoc) { if (d == state) { previously.push(c(color)) - return c(color); + return '#B15928' } else { previously.push(c(0)) - return c(0) + return 'rgb(' + c(d) + ',' + c(d) + ',' + c(d) + ')' } } else { - return c(0) + return 'rgb(' + c(d) + ',' + c(d) + ',' + c(d) + ')' } }) diff --git a/run.py b/run.py index 4da71ba..0b8a448 100644 --- a/run.py +++ b/run.py @@ -110,6 +110,12 @@ def reset(): global target_namesLoc target_namesLoc = [] + + global featureCompareData + featureCompareData = [] + + global columnsKeep + columnsKeep = [] return 'The reset was done!' # retrieve data from client and select the correct data set @@ -199,9 +205,14 @@ def retrieveFileName(): keyFirstTime = True global target_namesLoc - target_namesLoc = [] + global featureCompareData + featureCompareData = [] + + global columnsKeep + columnsKeep = [] + DataRawLength = -1 DataRawLengthTest = -1 data = json.loads(fileName) @@ -379,13 +390,15 @@ def dataSetSelection(): global XData, yData, RANDOM_SEED XData, yData = ArrayDataResults, AllTargetsFloatValues + XData.columns = [str(col) + ' (F'+str(idx+1)+')' for idx, col in enumerate(XData.columns)] + global XDataStored, yDataStored XDataStored = XData.copy() yDataStored = yData.copy() warnings.simplefilter('ignore') - executeModel([]) + executeModel([], 0) return 'Everything is okay' @@ -400,7 +413,7 @@ def create_global_function(): return np.mean(result['test_score']) # check this issue later because we are not getting the same results -def executeModel(exeCall): +def executeModel(exeCall, flagEx): global keyFirstTime global estimator @@ -412,6 +425,8 @@ def executeModel(exeCall): global previousState scores = [] + XData = XDataStored.copy() + if (keyFirstTime): create_global_function() params = {"C": (0.0001, 10000), "gamma": (0.0001, 10000)} @@ -419,12 +434,20 @@ def executeModel(exeCall): svc_bayesopt.maximize(init_points=130, n_iter=20, acq='ucb') bestParams = svc_bayesopt.max['params'] estimator = SVC(C=bestParams.get('C'), gamma=bestParams.get('gamma'), probability=True, random_state=RANDOM_SEED) - featureImportanceData = estimatorFeatureSelection(estimator) + featureImportanceData = estimatorFeatureSelection(XData, estimator) - XData = XDataStored.copy() if (len(exeCall) != 0): - XData = XData.drop(XData.columns[exeCall], axis=1) - + if (flagEx == 1): + XData = XData.drop(XData.columns[exeCall], axis=1) + else: + columnsKeepNew = [] + columns = XDataGen.columns.values.tolist() + for indx, col in enumerate(columns): + if indx in exeCall: + columnsKeepNew.append(col) + XDataTemp = XDataGen[columnsKeepNew] + XData[columnsKeepNew] = XDataTemp.values + print(XData) estimator.fit(XData, yData) yPredict = estimator.predict(XData) yPredictProb = cross_val_predict(estimator, XData, yData, cv=crossValidation, method='predict_proba') @@ -465,24 +488,24 @@ def executeModel(exeCall): return 'Everything Okay' -def estimatorFeatureSelection(clf): +def estimatorFeatureSelection(Data, clf): resultsFS = [] permList = [] PerFeatureAccuracy = [] PerFeatureAccuracyAll = [] - perm = PermutationImportance(clf, cv = None, refit = True, n_iter = 25).fit(XData, yData) + perm = PermutationImportance(clf, cv = None, refit = True, n_iter = 25).fit(Data, yData) permList.append(perm.feature_importances_) - n_feats = XData.shape[1] + n_feats = Data.shape[1] PerFeatureAccuracy = [] for i in range(n_feats): - scores = model_selection.cross_val_score(clf, XData.values[:, i].reshape(-1, 1), yData, cv=crossValidation) + scores = model_selection.cross_val_score(clf, Data.values[:, i].reshape(-1, 1), yData, cv=crossValidation) PerFeatureAccuracy.append(scores.mean()) PerFeatureAccuracyAll.append(PerFeatureAccuracy) - clf.fit(XData, yData) - yPredict = clf.predict(XData) + clf.fit(Data, yData) + yPredict = clf.predict(Data) yPredict = np.nan_to_num(yPredict) perm_imp_eli5PD = pd.DataFrame(permList) @@ -492,9 +515,9 @@ def estimatorFeatureSelection(clf): PerFeatureAccuracyPandas = PerFeatureAccuracyPandas.to_json() bestfeatures = SelectKBest(score_func=chi2, k='all') - fit = bestfeatures.fit(XData,yData) + fit = bestfeatures.fit(Data,yData) dfscores = pd.DataFrame(fit.scores_) - dfcolumns = pd.DataFrame(XData.columns) + dfcolumns = pd.DataFrame(Data.columns) featureScores = pd.concat([dfcolumns,dfscores],axis=1) featureScores.columns = ['Specs','Score'] #naming the dataframe columns featureScores = featureScores.to_json() @@ -514,6 +537,17 @@ def sendFeatureImportance(): } return jsonify(response) +@app.route('/data/sendFeatImpComp', methods=["GET", "POST"]) +def sendFeatureImportanceComp(): + global featureCompareData + global columnsKeep + + response = { + 'ImportanceCompare': featureCompareData, + 'FeatureNames': columnsKeep + } + return jsonify(response) + def solve(sclf,XData,yData,crossValidation,scoringIn,loop): scoresLoc = [] temp = model_selection.cross_val_score(sclf, XData, yData, cv=crossValidation, scoring=scoringIn, n_jobs=-1) @@ -1060,6 +1094,16 @@ def Seperation(): global packCorr packCorr = [] + AbbreviatedFeatures = [] + for index, value in enumerate(XData.columns.values.tolist()): + realIndex = index + 1 + AbbreviatedFeatures.append('F'+str(realIndex)) + + AbbreviatedFeaturesOriginal = [] + for index, value in enumerate(XDataStored.columns.values.tolist()): + realIndex = index + 1 + AbbreviatedFeaturesOriginal.append('F'+str(realIndex)) + packCorr.append(list(XData.columns.values.tolist())) packCorr.append(json.dumps(target_names)) packCorr.append(json.dumps(probabilityPredictions)) @@ -1101,6 +1145,8 @@ def Seperation(): packCorr.append(json.dumps(MI5List)) packCorr.append(list(XDataStored.columns.values.tolist())) + packCorr.append(AbbreviatedFeatures) + packCorr.append(AbbreviatedFeaturesOriginal) return 'Everything Okay' @@ -1140,5 +1186,55 @@ def ManipulFeat(): featureProcess = request.get_data().decode('utf8').replace("'", '"') featureProcess = json.loads(featureProcess) featureProcessExtract = featureProcess['featureAddRem'] - executeModel(featureProcessExtract) + executeModel(featureProcessExtract, 1) + return 'Okay' + +@cross_origin(origin='localhost',headers=['Content-Type','Authorization']) +@app.route('/data/AddRemGenFun', methods=["GET", "POST"]) +def ManipulFeatGen(): + featureProcess = request.get_data().decode('utf8').replace("'", '"') + featureProcess = json.loads(featureProcess) + featureProcessExtract = featureProcess['featureAddRemGen'] + executeModel(featureProcessExtract, 2) + return 'Okay' + +@cross_origin(origin='localhost',headers=['Content-Type','Authorization']) +@app.route('/data/compareFun', methods=["GET", "POST"]) +def CompareFunPy(): + global featureCompareData + global columnsKeep + global XDataGen + global IDsToCompare + + retrieveComparison = request.get_data().decode('utf8').replace("'", '"') + retrieveComparison = json.loads(retrieveComparison) + compareMode = retrieveComparison['compareNumber'] + IDsToCompare = retrieveComparison['getIDs'] + XDataGen = XDataStored.copy() + columns = XData.columns.values.tolist() + columnsKeep = [] + columnsKeepID = [] + for indx, col in enumerate(columns): + if indx in IDsToCompare: + columnsKeep.append(col) + columnsKeepID.append(str(indx+1)) + if (compareMode == 1): + XDataGen = XData[columnsKeep] + feat1 = XDataGen.iloc[:,0] + feat2 = XDataGen.iloc[:,1] + XDataGen['F'+columnsKeepID[0]+'+F'+columnsKeepID[1]] = feat1 + feat2 + XDataGen['|F'+columnsKeepID[0]+'-F'+columnsKeepID[1]+'|'] = abs(feat1 - feat2) + XDataGen['F'+columnsKeepID[0]+'xF'+columnsKeepID[1]] = feat1 + feat2 + XDataGen['F'+columnsKeepID[0]+'/F'+columnsKeepID[1]] = feat1 / feat2 + XDataGen['F'+columnsKeepID[1]+'/F'+columnsKeepID[0]] = feat2 / feat1 + columnsKeep.append('F'+columnsKeepID[0]+'+F'+columnsKeepID[1]) + columnsKeep.append('|F'+columnsKeepID[0]+'-F'+columnsKeepID[1]+'|') + columnsKeep.append('F'+columnsKeepID[0]+'xF'+columnsKeepID[1]) + columnsKeep.append('F'+columnsKeepID[0]+'/F'+columnsKeepID[1]) + columnsKeep.append('F'+columnsKeepID[1]+'/F'+columnsKeepID[0]) + elif (compareMode == 2): + pass + else: + pass + featureCompareData = estimatorFeatureSelection(XDataGen, estimator) return 'Okay' \ No newline at end of file