@ -1,30 +1,12 @@
< template >
< div >
< label id = "data" for = "param-dataset" data -toggle = " tooltip " data -placement = " right " title = "Tip: use one of the data sets already provided or upload a new file." > { { dataset } } < / label >
< select id = "selectFile" @change ="selectDataSet()" >
< option value = "HeartC.csv" selected > Heart Disease < / option >
< option value = "IrisC.csv" > Iris < / option >
< option value = "local" > Upload New File < / option >
< / select >
< button class = "btn-outline-success"
id = "initializeID"
v - on : click = "initialize" >
< font -awesome -icon icon = "search" / >
{ { searchText } }
< / button >
< button class = "btn-outline-danger"
id = "resetID"
v - on : click = "reset" >
< font -awesome -icon icon = "trash" / >
{ { resetText } }
< / button >
< div class = "column" >
< div id = "FeatureGraph3" > < / div >
< / div >
< / template >
< script >
import Papa from 'papaparse'
import { EventBus } from '../main.js'
import { $ , jQuery } from 'jquery' ;
import * as greadability from '../greadability.js'
import * as d3Base from 'd3'
/ / a t t a c h a l l d 3 p l u g i n s t o t h e d 3 l i b r a r y
@ -34,53 +16,487 @@ export default {
name : 'FeatureSpace3' ,
data ( ) {
return {
defaultDataSet : 'HeartC' , / / d e f a u l t v a l u e f o r t h e f i r s t d a t a s e t
searchText : 'Hyper-parameter search' ,
resetText : 'Reset' ,
dataset : 'Data set'
dataFS3 : [ ] ,
jsonData : [ ] ,
}
} ,
methods : {
selectDataSet ( ) {
const fileName = document . getElementById ( 'selectFile' )
this . defaultDataSet = fileName . options [ fileName . selectedIndex ] . value
this . defaultDataSet = this . defaultDataSet . split ( '.' ) [ 0 ]
if ( this . defaultDataSet == "DiabetesC" || this . defaultDataSet == "HeartC" || this . defaultDataSet == "IrisC" || this . defaultDataSet == "StanceC" ) { / / T h i s i s a f u n c t i o n t h a t h a n d l e s a n e w f i l e , w h i c h u s e r s c a n u p l o a d .
this . dataset = "Data set"
d3 . select ( "#data" ) . select ( "input" ) . remove ( ) ; / / R e m o v e t h e s e l e c t i o n f i e l d .
EventBus . $emit ( 'SendToServerDataSetConfirmation' , this . defaultDataSet )
} else {
EventBus . $emit ( 'SendToServerDataSetConfirmation' , this . defaultDataSet )
d3 . select ( "#data" ) . select ( "input" ) . remove ( ) ;
this . dataset = ""
var data
d3 . select ( "#data" )
. append ( "input" )
. attr ( "type" , "file" )
. style ( "font-size" , "18.5px" )
. style ( "width" , "200px" )
. on ( "change" , function ( ) {
var file = d3 . event . target . files [ 0 ] ;
Papa . parse ( file , {
header : true ,
dynamicTyping : true ,
skipEmptyLines : true ,
complete : function ( results ) {
data = results . data ;
EventBus . $emit ( 'SendToServerLocalFile' , data )
initializeNetwork ( ) {
var listofNodes = this . dataFS3 [ 0 ]
var dataLoc = JSON . parse ( this . dataFS3 [ 4 ] )
var nodes = [ ]
listofNodes . forEach ( element => nodes . push ( { "name" : element } ) )
var links = [ ]
Object . entries ( dataLoc ) . forEach (
function ( [ feature , value ] ) {
Object . entries ( value ) . forEach ( function ( [ featureInside , value ] ) {
if ( feature != featureInside ) {
if ( value >= 0 ) {
links . push ( { "source" : listofNodes . indexOf ( feature ) , "target" : listofNodes . indexOf ( featureInside ) , "value" : Math . abs ( value ) * 30 , "group" : 1 } )
} else {
links . push ( { "source" : listofNodes . indexOf ( feature ) , "target" : listofNodes . indexOf ( featureInside ) , "value" : Math . abs ( value ) * 30 , "group" : 2 } )
}
}
} )
} )
this . jsonData = { "nodes" : nodes , "links" : links } ;
this . graphVizualization ( )
} ,
graphVizualization ( ) {
var listofNodes = this . dataFS3 [ 0 ]
var uniqueTarget = JSON . parse ( this . dataFS3 [ 16 ] )
var corrTarget = JSON . parse ( this . dataFS3 [ 8 ] )
var corrGlob = JSON . parse ( this . dataFS3 [ 12 ] )
var VIFVar = JSON . parse ( this . dataFS3 [ 20 ] )
var MIVar = JSON . parse ( this . dataFS3 [ 24 ] )
var colorCateg = d3 . scaleOrdinal ( d3 . schemeAccent )
var corrTargetFormatted = [ ]
for ( let i = 0 ; i < Object . keys ( corrTarget ) . length ; i ++ ) {
var corrTargetFormattedLoc = [ ]
for ( let j = 0 ; j < Object . keys ( corrTarget [ i ] ) . length ; j ++ ) {
if ( j > uniqueTarget . length - 1 ) {
corrTargetFormattedLoc . push ( Math . round ( Object . values ( corrTarget [ i ] ) [ j ] * 100 ) )
}
}
corrTargetFormatted . push ( corrTargetFormattedLoc )
}
var corrGlobFormatted = [ ]
for ( let i = 0 ; i < Object . keys ( corrGlob ) . length ; i ++ ) {
if ( i != 0 ) {
corrGlobFormatted . push ( Math . round ( Object . values ( corrGlob ) [ i ] [ '0' ] * 100 ) )
}
}
var VIFVarFormatted = [ ]
for ( let i = 0 ; i < Object . keys ( VIFVar ) . length ; i ++ ) {
if ( i != 0 ) {
if ( Object . values ( VIFVar ) [ i ] > 10 ) {
VIFVarFormatted . push ( 4 )
} else if ( Object . values ( VIFVar ) [ i ] > 5 ) {
VIFVarFormatted . push ( 2 )
} else {
VIFVarFormatted . push ( 0 )
}
}
}
function min ( input ) {
if ( toString . call ( input ) !== "[object Array]" )
return false ;
return Math . min . apply ( null , input ) ;
}
function max ( input ) {
if ( toString . call ( input ) !== "[object Array]" )
return false ;
return Math . max . apply ( null , input ) ;
}
function normalize ( min , max ) {
var delta = max - min ;
return function ( val ) {
return ( val - min ) / delta ;
} ;
}
var MIMin = min ( MIVar )
var MIMax = max ( MIVar )
MIVar = MIVar . map ( normalize ( MIMin , MIMax ) )
var colorsScaleNodes = d3 . scaleLinear ( )
. domain ( [ MIMin , MIMax ] )
. range ( [ '#6baed6' , '#4292c6' , '#2171b5' , '#08519c' , '#08306b' ] ) ;
var svg = d3 . select ( "#FeatureGraph3" ) ;
svg . selectAll ( "*" ) . remove ( ) ;
var width = 800 ;
var height = 500 ;
var numTicks = 200 ;
var selectedParams ;
var bestParams ;
var dispatch = d3 . dispatch ( 'layoutend' ) ;
svg = d3 . select ( "#FeatureGraph3" ) . append ( "svg" )
. attr ( "width" , width )
. attr ( "height" , height ) ;
var graph = this . jsonData
var link = svg . append ( 'g' )
. attr ( 'class' , 'links' )
. selectAll ( 'line' )
. data ( graph . links )
. enter ( ) . append ( 'line' )
. attr ( "stroke-width" , function ( d ) { return Math . sqrt ( d . value ) ; } ) ;
var node = svg . append ( 'g' )
. attr ( 'class' , 'nodes' )
. selectAll ( 'g' )
. data ( graph . nodes )
. enter ( ) . append ( 'g' )
var paramGroups = [
{ name : 'chargeStrength' , values : [ - 30 , - 80 ] } ,
{ name : 'linkDistance' , values : [ 30 , - 80 ] } ,
{ name : 'linkStrength' , values : [ 0 , 1 ] } ,
{ name : 'gravity' , values : [ 0 , 0.5 ] } ,
{ name : 'iterations' , values : [ 1 , 2 ] } ,
{ name : 'alphaDecay' , values : [ 0 , 0.0228 , 0.05 ] } ,
{ name : 'velocityDecay' , values : [ 0.4 , 0.8 ] }
] ;
var paramList = generateParams ( paramGroups ) ;
var bestSoFar = d3 . select ( '.best' ) . selectAll ( 'li' )
. data ( paramGroups . map ( function ( d ) { return d . name ; } ) )
. enter ( ) . append ( 'li' )
. text ( function ( d ) { return d ; } ) ;
dispatch . on ( 'layoutend' , function ( params , i ) {
if ( ! bestParams || params . graphReadability > bestParams . graphReadability ) {
bestParams = params ;
selectedParams = bestParams ;
bestSoFar
. data ( d3 . map ( bestParams ) . keys ( ) . filter ( function ( d ) { return d !== 'positions' && d !== 'graphReadability' ; } ) )
. text ( function ( d ) { return d + ' = ' + bestParams [ d ] ; } ) ;
}
} ) ;
var i = 0 ;
var stepper = d3 . timer ( function ( ) {
var p = paramList [ i ] ;
var forceSim = getForceSimFromParams ( p ) ;
/ / R e s e t n o d e a t t r i b u t e s .
graph . nodes . forEach ( function ( n ) {
n . x = n . y = n . vx = n . vy = 0 ;
} ) ;
forceSim . nodes ( graph . nodes )
. stop ( ) ;
forceSim . force ( 'link' )
. links ( graph . links ) ;
for ( var t = 0 ; t < numTicks ; ++ t ) {
forceSim . tick ( ) ;
}
p . graphReadability = greadability . greadability ( graph . nodes , graph . links ) ;
p . graphReadability = ( p . graphReadability . crossing + p . graphReadability . crossingAngle +
p . graphReadability . angularResolutionMin + p . graphReadability . angularResolutionDev ) / 4
p . positions = graph . nodes . map ( function ( n ) { return { x : n . x , y : n . y } ; } ) ;
dispatch . call ( 'layoutend' , forceSim , p , i ) ;
++ i ;
if ( i >= paramList . length ) {
var widthLoc = 100 ;
var arcSize = ( 6 * widthLoc / 100 ) ;
var innerRadius = arcSize * 2 ;
var svgLoc = node . append ( 'svg' ) . attr ( 'width' , widthLoc ) . attr ( 'height' , widthLoc )
. attr ( "id" , function ( d , i ) { return "svg" + ( listofNodes . length * 2 + i ) ; } )
graph . nodes . forEach ( function ( itemVal , indexNode ) {
/ / v a r d a t a = [ [
/ / { v a l u e : 7 0 , l a b e l : " " , c o l o r : ' # f f 0 0 0 0 ' , l c o l o r : ' ' } ,
/ / { v a l u e : 3 3 , l a b e l : " " , c o l o r : ' # 0 0 f f 0 0 ' , l c o l o r : ' ' } ,
/ / { v a l u e : 1 0 0 , l a b e l : " 4 4 . 5 " , c o l o r : ' # 0 0 0 0 0 0 ' , l c o l o r : ' b l a c k ' }
/ / ] ; ]
var data = [ ]
for ( let k = 0 ; k < uniqueTarget . length ; k ++ ) {
data . push ( { value : corrTargetFormatted [ k ] [ indexNode ] , label : '' , color : colorCateg ( uniqueTarget [ k ] ) , lcolor : '' } )
}
var length = data . length
data . push ( { value : 100 , label : corrGlobFormatted [ indexNode ] , color : '#000000' , lcolor : colorsScaleNodes ( MIVar [ indexNode ] ) } )
var border = VIFVarFormatted [ indexNode ]
var arcs = data . map ( function ( obj , i ) {
if ( i == length ) {
return d3 . arc ( ) . innerRadius ( i * arcSize + innerRadius ) . outerRadius ( ( i + 1 ) * arcSize - ( widthLoc / 100 ) + innerRadius + border ) ;
} else {
return d3 . arc ( ) . innerRadius ( i * arcSize + innerRadius ) . outerRadius ( ( i + 1 ) * arcSize - ( widthLoc / 100 ) + innerRadius ) ;
}
} ) ;
var arcsGrey = data . map ( function ( obj , i ) {
return d3 . arc ( ) . innerRadius ( i * arcSize + ( innerRadius + ( ( arcSize / 2 ) - 2 ) ) ) . outerRadius ( ( i + 1 ) * arcSize - ( ( arcSize / 2 ) ) + ( innerRadius ) ) ;
} ) ;
var pieData = data . map ( function ( obj , i ) {
return [
{ value : obj . value , arc : arcs [ i ] , object : obj } ,
{ value : ( 100 - obj . value ) , arc : arcsGrey [ i ] , object : obj } ,
{ value : 0 , arc : arcs [ i ] , object : obj } ] ;
} ) ;
var pie = d3 . pie ( ) . sort ( null ) . value ( function ( d ) {
return d . value ;
} ) ;
var id = listofNodes . length * 2 + indexNode
var g = d3 . select ( '#svg' + id ) . selectAll ( 'g' ) . data ( pieData ) . enter ( )
. append ( 'g' )
. attr ( 'transform' , 'translate(' + widthLoc / 2 + ',' + widthLoc / 2 + ') rotate(180)' ) ;
var gText = d3 . select ( '#svg' + id ) . selectAll ( 'g.textClass' ) . data ( [ { } ] ) . enter ( )
. append ( 'g' )
. classed ( 'textClass' , true )
. attr ( 'transform' , 'translate(' + widthLoc / 2 + ',' + widthLoc / 2 + ') rotate(180)' ) ;
g . selectAll ( 'path' ) . data ( function ( d ) {
return pie ( d ) ;
} ) . enter ( ) . append ( 'path' )
. attr ( 'id' , function ( d , i ) {
if ( i == 1 ) {
return "Text" + d . data . object . label
}
} )
. attr ( 'd' , function ( d ) {
return d . data . arc ( d ) ;
} ) . attr ( 'fill' , function ( d , i ) {
return i == 0 ? d . data . object . color : i == 1 ? '#D3D3D3' : 'none' ;
} ) ;
g . each ( function ( d , index ) {
var el = d3 . select ( this ) ;
var path = el . selectAll ( 'path' ) . each ( function ( r , i ) {
if ( i === 1 ) {
var centroid = r . data . arc . centroid ( {
startAngle : r . startAngle + 0.05 ,
endAngle : r . startAngle + 0.001 + 0.05
} ) ;
var lableObj = r . data . object ;
g . append ( 'text' )
. attr ( 'font-size' , ( ( 2 * width ) / 100 ) )
. attr ( 'dominant-baseline' , 'central' )
. append ( "textPath" )
. attr ( "textLength" , function ( d , i ) {
return 0 ;
} )
. attr ( "startOffset" , '5' )
. attr ( "dy" , '-3em' )
. text ( lableObj . value + '%' ) ;
}
if ( i === 0 ) {
var centroidText = r . data . arc . centroid ( {
startAngle : r . startAngle ,
endAngle : r . startAngle
} ) ;
var lableObj = r . data . object ;
gText . append ( 'text' )
. attr ( 'font-size' , ( ( 2 * width ) / 100 ) )
. text ( lableObj . label )
. style ( 'fill' , lableObj . lcolor )
. attr ( 'transform' , "translate(" + ( 10 ) + "," + ( 0 + ") rotate(" + ( 180 ) + ")" ) )
. attr ( 'dominant-baseline' , 'central' ) ;
}
} ) ;
} ) ;
} )
var drag _handler = d3 . drag ( )
. on ( "start" , drag _start )
. on ( "drag" , drag _drag )
. on ( "end" , drag _end ) ;
drag _handler ( node ) ;
var labels = node . append ( "text" )
. text ( function ( d ) {
return d . name ;
} )
. attr ( 'x' , 20 )
. attr ( 'y' , 8 ) ;
node . append ( 'title' ) . text ( function ( d ) { return d . name ; } ) ;
/ / a d d z o o m c a p a b i l i t i e s
var zoom _handler = d3 . zoom ( )
. on ( "zoom" , zoom _actions ) ;
zoom _handler ( svg ) ;
drawGraph ( ) ;
/ / Z o o m f u n c t i o n s
function zoom _actions ( ) {
svg . attr ( "transform" , d3 . event . transform )
}
} ) ;
} )
}
} ,
reset ( ) {
EventBus . $emit ( 'reset' )
EventBus . $emit ( 'alternateFlagLock' )
function drag _start ( d ) {
if ( ! d3 . event . active ) forceSim . alphaTarget ( 0.3 ) . restart ( ) ;
d . fx = d . x ;
d . fy = d . y ;
}
/ / m a k e s u r e y o u c a n ' t d r a g t h e c i r c l e o u t s i d e t h e b o x
function drag _drag ( d ) {
d . fx = d3 . event . x ;
d . fy = d3 . event . y ;
tickActions ( ) ;
}
function drag _end ( d ) {
if ( ! d3 . event . active ) forceSim . alphaTarget ( 0 ) ;
d . fx = null ;
d . fy = null ;
}
stepper . stop ( ) ;
}
} ) ;
function tickActions ( ) {
link
. attr ( 'x1' , function ( d ) { return d . source . x ; } )
. attr ( 'x2' , function ( d ) { return d . target . x ; } )
. attr ( 'y1' , function ( d ) { return d . source . y ; } )
. attr ( 'y2' , function ( d ) { return d . target . y ; } ) ;
node
. attr ( "id" , function ( d , i ) { return "g" + ( listofNodes . length * 2 + i ) ; } )
. attr ( "transform" , function ( d , i ) {
d . x = d . x - 50
d . y = d . y - 50
return "translate(" + d . x + "," + d . y + ")" ;
} )
} ;
function drawGraph ( ) {
graph . nodes . forEach ( function ( n , i ) {
n . x = selectedParams . positions [ i ] . x ;
n . y = selectedParams . positions [ i ] . y ;
} ) ;
var xDistance = d3 . extent ( graph . nodes , function ( n ) { return n . x ; } ) ;
var xMin = xDistance [ 0 ] ;
xDistance = xDistance [ 1 ] - xDistance [ 0 ] ;
var yDistance = d3 . extent ( graph . nodes , function ( n ) { return n . y ; } ) ;
var yMin = yDistance [ 0 ] ;
yDistance = yDistance [ 1 ] - yDistance [ 0 ] ;
graph . nodes . forEach ( function ( n , i ) {
n . x = ( height - 10 ) * ( n . x - xMin ) / Math . max ( xDistance , yDistance ) ;
n . y = ( height - 10 ) * ( n . y - yMin ) / Math . max ( xDistance , yDistance ) ;
} ) ;
xDistance = d3 . extent ( graph . nodes , function ( n ) { return n . x ; } ) ;
var xMid = ( xDistance [ 1 ] + xDistance [ 0 ] ) / 2 ;
yDistance = d3 . extent ( graph . nodes , function ( n ) { return n . y ; } ) ;
var yMid = ( yDistance [ 1 ] - yDistance [ 0 ] ) / 2 ;
graph . nodes . forEach ( function ( n , i ) {
n . x = n . x + width / 2 - xMid ;
n . y = n . y + height / 2 - yMid ;
} ) ;
tickActions ( ) ;
}
function generateParams ( paramGroups , paramList , currParam ) {
var p = paramGroups [ 0 ] ;
if ( ! paramList ) paramList = [ ] ;
if ( ! currParam ) currParam = { } ;
p . values . forEach ( function ( v ) {
var setting = { } ;
setting [ p . name ] = v ;
if ( paramGroups . length === 1 ) {
paramList . push ( Object . assign ( setting , currParam ) ) ;
} else {
generateParams ( paramGroups . slice ( 1 ) , paramList , Object . assign ( setting , currParam ) ) ;
}
} ) ;
return paramList ;
}
function getForceSimFromParams ( params ) {
var forceSim = d3 . forceSimulation ( )
. force ( 'link' , d3 . forceLink ( ) . iterations ( params . iterations ) )
. force ( 'charge' , d3 . forceManyBody ( ) . strength ( params . chargeStrength ) )
. force ( 'x' , d3 . forceX ( 0 ) . strength ( params . gravity ) )
. force ( 'y' , d3 . forceY ( 0 ) . strength ( params . gravity ) )
. force ( 'center' , d3 . forceCenter ( 0 , 0 ) )
. alphaDecay ( params . alphaDecay )
. velocityDecay ( params . velocityDecay ) ;
if ( params . linkStrength !== null ) {
forceSim . force ( 'link' ) . strength ( params . linkStrength ) ;
}
return forceSim ;
}
} ,
reset ( ) {
var svg = d3 . select ( "#FeatureGraph3" ) ;
svg . selectAll ( "*" ) . remove ( ) ;
} ,
} ,
initialize ( ) {
EventBus . $emit ( 'ConfirmDataSet' )
}
mounted ( ) {
EventBus . $on ( 'quad3' , data => { this . dataFS3 = data } )
EventBus . $on ( 'quad3' , this . initializeNetwork )
}
}
< / script >
< style >
text {
font - family : sans - serif ;
}
svg {
display : block ;
}
. links line {
stroke : # D3D3D3 ;
stroke - opacity : 0.6 ;
}
. nodes circle {
fill : # 000000 ;
stroke : # fff ;
stroke - width : 1 px ;
}
. column {
float : left ;
margin : 0 10 px ;
}
< / style >