t-viSNE: Interactive Assessment and Interpretation of t-SNE Projections https://doi.org/10.1109/TVCG.2020.2986996
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.
 
 
 
 
 
t-viSNE/js/tsne_vis.js

2816 lines
88 KiB

// t-SNE.js object and other global variables
var toggleValue = false; var k; var points = []; var all_fields; var pointsbeta = []; var KNNEnabled = true;
// These are the dimensions for the square shape of the main panel\
var dimensions = document.getElementById('modtSNEcanvas').offsetWidth;
// These are the dimensions for the overview panel
var dim = document.getElementById('tSNEcanvas').offsetWidth;
var format; var new_file; var opt; var step_counter; var final_dataset; var max_counter; var dists; var dists2d; var all_labels; var runner; var tsne; var count_canvas = 0; var x_position = []; var y_position = []; var x_position2 = []; var y_position2 = []; var cost_each; var beta_all = [];
var points2d = []; var ArrayContainsDataFeatures = []; var ArrayContainsDataFeaturesCleared = [];
var InitialStatePoints = [];
function getfile(file){
new_file = file; //uploaded file data
}
// Parse data
var getData = function() {
// form controls
var value = document.getElementById("param-dataset").value;
format = document.getElementById("param-dataset").value.split("."); //get the actual format
if (format[value.split(".").length-1] == "csv") {
parseData("./data/"+value);
}else{
parseData(new_file, init);
}
};
function parseData(url) {
Papa.parse(url, { //for csv file!
download: true,
header: true,
dynamicTyping: true,
skipEmptyLines: true,
complete: function(results) {
results.data = results.data.filter(function (el) {
var counter = 0;
for(key in el) {
if(el.hasOwnProperty(key)) {
var value = el[key];
if (key === 'name'){
}else{
if(typeof(value) !== 'number' || value === undefined || key === "Version"){ //add more limitations if needed!
delete el[key];
}else{
el[counter] = el[key];
delete el[key];
counter = counter + 1;
}
}
}
}
return el;
});
Papa.parse(url, { //for csv file!
download: true,
header: true,
dynamicTyping: true,
skipEmptyLines: true,
complete: function(data) {
doStuff(data.data);
}
});
function doStuff(results_all){
init(results.data, results_all, results.meta.fields);
}
}
});
}
function setContinue(){
d3v3.select("#SvgAnnotator").style("z-index", 2);
}
var ringNotes = [];
var gAnnotationsAll = [];
var AnnotationsAll = [];
var draggable = [];
function setReset(){
d3.selectAll("#SvgAnnotator > *").remove();
d3.selectAll("#OverviewtSNE > *").remove();
d3.selectAll("#correlation > *").remove();
d3.selectAll("#modtSNEcanvas_svg > *").remove();
d3.selectAll("#kNNBar > *").remove();
for (var i=0; i < InitialStatePoints.length; i++){
InitialStatePoints[i].selected = true;
}
redraw(InitialStatePoints);
}
function setLayerProj(){
d3.select("#modtSNEcanvas").style("z-index", 2);
d3.select("#modtSNEcanvas_svg").style("z-index", 1);
}
function setLayerComp(){
d3.select("#modtSNEcanvas_svg").style("z-index", 3);
}
function setLayerSche(){
d3.select("#modtSNEcanvas_svg").style("z-index", 3);
toggleValue = true;
}
function setAnnotator(){
var viewport2 = getViewport();
var vw2 = viewport2[0];
var vh2 = viewport2[1];
var textarea = document.getElementById("comment").value;
var annotations = [
{
"cx": 232,
"cy": 123,
"r": 103,
"text": textarea,
"textOffset": [
114,
88
]
}
];
var ringNote = d3v3.ringNote()
.draggable(true);
var svgAnnotator = d3v3.select("#SvgAnnotator")
.attr("width", vw2 * 0.5)
.attr("height", vh2 * 0.888)
.style("z-index", 3);
var gAnnotations = svgAnnotator.append("g")
.attr("class", "annotations")
.call(ringNote, annotations);
// Styling individual annotations based on bound data
gAnnotations.selectAll(".annotation circle")
.classed("shaded", function(d) { return d.shaded; });
ringNotes.push(ringNote);
gAnnotationsAll.push(gAnnotations);
AnnotationsAll.push(annotations);
draggable.push(true);
}
// Hide or show the controls
d3.select("#controls")
.on("change", function() {
if(ringNotes[0]){
for (var i = 0; i < ringNotes.length; i++){
ringNotes[i].draggable(draggable[i] = !draggable[i]);
gAnnotationsAll[i]
.call(ringNotes[i], AnnotationsAll[i])
.selectAll(".annotation circle")
.classed("shaded", function(d) { return d.shaded; });
}
} else{
alert("Cannot hide the annotators' controls because, currently, there are no annotations into the visual representation.")
}
});
// Three.js render loop
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
var MainCanvas;
var Child;
var renderer;
var fov = 21;
var near = 10;
var far = 7000;
var camera;
var scene;
// function that executes after data is successfully loaded
function init(data, results_all, fields) {
MainCanvas = document.getElementById('modtSNEcanvas');
Child = document.getElementById('modtSNEDiv');
// Add canvas
renderer = new THREE.WebGLRenderer({ canvas: MainCanvas});
renderer.setSize(dimensions, dimensions);
Child.append(renderer.domElement);
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
// Set up camera and scene
camera = new THREE.PerspectiveCamera(
fov,
dimensions / dimensions,
near,
far
);
animate();
step_counter = 0;
max_counter = document.getElementById("param-maxiter-value").value;
opt = {};
var fields;
fields.push("beta");
fields.push("cost");
all_fields = fields;
opt.epsilon = document.getElementById("param-learningrate-value").value; // epsilon is learning rate (10 = default)
opt.perplexity = document.getElementById("param-perplexity-value").value; // roughly how many neighbors each point influences (30 = default)
tsne = new tsnejs.tSNE(opt);
final_dataset = data;
dataFeatures = results_all;
var object;
for (let k = 0; k < dataFeatures.length; k++){
ArrayContainsDataFeatures.push(Object.values(dataFeatures[k]).concat(k));
object = [];
Object.values(dataFeatures[k]).forEach(function(dataFeature){
if(typeof(dataFeature) == "number"){
object.push(dataFeature);
}
});
ArrayContainsDataFeaturesCleared.push(object);
}
$("#datasetDetails").html("Number of Dimensions: " + (ArrayContainsDataFeatures[0].length - 1) + ", Number of Samples: " + final_dataset.length);
dists = computeDistances(data, document.getElementById("param-distance").value, document.getElementById("param-transform").value);
tsne.initDataDist(dists);
all_labels = [];
for(var i = 0; i < data.length; i++) {
if (final_dataset[i]["name"] != "" || final_dataset[i]["name"] != "undefined"){
all_labels[i] = final_dataset[i]["name"];
}
else{
all_labels[i];
}
}
for(var i = 0; i < final_dataset.length; i++) {final_dataset[i].beta = tsne.beta[i]; beta_all[i] = tsne.beta[i];}
runner = setInterval(step, 0);
}
// initialize distance matrix
function initDist(data) {
var dist = new Array(data.length);
for(var i = 0; i < data.length; i++) {
dist[i] = new Array(data.length);
}
for(var i = 0; i < data.length; i++) {
for(var j = 0; j < data.length; j++) {
dist[i][j] = 0;
}
}
return dist;
}
// calculate euclidean distance
function euclideanDist(data) {
dist = initDist(data);
for(var i = 0; i < data.length; i++) {
for(var j = i + 1; j < data.length; j++) {
for(var d in data[0]) {
if(d != "name") {
dist[i][j] += Math.pow(data[i][d] - data[j][d], 2);
}
}
dist[i][j] = Math.sqrt(dist[i][j]);
dist[j][i] = dist[i][j];
}
}
return dist;
}
// calculate jaccard dist
function jaccardDist(data) {
dist = initDist(data);
for(var i = 0; i < data.length; i++) {
for(var j = i + 1; j < data.length; j++) {
for(var d in data[0]) {
if(d != "name") {
x = data[i][d];
y = data[j][d];
if(x == y) {
dist[i][j] += 1;
}
}
}
dist[j][i] = dist[i][j];
}
}
return dist;
}
// normalize distances to prevent numerical issues
function normDist(data, dist) {
var max_dist = 0;
for(var i = 0; i < data.length; i++) {
for(var j = i + 1; j < data.length; j++) {
if(dist[i][j] > max_dist) max_dist = dist[i][j];
}
}
for(var i = 0; i < data.length; i++) {
for(var j = 0; j < data.length; j++) {
dist[i][j] /= max_dist;
}
}
return dist;
}
function noTrans(data) {
return data;
}
// Log transform
function logTrans(data) {
for(var i = 0; i < data.length; i++) {
for(var d in data[0]) {
if(d != "name") {
X = data[i][d];
data[i][d] = Math.log10(X + 1);
}
}
}
return data;
}
// asinh transform
function asinhTrans(data) {
for(var i = 0; i < data.length; i++) {
for(var d in data[0]) {
if(d != "name") {
X = data[i][d];
data[i][d] = Math.log(X + Math.sqrt(X * X + 1));
}
}
}
return data;
}
// binarize
function binTrans(data) {
for(var i = 0; i < data.length; i++) {
for(var d in data[0]) {
if(d != "name") {
X = data[i][d];
if(X > 0) data[i][d] = 1;
if(X < 0) data[i][d] = 0;
}
}
}
return data;
}
function computeDistances(data, distFunc, transFunc) {
dist = eval(distFunc)(eval(transFunc)(data));
dist = normDist(data, dist);
return dist;
}
// function that updates embedding
function updateEmbedding() {
var Y = tsne.getSolution(); // here we get the solution from the actual t-sne
var xExt = d3.extent(Y, d => d[0]);
var yExt = d3.extent(Y, d => d[1]);
var maxExt = [Math.min(xExt[0], yExt[0]), Math.max(xExt[1], yExt[1])];
var x = d3.scaleLinear()
.domain(maxExt)
.range([10, +dimensions-10]);
var y = d3.scaleLinear()
.domain(maxExt)
.range([10, +dimensions-10]);
for(var i = 0; i < final_dataset.length; i++) {
x_position[i] = x(Y[i][0]);
y_position[i] = y(Y[i][1]);
points[i] = {id: i, x: x_position[i], y: y_position[i], beta: final_dataset[i].beta, cost: final_dataset[i].cost, selected: true, DimON: null, starplot: false};
points2d[i] = {id: i, x: x_position[i], y: y_position[i], selected: true};
points[i] = extend(points[i], ArrayContainsDataFeaturesCleared[i]);
points[i] = extend(points[i], dataFeatures[i]);
}
InitialStatePoints = points;
function extend(obj, src) {
for (var key in src) {
if (src.hasOwnProperty(key)) obj[key] = src[key];
}
return obj;
}
if (step_counter == max_counter){
ShepardHeatMap();
OverviewtSNE(points);
BetatSNE(points);
}
}
function ShepardHeatMap () {
var margin = { top: 35, right: 15, bottom: 15, left: 35 },
dim2 = Math.min(parseInt(d3.select("#sheparheat").style("width")), parseInt(d3.select("#sheparheat").style("height")))
width = dim2- margin.left - margin.right,
height = dim2 - margin.top - margin.bottom,
buckets = 10,
gridSize = width / buckets,
dim_1 = ["0.0", "0.2", "0.4", "0.6", "0.8", "1.0"],
dim_2 = ["0.0", "0.4", "0.6", "1.0"]
// Create the svg canvas
var svg = d3.select("#sheparheat")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
dists2d = computeDistances(points2d, document.getElementById("param-distance").value, document.getElementById("param-transform").value);
var dist_list2d = [];
var dist_list = [];
for (var j=0; j<dists2d.length; j++){
dists2d[j] = dists2d[j].slice(0,j);
dists[j] = dists[j].slice(0,j);
}
for (var i=0; i<dists2d.length; i++){
for (var j=0; j<dists2d.length; j++){
let singleObj = {};
singleObj = dists2d[i][j];
dist_list2d.push(singleObj);
let singleObj2 = {};
singleObj2 = dists[i][j];
dist_list.push(singleObj2);
}
}
dist_list2d = dist_list2d.sort();
dist_list = dist_list.sort();
dist_list2d = dist_list2d.filter(function(val){ return val!==undefined; });
dist_list = dist_list.filter(function(val){ return val!==undefined; });
d3.tsv("./modules/heat.tsv").then(function(data) {
data.forEach(function(d) {
d.dim1 = +d.dim1;
d.dim2 = +d.dim2;
d.value = 0;
});
var counter = 0;
var counnum = [];
var temp_loop = 0;
for (var l=0; l<100; l++) {counnum[l] = 0};
var dist_list_all = [];
dist_list_all =[dist_list, dist_list2d];
for (var l=0; l<100; l++){
for (k=0; k<dist_list_all[0].length;k++){
if (l==0){
if (dist_list_all[0][k] <= data[l].dim1/10 && dist_list_all[1][k] <= data[l].dim2/10){
counnum[l] = counnum[l] + 1;
}
}else if (l <= 10){
if (dist_list_all[0][k] < data[l].dim1/10 && dist_list_all[1][k] < data[l].dim2/10 && dist_list_all[1][k] > data[l-1].dim2/10){
counnum[l] = counnum[l] + 1;
}
}else if (l % 10 == 1){
temp_loop = data[l].dim1-1;
if (dist_list_all[0][k] < data[l].dim1/10 && dist_list_all[1][k] < data[l].dim2/10 && dist_list_all[0][k] > temp_loop/10){
counnum[l] = counnum[l] + 1;
}
}else{
if (dist_list_all[0][k] <= data[l].dim1/10 && dist_list_all[1][k] <= data[l].dim2/10 && dist_list_all[1][k] >= data[l-1].dim2/10 && dist_list_all[0][k] > temp_loop/10){
counnum[l] = counnum[l] + 1;
}
}
}
counter = counter + counnum[l];
}
for (var m=0; m<data.length; m++)
{
data[m].value = counnum[m];
}
var maxNum = Math.round(d3.max(data,function(d){ return d.value; }));
var minNum = Math.round(d3.min(data,function(d){ return d.value; }));
var colors = ["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"];
let calcStep = (maxNum-minNum)/colors.length;
var colorScale = d3.scaleLinear()
.domain(d3.range(0, maxNum+calcStep,calcStep))
.range(colors);
var tip = d3.tip()
.attr('class', 'd3-tip')
.style("visibility","visible")
.offset([-20, 0])
.html(function(d) {
return "Value: <span style='color:red'>" + Math.round(d.value);
});
tip(svg.append("g"));
var dim1Labels = svg.selectAll(".dim1Label")
.data(dim_1)
.enter().append("text")
.text(function (d) { return d; })
.attr("x", 0)
.attr("y", function (d, i) { return i * gridSize * 2; })
.style("text-anchor", "end")
.style("font-size", "10px")
.attr("transform", "translate(-6," + gridSize / 4 + ")")
.attr("class","mono");
var title = svg.append("text")
.attr("class", "mono")
.attr("x", -(gridSize * 7))
.attr("y", -26)
.style("font-size", "12px")
.attr("transform", "rotate(-90)")
.attr("class","mono")
.text("Input Distance");
var title = svg.append("text")
.attr("class", "mono")
.attr("x", gridSize * 3 )
.attr("y", -26)
.style("font-size", "12px")
.text("Output Distance");
var dim2Labels = svg.selectAll(".dim2Label")
.data(dim_2)
.enter().append("text")
.text(function(d) { return d; })
.attr("x", function(d, i) { return i * gridSize * 3.2; })
.attr("y", 0)
.style("text-anchor", "middle")
.style("font-size", "10px")
.attr("transform", "translate(" + gridSize / 4 + ", -6)")
.attr("class","mono");
var heatMap = svg.selectAll(".dim2")
.data(data)
.enter().append("rect")
.attr("x", function(d) { return (d.dim2 - 1) * gridSize; })
.attr("y", function(d) { return (d.dim1 - 1) * gridSize; })
.attr("rx", 0.4)
.attr("ry", 0.4)
.attr("class", "dim2 bordered")
.attr("width", gridSize-2)
.attr("height", gridSize-2)
.style("fill", colors[0])
.attr("class", "square")
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
heatMap.transition()
.style("fill", function(d) { return colorScale(d.value); });
heatMap.append("title").text(function(d) { return d.value; });
var heatleg = d3.select("#legend4");
heatleg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(0,10)");
var legend = d3.legendColor()
.labelFormat(d3.format(",.0f"))
.cells(9)
.title("Number of Points")
.scale(colorScale);
heatleg.select(".legendLinear")
.call(legend);
});
}
// perform single t-SNE iteration
function step() {
step_counter++;
if(step_counter <= max_counter) {
var cost = tsne.step();
cost_each = cost[1];
for(var i = 0; i < final_dataset.length; i++) final_dataset[i].cost = cost_each[i];
$("#cost").html("Number of Iteration: " + tsne.iter + ", Overall Cost: " + cost[0].toFixed(3));
}
else {
clearInterval(runner);
}
updateEmbedding();
}
function resize(canvas) {
// Lookup the size the browser is displaying the canvas.
var displayWidth = canvas.clientWidth;
var displayHeight = canvas.clientHeight;
// Check if the canvas is not the same size.
if (canvas.width != displayWidth ||
canvas.height != displayHeight) {
// Make the canvas the same size
canvas.width = displayWidth;
canvas.height = displayHeight;
}
}
var Arrayx = [];
var Arrayy = [];
var XYDistId = [];
var Arrayxy = [];
var DistanceDrawing1D = [];
var allTransformPoints = [];
var p;
var pFinal = [];
var paths;
var path;
var ArrayLimit = [];
var minimum;
var correlationResults = [];
var ArrayContainsDataFeaturesLimit = [];
function OverviewtSNE(points){
if (step_counter == 1){
d3.select("#OverviewtSNE").select("g").remove();
d3.select("#correlation").select("g").remove();
d3.selectAll("#modtSNEcanvas_svg > *").remove();
Arrayx = [];
Arrayy = [];
XYDistId = [];
Arrayxy = [];
DistanceDrawing1D = [];
allTransformPoints = [];
p;
pFinal = [];
paths;
path;
ArrayLimit = [];
minimum;
correlationResults = [];
ArrayContainsDataFeaturesLimit = [];
}
var canvas = document.getElementById('tSNEcanvas');
gl = canvas.getContext('experimental-webgl');
// If we don't have a GL context, give up now
if (!gl) {
alert('Unable to initialize WebGL. Your browser or machine may not support it.');
return;
}
if (all_labels[0] == undefined){
var colorScale = d3.scaleOrdinal(d3.schemeCategory10).domain(["No Category"]).range(["#0000ff"]);
}
else{
var colorScale = d3.scaleOrdinal(d3.schemeCategory10).domain(all_labels);
}
d3.select("#legend3").select("svg").remove();
var svg = d3.select("#legend3").append("svg");
svg.append("g")
.attr("class", "legendOrdinal")
.attr("transform", "translate(8,5)");
var legendOrdinal = d3.legendColor()
.shape("path", d3.legendSize(100))
.shapePadding(15)
.scale(colorScale);
svg.select(".legendOrdinal")
.call(legendOrdinal);
let vertices = [];
let colors = [];
for (var i=0; i<points.length; i++){
let singleObj = {};
// convert the position from pixels to 0.0 to 1.0
let zeroToOne = points[i].x / dimensions;
let zeroToOne2 = points[i].y / dimensions;
// convert from 0->1 to 0->2
let zeroToTwo = zeroToOne * 2.0;
let zeroToTwo2 = zeroToOne2 * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
let clipSpace = zeroToTwo - 1.0;
let clipSpace2 = zeroToTwo2 - 1.0;
singleObj = clipSpace;
vertices.push(singleObj);
singleObj = clipSpace2 * -1;
vertices.push(singleObj);
singleObj = 0.0;
vertices.push(singleObj);
}
for (var i=0; i<points.length; i++){
let singleCol = {};
if (points[i].selected == false){
let colval = d3.rgb(211,211,211);
singleCol = colval.r/255;
colors.push(singleCol);
singleCol = colval.g/255;
colors.push(singleCol);
singleCol = colval.b/255;
colors.push(singleCol);
}else{
let colval = d3.rgb(colorScale(points[i].name));
singleCol = colval.r/255;
colors.push(singleCol);
singleCol = colval.g/255;
colors.push(singleCol);
singleCol = colval.b/255;
colors.push(singleCol);
}
}
// Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object and store color data
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// vertex shader source code
var vertCode = 'attribute vec3 coordinates;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'gl_PointSize = 3.5;'+
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
var fragCode = `
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif
precision mediump float;
varying vec3 vColor;
void main()
{
float r = 0.0, delta = 0.0, alpha = 1.0;
vec2 cxy = 2.0 * gl_PointCoord - 1.0;
r = dot(cxy, cxy);
#ifdef GL_OES_standard_derivatives
delta = fwidth(r);
alpha = 1.0 - smoothstep(1.0 - delta, 1.0 + delta, r);
#endif
gl_FragColor = vec4(vColor, alpha);
}`;
gl.getExtension('OES_standard_derivatives');
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to
// store the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
// bind the color buffer
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
// get the attribute location
var color = gl.getAttribLocation(shaderProgram, "color");
// point attribute to the volor buffer object
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;
// enable the color attribute
gl.enableVertexAttribArray(color);
// Clear the canvas
gl.clearColor(1.0, 1.0, 1.0, 1.0);
// Enable the depth test
gl.disable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
resize(gl.canvas);
gl.viewport(0, 0, dim, dim);
//Draw the triangle
gl.drawArrays(gl.POINTS, 0, points.length);
}
function redraw(repoints){
//OverviewtSNE(repoints);
BetatSNE(repoints);
//CosttSNE(repoints);
}
function handleLassoEnd(lassoPolygon) {
var countLassoFalse = 0;
KNNEnabled = true;
if (toggleValue == false){
for (var i = 0 ; i < points.length ; i ++) {
x = points[i].x;
y = points[i].y;
if (d3.polygonContains(lassoPolygon, [x, y])){
points[i].selected = true;
points2d[i].selected = true;
} else{
countLassoFalse = countLassoFalse + 1;
points[i].selected = false;
points2d[i].selected = true;
}
}
if (countLassoFalse == points.length){
for (var i = 0 ; i < points.length ; i ++) {
points[i].selected = true;
points2d[i].selected = true;
}
}
if (points.length - countLassoFalse <= 10 && points.length - countLassoFalse != 0){
for (var i = 0 ; i < points.length ; i ++) {
if (points[i].selected == true){
points[i].starplot = true;
}
}
} else{
for (var i = 0 ; i < points.length ; i ++) {
points[i].starplot = false;
}
}
redraw(points);
} else{
click();
}
}
// reset selected points when starting a new polygon
function handleLassoStart(lassoPolygon) {
if (toggleValue == true){
} else{
KNNEnabled = false;
for (var i = 0 ; i < points.length ; i ++) {
points[i].selected = true;
points[i].starplot = false;
points2d[i].selected = true;
}
redraw(points);
}
}
var svg,
defs,
gBrush,
brush,
main_xScale,
mini_xScale,
main_yScale,
mini_yScale,
main_xAxis,
main_yAxis,
mini_width,
textScale;
//Added only for the mouse wheel
var zoomer = d3v3.behavior.zoom()
.on("zoom", null);
var main_margin = {top: 8, right: 10, bottom: 30, left: 100},
main_width = 500 - main_margin.left - main_margin.right,
main_height = 320 - main_margin.top - main_margin.bottom;
var mini_margin = {top: 8, right: 10, bottom: 30, left: 10},
mini_height = 320 - mini_margin.top - mini_margin.bottom;
mini_width = 100 - mini_margin.left - mini_margin.right;
svg = d3v3.select("#correlation").attr("class", "svgWrapper")
.attr("width", main_width + main_margin.left + main_margin.right + mini_width + mini_margin.left + mini_margin.right)
.attr("height", main_height + main_margin.top + main_margin.bottom)
.call(zoomer)
.on("wheel.zoom", scroll)
.on("mousedown.zoom", null)
.on("touchstart.zoom", null)
.on("touchmove.zoom", null)
.on("touchend.zoom", null);
function click(){
let svgClick = d3.select('#modtSNEcanvas_svg');
function drawCircle(x, y, size) {
svgClick.append("circle")
.attr('class', 'click-circle')
.attr("cx", x)
.attr("cy", y)
.attr("r", size);
Arrayx.push(x);
Arrayy.push(y);
}
svgClick.on('click', function() {
var coords = d3.mouse(this);
drawCircle(coords[0], coords[1], 4);
});
//if (Arrayx.length == 1){
//}
svgClick.on("contextmenu", function (d) {
// Prevent the default mouse action. Allow right click to be used for the confirmation of our schema.
d3.event.preventDefault();
var line = d3.line().curve(d3.curveCardinal);
for (var k = 0; k < Arrayx.length ; k++){
Arrayxy[k] = [Arrayx[k], Arrayy[k]];
}
for (var loop = 0; loop < points.length ; loop++){
allTransformPoints[loop] = [points[loop].x, points[loop].y, points[loop].id, points[loop].beta, points[loop].cost, points[loop].selected];
}
for (var k = 0; k < Arrayxy.length - 1; k++){
path = svgClick.append("path")
.datum(Arrayxy.slice(k, k+2))
.attr("class", "SchemaCheck")
.attr("d", line);
}
var line = svgClick.append("line");
paths = svgClick.selectAll("path").filter(".SchemaCheck");
var correlLimit = document.getElementById("param-corr-value").value;
correlLimit = parseInt(correlLimit);
if (paths.nodes().length == 0){
alert("Please, provide one more point in order to create a line (i.e., path)!")
} else{
for (var m = 0; m < paths.nodes().length; m++) {
for (var j = 0; j < allTransformPoints.length; j++){
p = closestPoint(paths.nodes()[m], allTransformPoints[j]);
XYDistId.push(p);
}
}
for (var j = 0; j < allTransformPoints.length; j++){
for (var m = 0; m < paths.nodes().length; m++) {
if (m == 0){
minimum = XYDistId[j].distance;
}
else if (minimum > XYDistId[(m * allTransformPoints.length) + j].distance) {
minimum = XYDistId[(m * allTransformPoints.length) + j].distance;
}
}
for (var l = 0; l < paths.nodes().length ; l++) {
if (XYDistId[(l * allTransformPoints.length) + j].distance == minimum){
allTransformPoints[j].bucketID = l;
}
}
}
var arrays = [], size = allTransformPoints.length;
while (XYDistId.length > 0) {
arrays.push(XYDistId.splice(0, size));
}
var arraysCleared = [];
for (var j = 0; j < allTransformPoints.length; j++){
for (var m=0; m < arrays.length; m++) {
if (allTransformPoints[j].bucketID == m){
arraysCleared.push(arrays[m][j].concat(allTransformPoints[j].bucketID, Arrayxy[m], arrays[m][j].distance, arrays[m][j].id));
}
}
}
for (var i=0; i<arraysCleared.length; i++) {
if (arraysCleared[i][5] < correlLimit) {
ArrayLimit.push(arraysCleared[i]);
}
}
var temparray = [];
var count = new Array(paths.nodes().length).fill(0);
for (var m=0; m < paths.nodes().length; m++) {
for (var i=0; i<ArrayLimit.length; i++) {
if (ArrayLimit[i][2] == m){
count[m] = count[m] + 1;
temparray.push(ArrayLimit[i]);
}
// do whatever
}
}
var arraysSplitted = [];
for (var m=0; m < paths.nodes().length; m++) {
arraysSplitted.push(temparray.splice(0, count[m]));
}
for (var m=0; m < paths.nodes().length; m++) {
arraysSplitted[m] = arraysSplitted[m].sort(function(a, b){
var dist = (a[0]-a[3]) * (a[0]-a[3]) + (a[1]-a[4]) * (a[1]-a[4]);
var distAgain = (b[0]-b[3]) * (b[0]-b[3]) + (b[1]-b[4]) * (b[1]-b[4]);
// Compare the 2 dates
if(dist < distAgain) return -1;
if(distAgain > dist) return 1;
return 0;
});
}
var arraysConnected = [];
if (paths.nodes().length == 1) {
arraysConnected = arraysSplitted[0];
} else {
for (var m=0; m < paths.nodes().length - 1; m++) {
arraysConnected = arraysSplitted[m].concat(arraysSplitted[m+1]);
}
}
var Order = [];
for (var temp = 0; temp < arraysConnected.length; temp++) {
Order.push(arraysConnected[temp][6]);
}
for (var i = 0; i < points.length; i++){
points[i].selected = false;
for (var j = 0; j < ArrayLimit.length; j++){
if (ArrayLimit[j][6] == points[i].id){
points[i].selected = true;
}
}
}
redraw(points);
ArrayContainsDataFeatures = mapOrder(ArrayContainsDataFeatures, Order, 5);
for (var i = 0; i < ArrayContainsDataFeatures.length; i++){
for (var j = 0; j < arraysConnected.length; j++){
if (ArrayContainsDataFeatures[i][5] == arraysConnected[j][6]){
ArrayContainsDataFeaturesLimit.push(ArrayContainsDataFeatures[i]);
}
}
}
for (var loop = 0; loop < ArrayContainsDataFeaturesLimit.length; loop++) {
ArrayContainsDataFeaturesLimit[loop].push(loop);
}
for (var k = 0; k < Arrayxy.length - 1 ; k++){
d3.select('#modtSNEcanvas_svg').append('line')
.attr("x1", Arrayxy[k][0])
.attr("y1", Arrayxy[k][1])
.attr("x2", Arrayxy[k+1][0])
.attr("y2", Arrayxy[k+1][1])
.style("stroke","black")
.style("stroke-width",2);
}
var SignStore = [];
const arrayColumn = (arr, n) => arr.map(x => x[n]);
for (var temp = 0; temp < ArrayContainsDataFeaturesLimit[0].length - 2; temp++) {
var tempData = new Array(
arrayColumn(ArrayContainsDataFeaturesLimit, temp),
arrayColumn(ArrayContainsDataFeaturesLimit, ArrayContainsDataFeaturesLimit[0].length - 1)
);
if (isNaN(pearsonCorrelation(tempData, 0, 1))) {
} else{
SignStore.push([temp, pearsonCorrelation(tempData, 0, 1)]);
correlationResults.push(["Dimension "+temp, Math.abs(pearsonCorrelation(tempData, 0, 1))]);
}
}
correlationResults = correlationResults.sort(
function(a,b) {
if (a[1] == b[1])
return a[0] < b[0] ? -1 : 1;
return a[1] < b[1] ? 1 : -1;
}
);
for (var j = 0; j < correlationResults.length; j++) {
for (var i = 0; i < SignStore.length; i++) {
if (SignStore[i][1]*(-1) == correlationResults[j][1]) {
correlationResults[j][1] = parseInt(correlationResults[j][1] * 100) * (-1);
correlationResults[j].push(j);
//correlationResults[j][1] = correlationResults[j][1].toFixed(2)*(-1);
}
if (SignStore[i][1] == correlationResults[j][1]) {
correlationResults[j][1] = parseInt(correlationResults[j][1] * 100);
correlationResults[j].push(j);
}
}
}
/////////////////////////////////////////////////////////////
///////////////// Set-up SVG and wrappers ///////////////////
/////////////////////////////////////////////////////////////
var mainGroup = svg.append("g")
.attr("class","mainGroupWrapper")
.attr("transform","translate(" + main_margin.left + "," + main_margin.top + ")")
.append("g") //another one for the clip path - due to not wanting to clip the labels
.attr("clip-path", "url(#clip)")
.style("clip-path", "url(#clip)")
.attr("class","mainGroup")
var miniGroup = svg.append("g")
.attr("class","miniGroup")
.attr("transform","translate(" + (main_margin.left + main_width + main_margin.right + mini_margin.left) + "," + mini_margin.top + ")");
var brushGroup = svg.append("g")
.attr("class","brushGroup")
.attr("transform","translate(" + (main_margin.left + main_width + main_margin.right + mini_margin.left) + "," + mini_margin.top + ")");
/////////////////////////////////////////////////////////////
////////////////////// Initiate scales //////////////////////
/////////////////////////////////////////////////////////////
main_xScale = d3v3.scale.linear().range([0, main_width]);
mini_xScale = d3v3.scale.linear().range([0, mini_width]);
main_yScale = d3v3.scale.ordinal().rangeBands([0, main_height], 0.4, 0);
mini_yScale = d3v3.scale.ordinal().rangeBands([0, mini_height], 0.4, 0);
//Based on the idea from: http://stackoverflow.com/questions/21485339/d3-brushing-on-grouped-bar-chart
main_yZoom = d3v3.scale.linear()
.range([0, main_height])
.domain([0, main_height]);
//Create x axis object
main_xAxis = d3v3.svg.axis()
.scale(main_xScale)
.orient("bottom")
.ticks(8)
.outerTickSize(0);
//Add group for the x axis
d3v3.select(".mainGroupWrapper").append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + 0 + "," + (main_height + 5) + ")");
//Create y axis object
main_yAxis = d3v3.svg.axis()
.scale(main_yScale)
.orient("left")
.tickSize(0)
.outerTickSize(0);
//Add group for the y axis
mainGroup.append("g")
.attr("class", "y axis")
.attr("transform", "translate(-5,0)");
/////////////////////////////////////////////////////////////
/////////////////////// Update scales ///////////////////////
/////////////////////////////////////////////////////////////
//Update the scales
main_xScale.domain([-100, 100]);
mini_xScale.domain([-100, 100]);
main_yScale.domain(correlationResults.map(function(d) { return d[0]; }));
mini_yScale.domain(correlationResults.map(function(d) { return d[0]; }));
//Create the visual part of the y axis
d3v3.select(".mainGroup").select(".y.axis").call(main_yAxis);
d3v3.select(".mainGroupWrapper").select(".x.axis").call(main_xAxis);
/////////////////////////////////////////////////////////////
///////////////////// Label axis scales /////////////////////
/////////////////////////////////////////////////////////////
textScale = d3v3.scale.linear()
.domain([15,50])
.range([12,6])
.clamp(true);
/////////////////////////////////////////////////////////////
///////////////////////// Create brush //////////////////////
/////////////////////////////////////////////////////////////
//What should the first extent of the brush become - a bit arbitrary this
var brushExtent = parseInt(Math.max( 1, Math.min( 20, Math.round(correlationResults.length * 0.75) ) ));
brush = d3v3.svg.brush()
.y(mini_yScale)
.extent([mini_yScale(correlationResults[0][0]), mini_yScale(correlationResults[brushExtent][0])])
.on("brush", brushmove)
//Set up the visual part of the brush
gBrush = d3v3.select(".brushGroup").append("g")
.attr("class", "brush")
.call(brush);
gBrush.selectAll(".resize")
.append("line")
.attr("x2", mini_width);
gBrush.selectAll(".resize")
.append("path")
.attr("d", d3v3.svg.symbol().type("triangle-up").size(20))
.attr("transform", function(d,i) {
return i ? "translate(" + (mini_width/2) + "," + 4 + ") rotate(180)" : "translate(" + (mini_width/2) + "," + -4 + ") rotate(0)";
});
gBrush.selectAll("rect")
.attr("width", mini_width);
//On a click recenter the brush window
gBrush.select(".background")
.on("mousedown.brush", brushcenter)
.on("touchstart.brush", brushcenter);
///////////////////////////////////////////////////////////////////////////
/////////////////// Create a rainbow gradient - for fun ///////////////////
///////////////////////////////////////////////////////////////////////////
defs = svg.append("defs")
//Create two separate gradients for the main and mini bar - just because it looks fun
createGradient("gradient-main", "60%");
createGradient("gradient-mini", "13%");
//Add the clip path for the main bar chart
defs.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("x", -main_margin.left)
.attr("width", main_width + main_margin.left)
.attr("height", main_height);
/////////////////////////////////////////////////////////////
/////////////// Set-up the mini bar chart ///////////////////
/////////////////////////////////////////////////////////////
//The mini brushable bar
//DATA JOIN
var mini_bar = d3v3.select(".miniGroup").selectAll(".bar")
.data(correlationResults, function(d) { return +d[2]; });
//UDPATE
mini_bar
.attr("width", function(d) { return Math.abs(mini_xScale(d[1]) - mini_xScale(0)); })
.attr("y", function(d,i) { return mini_yScale(d[0]); })
.attr("height", mini_yScale.rangeBand())
//ENTER
mini_bar.enter().append("rect")
.attr("class", "bar")
.attr("x", function (d) { return mini_xScale(Math.min(0, d[1])); })
.attr("width", function(d) { return Math.abs(mini_xScale(d[1]) - mini_xScale(0)); })
.attr("y", function(d,i) { return mini_yScale(d[0]); })
.attr("height", mini_yScale.rangeBand())
.style("fill", "url(#gradient-mini)");
//EXIT
mini_bar.exit()
.remove();
//Start the brush
//gBrush.call(brush.event);
gBrush.call(brush.event);
}
});
}
//Function runs on a brush move - to update the big bar chart
function updateBarChart() {
/////////////////////////////////////////////////////////////
////////// Update the bars of the main bar chart ////////////
/////////////////////////////////////////////////////////////
var bar = d3v3.select(".mainGroup").selectAll(".bar")
.data(correlationResults, function(d) { return +d[2]; })
//, function(d) { return d.key; });
bar
.attr("x", function (d) { return main_xScale(Math.min(0, d[1])); })
.attr("width", function(d) { return Math.abs(main_xScale(d[1]) - main_xScale(0)); })
.attr("y", function(d,i) { return main_yScale(d[0]); })
.attr("height", main_yScale.rangeBand());
//ENTER
bar.enter().append("rect")
.attr("class", "bar")
.style("fill", "url(#gradient-main)")
.attr("x", function (d) { return main_xScale(Math.min(0, d[1])); })
.attr("width", function(d) { return Math.abs(main_xScale(d[1]) - main_xScale(0)); })
.attr("y", function(d,i) { return main_yScale(d[0]); })
.attr("height", main_yScale.rangeBand())
.on("mouseover", () => {
svg.select('.tooltip').style('display', 'none');
})
.on("mouseout", function(d){
points.forEach(function (p) {
p.DimON = null
})
BetatSNE(points);
svg.select('.tooltip').style('display', 'none');
})
.on("mousemove", function(d) {
points.forEach(function (p) {
if (p.selected == true) {
p.DimON = d[0];
}
})
BetatSNE(points);
});
//EXIT
bar.exit()
.remove();
}//update
/////////////////////////////////////////////////////////////
////////////////////// Brush functions //////////////////////
/////////////////////////////////////////////////////////////
//First function that runs on a brush move
function brushmove() {
var extent = brush.extent();
//Reset the part that is visible on the big chart
var originalRange = main_yZoom.range();
main_yZoom.domain( extent );
//Update the domain of the x & y scale of the big bar chart
main_yScale.domain(correlationResults.map(function(d) { return d[0]; }));
main_yScale.rangeBands( [ main_yZoom(originalRange[0]), main_yZoom(originalRange[1]) ], 0.4, 0);
//Update the y axis of the big chart
d3v3.select(".mainGroup")
.select(".y.axis")
.call(main_yAxis);
//Which bars are still "selected"
var selected = mini_yScale.domain()
.filter(function(d) { return (extent[0] - mini_yScale.rangeBand () + 1e-2 <= mini_yScale(d)) && (mini_yScale(d) <= extent[1] - 1e-2); });
//Update the colors of the mini chart - Make everything outside the brush grey
d3.select(".miniGroup").selectAll(".bar")
.style("fill", function(d, i) { return selected.indexOf(d[0]) > -1 ? "url(#gradient-mini)" : "#e0e0e0"; });
//Update the label size
d3v3.selectAll(".y.axis text")
.style("font-size", textScale(selected.length));
//Update the big bar chart
updateBarChart();
}//brushmove
/////////////////////////////////////////////////////////////
////////////////////// Click functions //////////////////////
/////////////////////////////////////////////////////////////
//Based on http://bl.ocks.org/mbostock/6498000
//What to do when the user clicks on another location along the brushable bar chart
function brushcenter() {
var target = d3v3.event.target,
extent = brush.extent(),
size = extent[1] - extent[0],
range = mini_yScale.range(),
y0 = d3v3.min(range) + size / 2,
y1 = d3.max(range) + mini_yScale.rangeBand() - size / 2,
center = Math.max( y0, Math.min( y1, d3.mouse(target)[1] ) );
d3v3.event.stopPropagation();
gBrush
.call(brush.extent([center - size / 2, center + size / 2]))
.call(brush.event);
}//brushcenter
function scroll() {
//Mouse scroll on the mini chart
var extent = brush.extent(),
size = extent[1] - extent[0],
range = mini_yScale.range(),
y0 = d3v3.min(range),
y1 = d3v3.max(range) + mini_yScale.rangeBand(),
dy = d3v3.event.deltaY,
topSection;
if ( extent[0] - dy < y0 ) { topSection = y0; }
else if ( extent[1] - dy > y1 ) { topSection = y1 - size; }
else { topSection = extent[0] - dy; }
//Make sure the page doesn't scroll as well
d3v3.event.stopPropagation();
d3v3.event.preventDefault();
gBrush
.call(brush.extent([ topSection, topSection + size ]))
.call(brush.event);
}//scroll
/////////////////////////////////////////////////////////////
///////////////////// Helper functions //////////////////////
/////////////////////////////////////////////////////////////
//Create a gradient
function createGradient(idName, endPerc) {
var colorsBarChart = ['#7f3b08','#b35806','#e08214','#fdb863','#fee0b6','#d8daeb','#b2abd2','#8073ac','#542788','#2d004b']
colorsBarChart.reverse();
defs.append("linearGradient")
.attr("id", idName)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", "0%").attr("y1", "0%")
.attr("x2", endPerc).attr("y2", "0%")
.selectAll("stop")
.data(colorsBarChart)
.enter().append("stop")
.attr("offset", function(d,i) { return i/(colorsBarChart.length-1); })
.attr("stop-color", function(d) { return d; });
}//createGradient
function mapOrder(array, order, key) {
array.sort( function (a, b) {
var A = a[key], B = b[key];
if (order.indexOf(A) > order.indexOf(B)) {
return 1;
} else {
return -1;
}
});
return array;
};
/**
* Calculate the person correlation score between two items in a dataset.
*
* @param {object} prefs The dataset containing data about both items that
* are being compared.
* @param {string} p1 Item one for comparison.
* @param {string} p2 Item two for comparison.
* @return {float} The pearson correlation score.
*/
function pearsonCorrelation(prefs, p1, p2) {
var si = [];
for (var key in prefs[p1]) {
if (prefs[p2][key]) si.push(key);
}
var n = si.length;
if (n == 0) return 0;
var sum1 = 0;
for (var i = 0; i < si.length; i++) sum1 += prefs[p1][si[i]];
var sum2 = 0;
for (var i = 0; i < si.length; i++) sum2 += prefs[p2][si[i]];
var sum1Sq = 0;
for (var i = 0; i < si.length; i++) {
sum1Sq += Math.pow(prefs[p1][si[i]], 2);
}
var sum2Sq = 0;
for (var i = 0; i < si.length; i++) {
sum2Sq += Math.pow(prefs[p2][si[i]], 2);
}
var pSum = 0;
for (var i = 0; i < si.length; i++) {
pSum += prefs[p1][si[i]] * prefs[p2][si[i]];
}
var num = pSum - (sum1 * sum2 / n);
var den = Math.sqrt((sum1Sq - Math.pow(sum1, 2) / n) *
(sum2Sq - Math.pow(sum2, 2) / n));
if (den == 0) return 0;
return num / den;
}
function closestPoint(pathNode, point) {
var pathLength = pathNode.getTotalLength(),
precision = 8,
best,
bestLength,
bestDistance = Infinity;
// linear scan for coarse approximation
for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {
if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) {
best = scan, bestLength = scanLength, bestDistance = scanDistance;
}
}
// binary search for precise estimate
precision /= 2;
while (precision > 0.5) {
var before,
after,
beforeLength,
afterLength,
beforeDistance,
afterDistance;
if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) {
best = before, bestLength = beforeLength, bestDistance = beforeDistance;
} else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) {
best = after, bestLength = afterLength, bestDistance = afterDistance;
} else {
precision /= 2;
}
}
best = [best.x, best.y];
best.distance = Math.sqrt(bestDistance);
best.id = point[2];
return best;
function distance2(p) {
var dx = p.x - point[0],
dy = p.y - point[1];
return dx * dx + dy * dy;
}
// Points are represented as objects with x and y attributes.
/* var svg = d3.select('#modtSNEcanvas_svgClick').append('svg')
.attr('width', width)
.attr('height', height)
.on('mousemove', function() {
x = d3.event.pageX;
y = d3.event.pageY;
console.log( d3.event.pageX, d3.event.pageY ) // log the mouse x,y position
});
var interactionSvgClick = d3.select("#modtSNEcanvas_svgClick").append("circle")
.attr("transform", "translate(" + x + "," + y + ")")
.attr("r", "3")
.attr("class", "dot")
.style('position', 'absolute')
.style("cursor", "pointer");*/
//.call(drag);
}
/*
// Define drag behavior
var drag = d3.drag()
.on("drag", dragmove);
function dragmove(d) {
var x = d3.event.x;
var y = d3.event.y;
d3.select(this).attr("transform", "translate(" + x + "," + y + ")");
}
*/
function abbreviateNumber(value) {
var newValue = value;
if (value >= 1000) {
var suffixes = ["", "k", "m", "b","t"];
var suffixNum = Math.floor( (""+value).length/3 );
var shortValue = '';
for (var precision = 2; precision >= 1; precision--) {
shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
if (dotLessShortValue.length <= 2) { break; }
}
if (shortValue % 1 != 0) shortNum = shortValue.toFixed(1);
newValue = shortValue+suffixes[suffixNum];
}
return newValue;
}
function clearThree(obj){
while(obj.children.length > 0){
clearThree(obj.children[0])
obj.remove(obj.children[0]);
}
if(obj.geometry) obj.geometry.dispose()
if(obj.material) obj.material.dispose()
if(obj.texture) obj.texture.dispose()
}
var viewport3 = getViewport();
var vw3 = viewport3[0] * 0.2;
var margin = {top: 40, right: 100, bottom: 40, left: 190},
width = Math.min(vw3, window.innerWidth - 10) - margin.left - margin.right,
height = Math.min(width, window.innerHeight - margin.top - margin.bottom);
var wrapData = [];
//////////////////////////////////////////////////////////////
//////////////////// Draw the Chart //////////////////////////
//////////////////////////////////////////////////////////////
var radarChartOptions = {
w: width,
h: height,
margin: margin,
maxValue: 100,
roundStrokes: true
};
var colors;
var IDS = [];
//Call function to draw the Radar chart
RadarChart("#starPlot", wrapData, colors, IDS, radarChartOptions);
function BetatSNE(points){
selectedPoints = [];
var findNearestTable = [];
for (let m=0; m<points.length; m++){
if (points[m].selected == true){
selectedPoints.push(points[m]);
}
}
if (KNNEnabled == true && selectedPoints.length != 0){
var distsFull = dists;
var dists2dFull = dists2d;
for (var i=0; i<dists.length; i++){
for (var j=0; j<dists.length; j++){
if(dists[i][j] != null) {
distsFull[j][i] = dists[i][j];
dists2dFull[j][i] = dists2d[i][j];
}
}
}
var indexOrder = [];
var indexOrder2d = [];
var indices = new Array(selectedPoints.length);
var indices2d = new Array(selectedPoints.length);
var findNearest;
var counter1;
var counter2;
var temp = [];
var temp2 = [];
var viewport = getViewport();
var vw = viewport[0] * 0.5;
var vh = viewport[1] * 0.042;
var factor = Math.log10(points.length) * 4;
if (factor == 0){
factor = 1;
}
var maxKNN = Math.ceil(points.length / factor);
selectedPoints.sort(function(a, b) {
return parseFloat(a.id) - parseFloat(b.id);
});
for (k=maxKNN; k>0; k--){
findNearest = 0;
var indexOrderSliced = [];
var indexOrderSliced2d = [];
var count1 = new Array(selectedPoints.length).fill(0);
var count2 = new Array(selectedPoints.length).fill(0);
counter1 = 0;
counter2 = 0;
for (var i=0; i<selectedPoints.length; i++){
temp[i] = 0;
temp2[i] = 0;
if (k == maxKNN){
// temporary array holds objects with position and sort-value
indices[i] = dists[i].map(function(el, i) {
return [ i, el ];
})
var index = indices[i].indexOf(selectedPoints[i].id);
if (index > -1) {
indices[i].splice(index, 1);
}
// sorting the mapped array containing the reduced values
indices[i].sort(function(a, b) {
if (a[1] > b[1]) {
return 1;
}
if (a[1] < b[1]) {
return -1;
}
return 0;
});
indexOrder[i] = indices[i].map(function(value) { return value[0]; });
// temporary array holds objects with position and sort-value
indices2d[i] = dists2d[i].map(function(el, i) {
return [ i, el ];
})
var index2d = indices2d[i].indexOf(selectedPoints[i].id);
if (index2d > -1) {
indices2d[i].splice(index2d, 1);
}
// sorting the mapped array containing the reduced values
indices2d[i].sort(function(a, b) {
if (a[1] > b[1]) {
return 1;
}
if (a[1] < b[1]) {
return -1;
}
return 0;
});
indexOrder2d[i] = indices2d[i].map(function(value) { return value[0]; });
}
indexOrderSliced[i] = indexOrder[i].slice(0,k);
indexOrderSliced2d[i] = indexOrder2d[i].slice(0,k);
for (var m=0; m < indexOrderSliced2d[i].length; m++){
if (indexOrderSliced[i].includes(indexOrderSliced2d[i][m])){
count1[i] = count1[i] + 1;
temp[i] = temp[i] + 1;
}
if(indexOrderSliced[i][m] == indexOrderSliced2d[i][m]){
count2[i] = count2[i] + 1;
temp2[i] = temp2[i] + 1;
}
}
if (count1[i] != 0){
counter1 = (count1[i] / temp[i]) + counter1;
}
if (count2[i] != 0){
counter2 = (count2[i] / temp2[i]) + counter2;
}
}
sumUnion = counter1 / selectedPoints.length;
sumIntersection = counter2 / selectedPoints.length;
if (sumUnion == 0){
findNearest = 0;
} else{
findNearest = sumIntersection / sumUnion;
}
if (isNaN(findNearest)){
findNearest = 0;
}
findNearestTable.push(findNearest * vh * 2);
}
findNearestTable.reverse();
var barPadding = 5;
d3v3.select("#knnBarChart").selectAll("rect").remove();
var svg2 = d3v3.select('#knnBarChart')
.attr("class", "bar-chart");
var barWidth = (vw / findNearestTable.length);
var knnBarChartSVG = svg2.selectAll("rect")
.data(findNearestTable)
.enter()
.append("rect")
.attr("y", function(d) {
return Math.round(vh*2 - d)
})
.attr("height", function(d) {
return d;
})
.attr("width", barWidth - barPadding)
.attr("transform", function (d, i) {
var translate = [barWidth * i, 0];
return "translate("+ translate +")";
});
}
d3.select("#starPlot").selectAll('g').remove();
if(selectedPoints.length <= 10){
var FeatureWise = [];
for (var j=0; j<Object.values(dataFeatures[0]).length; j++){
for (var i=0;i<dataFeatures.length;i++){
if (!isNaN(Object.values(dataFeatures[i])[j])){
FeatureWise.push(Object.values(dataFeatures[i])[j]);
}
}
}
var sum = new Array(Object.values(dataFeatures[0]).length).fill(0);
for (var j=0; j<Object.values(dataFeatures[0]).length; j++){
var FeatureWiseSliced = FeatureWise.slice(0+(j*dataFeatures.length),dataFeatures.length+j*dataFeatures.length);
for (var i=0; i<FeatureWiseSliced.length; i++){
sum[j] = FeatureWiseSliced[i] + sum[j];
}
}
var wrapData = [];
var IDS = [];
for (var i=0; i<selectedPoints.length; i++){
var data = [];
for (var j=0; j< Object.keys(dataFeatures[selectedPoints[i].id]).length; j++){
if (!isNaN(Object.values(dataFeatures[i])[j])){
if (Object.keys(dataFeatures[i])[j] == "name") {
} else{
data.push({axis:Object.keys(dataFeatures[i])[j],value:Math.abs(Object.values(dataFeatures[i])[j]*100/sum[j])});
}
}
}
wrapData.push(data);
IDS.push(selectedPoints[i].id);
}
//////////////////////////////////////////////////////////////
//////////////////// Draw the Chart //////////////////////////
//////////////////////////////////////////////////////////////
var colors = ['#8dd3c7','#ffffb3','#bebada','#fb8072','#80b1d3','#fdb462','#b3de69','#fccde5','#d9d9d9','#bc80bd'];
var colorScl = d3v3.scale.ordinal()
.domain(IDS)
.range(colors);
var radarChartOptions = {
w: width,
h: height,
margin: margin,
levels: 10,
roundStrokes: true,
};
//Call function to draw the Radar chart
RadarChart("#starPlot", wrapData, colorScl, IDS, radarChartOptions);
}
if(step_counter == max_counter || step_counter == 1){
if (step_counter == 1){
d3.select("#modtSNEcanvas_svg").select("g").remove();
}else{
if (toggleValue == false){
interactionSvg = d3.select("#modtSNEcanvas_svg")
.attr("width", dimensions)
.attr("height", dimensions)
.style('position', 'absolute')
.style('top', 0)
.style('left', 0);
var lassoInstance = lasso()
.on('end', handleLassoEnd)
.on('start', handleLassoStart);
interactionSvg.call(lassoInstance);
}
}
}
var ColSizeSelector = document.getElementById("param-neighborHood").value;
if (ColSizeSelector == "color") {
var max = (d3.max(final_dataset,function(d){ return d.beta; }));
var min = (d3.min(final_dataset,function(d){ return d.beta; }));
// colors
var colorbrewer = ["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"];
var calcStep = (max-min)/7;
var colorScale = d3.scaleLinear()
.domain(d3.range(0, max+calcStep, calcStep))
.range(colorbrewer);
var maxSize1 = (d3.max(final_dataset,function(d){ return d.cost; }));
var minSize1 = (d3.min(final_dataset,function(d){ return d.cost; }));
var rscale1 = d3.scaleLinear()
.domain([minSize1, maxSize1])
.range([5,10]);
var colorScale = d3.scaleLinear()
.domain(d3.range(0, max+calcStep, calcStep))
.range(colorbrewer);
/*points = points.sort(function(a, b) {
return a.beta - b.beta;
})*/
var labels_beta = [];
var abbr_labels_beta = [];
labels_beta = d3.range(0, max+calcStep, calcStep);
for (var i=0; i<9; i++){
labels_beta[i] = parseInt(labels_beta[i]);
abbr_labels_beta[i] = abbreviateNumber(labels_beta[i]);
}
var svg = d3.select("#legend1");
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10,15)");
var legend = d3.legendColor()
.labelFormat(d3.format(",.0f"))
.cells(9)
.labels([abbr_labels_beta[0],abbr_labels_beta[1],abbr_labels_beta[2],abbr_labels_beta[3],abbr_labels_beta[4],abbr_labels_beta[5],abbr_labels_beta[6],abbr_labels_beta[7],abbr_labels_beta[8]])
.title("1 / sigma")
.scale(colorScale);
svg.select(".legendLinear")
.call(legend);
} else {
var max = (d3.max(final_dataset,function(d){ return d.cost; }));
var min = (d3.min(final_dataset,function(d){ return d.cost; }));
var maxSize2 = (d3.max(final_dataset,function(d){ return d.beta; }));
var minSize2 = (d3.min(final_dataset,function(d){ return d.beta; }));
var rscale2 = d3.scaleLinear()
.domain([minSize2, maxSize2])
.range([5,10]);
var colorbrewer = ["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"];
var calcStep = (max-min)/9;
var colorScale = d3.scaleLinear()
.domain(d3.range(min, max, calcStep))
.range(colorbrewer);
/*points = points.sort(function(a, b) {
return a.cost - b.cost;
})*/
var labels_cost = [];
var abbr_labels_cost = [];
labels_cost = d3.range(min, max, calcStep);
for (var i=0; i<9; i++){
labels_cost[i] = labels_cost[i].toFixed(5);
abbr_labels_cost[i] = abbreviateNumber(labels_cost[i]);
}
var svg = d3.select("#legend1");
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10,15)");
var legend = d3.legendColor()
.labelFormat(d3.format(",.5f"))
.cells(9)
.labels([abbr_labels_cost[0],abbr_labels_cost[1],abbr_labels_cost[2],abbr_labels_cost[3],abbr_labels_cost[4],abbr_labels_cost[5],abbr_labels_cost[6],abbr_labels_cost[7],abbr_labels_cost[8]])
.title("KLD(P||Q)")
.scale(colorScale);
svg.select(".legendLinear")
.call(legend);
}
let viz_width = dimensions;
window.addEventListener('resize', () => {
dimensions = window.innerWidth;
viz_width = dimensions;
dimensions = window.innerHeight;
renderer.setSize(dimensions, dimensions);
camera.aspect = dimensions / dimensions;
camera.updateProjectionMatrix();
})
let zoom = d3.zoom()
.scaleExtent([getScaleFromZ(far), getScaleFromZ(near)])
.on('zoom', () => {
let d3_transform = d3.event.transform;
zoomHandler(d3_transform);
});
view = d3.select(renderer.domElement);
function setUpZoom() {
view.call(zoom);
let initial_scale = getScaleFromZ(far);
var initial_transform = d3.zoomIdentity.translate(viz_width/2, dimensions/2).scale(initial_scale);
zoom.transform(view, initial_transform);
camera.position.set(0, 0, far);
}
setUpZoom();
var circle_sprite= new THREE.TextureLoader().load(
"./textures/circle-sprite.png"
)
let pointsGeometry = new THREE.Geometry();
clearThree(scene);
// Increase/reduce size factor selected by the user
var limitdist = document.getElementById("param-lim-value").value;
limitdist = parseFloat(limitdist).toFixed(1);
let pointsMaterial = [];
let factorPlusSize = [];
for (var i=0; i<points.length; i++) {
let vertex = new THREE.Vector3((((points[i].x/dimensions)*2) - 1)*dimensions, (((points[i].y/dimensions)*2) - 1)*dimensions*-1, 0);
pointsGeometry.vertices.push(vertex);
if (points[i].selected == false){
var color = new THREE.Color("rgb(211, 211, 211)");
} else if (points[i].DimON != null) {
let temp = points[i].DimON.match(/\d+/)[0];
var maxDim = (d3.max(points,function(d){ if(d.selected == true){return d[temp]}; }));
var minDim = (d3.min(points,function(d){ if(d.selected == true){return d[temp]}; }));
let colorsBarChart = ['#fcfbfd','#efedf5','#dadaeb','#bcbddc','#9e9ac8','#807dba','#6a51a3','#54278f','#3f007d'];
var calcStepDim = (maxDim-minDim)/8;
var colorScale = d3.scaleLinear()
.domain(d3.range(minDim, maxDim+calcStepDim, calcStepDim))
.range(colorsBarChart);
var color = new THREE.Color(colorScale(points[i][temp]));
} else if(points[i].starplot == true){
var color = new THREE.Color(colorScl(points[i].id));
} else if (ColSizeSelector == "color") {
var color = new THREE.Color(colorScale(points[i].beta));
}
else{
var color = new THREE.Color(colorScale(points[i].cost));
}
if (ColSizeSelector == "color") {
let sizePoint = rscale1(points[i].cost);
factorPlusSize[i] = limitdist * sizePoint;
pointsGeometry.colors.push(color);
pointsMaterial[i] = new THREE.PointsMaterial({
size: factorPlusSize[i],
sizeAttenuation: false,
vertexColors: THREE.VertexColors,
map: circle_sprite,
transparent: true
});
} else{
let sizePoint = rscale2(points[i].beta);
factorPlusSize[i] = limitdist * sizePoint;
pointsGeometry.colors.push(color);
pointsMaterial[i] = new THREE.PointsMaterial({
size: factorPlusSize[i],
sizeAttenuation: false,
vertexColors: THREE.VertexColors,
map: circle_sprite,
transparent: true
});
}
var particles = new THREE.Points(pointsGeometry, pointsMaterial[i]);
scene.add(particles);
}
let tempSort = -1;
for (var i=0; i<points.length; i++){
if (points[i].DimON != null) {
tempSort = points[i].DimON.match(/\d+/)[0];
}
}
if (tempSort != -1){
/*points = points.sort(function(a, b) {
return a[tempSort] - b[tempSort];
})*/
}
var temporal = 0;
for (var j=0; j < points.length; j++){
if(points[j].DimON != null) {
temporal = temporal + 1;
var labels_dim = [];
var abbr_labels_dim = [];
labels_dim = d3.range(minDim, maxDim+calcStepDim, calcStepDim);
for (var i=0; i<9; i++){
labels_dim[i] = labels_dim[i].toFixed(2);
abbr_labels_dim[i] = abbreviateNumber(labels_dim[i]);
}
d3.select("#legend1").selectAll('*').remove();
var svg = d3.select("#legend1");
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10,15)");
var legend = d3.legendColor()
.labelFormat(d3.format(",.0f"))
.cells(9)
.labels([abbr_labels_dim[0],abbr_labels_dim[1],abbr_labels_dim[2],abbr_labels_dim[3],abbr_labels_dim[4],abbr_labels_dim[5],abbr_labels_dim[6],abbr_labels_dim[7],abbr_labels_dim[8]])
.title(points[j].DimON)
.scale(colorScale);
svg.select(".legendLinear")
.call(legend);
break;
}
}
// This is for the legend
for (var j=0; j < points.length; j++){
if(temporal == 0 && points[j].DimON == null){
if (ColSizeSelector == "color"){
d3.select("#legend1").selectAll('*').remove();
var svg = d3.select("#legend1");
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10,15)");
var legend = d3.legendColor()
.labelFormat(d3.format(",.0f"))
.cells(9)
.labels([abbr_labels_beta[0],abbr_labels_beta[1],abbr_labels_beta[2],abbr_labels_beta[3],abbr_labels_beta[4],abbr_labels_beta[5],abbr_labels_beta[6],abbr_labels_beta[7],abbr_labels_beta[8]])
.title("1 / sigma")
.scale(colorScale);
svg.select(".legendLinear")
.call(legend);
break;
} else {
d3.select("#legend1").selectAll('*').remove();
var svg = d3.select("#legend1");
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10,15)");
var legend = d3.legendColor()
.labelFormat(d3.format(".4f"))
.cells(9)
.labels([abbr_labels_cost[0],abbr_labels_cost[1],abbr_labels_cost[2],abbr_labels_cost[3],abbr_labels_cost[4],abbr_labels_cost[5],abbr_labels_cost[6],abbr_labels_cost[7],abbr_labels_cost[8]])
.title("KLD(P||Q)")
.scale(colorScale);
svg.select(".legendLinear")
.call(legend);
break;
}
}
}
function zoomHandler(d3_transform) {
let scale = d3_transform.k;
let x = -(d3_transform.x - viz_width/2) / scale;
let y = (d3_transform.y - dimensions/2) / scale;
let z = getZFromScale(scale);
camera.position.set(x, y, z);
}
function getScaleFromZ (camera_z_position) {
let half_fov = fov/2;
let half_fov_radians = toRadians(half_fov);
let half_fov_height = Math.tan(half_fov_radians) * camera_z_position;
let fov_height = half_fov_height * 2;
let scale = dimensions / fov_height; // Divide visualization height by height derived from field of view
return scale;
}
function getZFromScale(scale) {
let half_fov = fov/2;
let half_fov_radians = toRadians(half_fov);
let scale_height = dimensions / scale;
let camera_z_position = scale_height / (2 * Math.tan(half_fov_radians));
return camera_z_position;
}
function toRadians (angle) {
return angle * (Math.PI / 180);
}
// Hover and tooltip interaction
raycaster = new THREE.Raycaster();
raycaster.params.Points.threshold = 10;
view.on("mousemove", () => {
let [mouseX, mouseY] = d3.mouse(view.node());
let mouse_position = [mouseX, mouseY];
checkIntersects(mouse_position);
});
function mouseToThree(mouseX, mouseY) {
return new THREE.Vector3(
mouseX / viz_width * 2 - 1,
-(mouseY / dimensions) * 2 + 1,
1
);
}
function checkIntersects(mouse_position) {
let mouse_vector = mouseToThree(...mouse_position);
raycaster.setFromCamera(mouse_vector, camera);
let intersects = raycaster.intersectObject(particles);
if (intersects[0]) {
let sorted_intersects = sortIntersectsByDistanceToRay(intersects);
let intersect = sorted_intersects[0];
let index = intersect.index;
let datum = points[index];
highlightPoint(datum);
showTooltip(mouse_position, datum);
} else {
removeHighlights();
hideTooltip();
}
}
function sortIntersectsByDistanceToRay(intersects) {
return _.sortBy(intersects, "distanceToRay");
}
hoverContainer = new THREE.Object3D()
scene.add(hoverContainer);
function highlightPoint(datum) {
removeHighlights();
let geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(
(((datum.x/dimensions)*2) - 1)*dimensions,
(((datum.y/dimensions)*2) - 1)*dimensions*-1,
0
)
);
if (all_labels[0] == undefined){
var colorScaleCat = d3.scaleOrdinal(d3.schemeCategory10).domain(["No Category"]).range(["#0000ff"]);
}
else{
var colorScaleCat = d3.scaleOrdinal(d3.schemeCategory10).domain(all_labels);
}
geometry.colors = [ new THREE.Color(colorScaleCat(datum.name)) ];
let material = new THREE.PointsMaterial({
size: 26,
sizeAttenuation: false,
vertexColors: THREE.VertexColors,
map: circle_sprite,
transparent: true
});
let point = new THREE.Points(geometry, material);
hoverContainer.add(point);
}
function removeHighlights() {
hoverContainer.remove(...hoverContainer.children);
}
view.on("mouseleave", () => {
removeHighlights()
});
// Initial tooltip state
let tooltip_state = { display: "none" }
let tooltip_dimensions;
let tooltip_template = document.createRange().createContextualFragment(`<div id="tooltip" style="display: none; z-index: 2; position: absolute; pointer-events: none; font-size: 13px; width: 240px; text-align: center; line-height: 1; padding: 6px; background: white; font-family: sans-serif;">
<div id="point_tip" style="padding: 4px; margin-bottom: 4px;"></div>
<div id="group_tip" style="padding: 4px;"></div>
</div>`);
document.body.append(tooltip_template);
let $tooltip = document.querySelector('#tooltip');
let $point_tip = document.querySelector('#point_tip');
let $group_tip = document.querySelector('#group_tip');
function updateTooltip() {
if (all_labels[0] == undefined){
var colorScaleCat = d3.scaleOrdinal(d3.schemeCategory10).domain(["No Category"]).range(["#0000ff"]);
}
else{
var colorScaleCat = d3.scaleOrdinal(d3.schemeCategory10).domain(all_labels);
}
$tooltip.style.display = tooltip_state.display;
$tooltip.style.left = tooltip_state.left + 'px';
$tooltip.style.top = tooltip_state.top + 'px';
$point_tip.innerText = tooltip_state.name;
$point_tip.style.background = colorScaleCat(tooltip_state.color);
$group_tip.innerText = `Data set's features: ${tooltip_dimensions}`;
}
function showTooltip(mouse_position, datum) {
let tooltip_width = 240;
let x_offset = tooltip_width + tooltip_width;
let y_offset = 30;
tooltip_state.display = "block";
tooltip_state.left = mouse_position[0] + x_offset;
tooltip_state.top = mouse_position[1] + y_offset;
if (all_labels[0] == undefined){
tooltip_state.name = datum.id;
tooltip_state.color = datum.id;
} else{
tooltip_state.name = datum.name + " (" + datum.id + ")";
tooltip_state.color = datum.name;
}
tooltip_dimensions = [];
for (var i=0; i < ArrayContainsDataFeaturesCleared.length; i++){
if (datum.id == i){
for (var j=0; j < ArrayContainsDataFeaturesCleared[i].length; j++){
tooltip_dimensions.push(ArrayContainsDataFeaturesCleared[i][j]);
}
}
}
updateTooltip();
}
function hideTooltip() {
tooltip_state.display = "none";
updateTooltip();
}
}
function getViewport() {
var viewPortWidth;
var viewPortHeight;
// the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight
if (typeof window.innerWidth != 'undefined') {
viewPortWidth = window.innerWidth,
viewPortHeight = window.innerHeight
}
// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)
else if (typeof document.documentElement != 'undefined'
&& typeof document.documentElement.clientWidth !=
'undefined' && document.documentElement.clientWidth != 0) {
viewPortWidth = document.documentElement.clientWidth,
viewPortHeight = document.documentElement.clientHeight
}
// older versions of IE
else {
viewPortWidth = document.getElementsByTagName('body')[0].clientWidth,
viewPortHeight = document.getElementsByTagName('body')[0].clientHeight
}
return [viewPortWidth, viewPortHeight];
}
/*
var canvas = document.getElementById('modtSNEcanvas');
var gl = canvas.getContext('webgl');
// If we don't have a GL context, give up now
if (!gl) {
alert('Unable to initialize WebGL. Your browser or machine may not support it.');
return;
}
var ColSizeSelector = document.getElementById("param-neighborHood").value;
if (ColSizeSelector == "color") {
var max = (d3.max(final_dataset,function(d){ return d.beta; }));
var min = (d3.min(final_dataset,function(d){ return d.beta; }));
// colors
var colorbrewer = ["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"];
var calcStep = (max-min)/7;
var colorScale = d3.scaleLinear()
.domain(d3.range(0, max+calcStep, calcStep))
.range(colorbrewer);
var maxSize1 = (d3.max(final_dataset,function(d){ return d.cost; }));
var minSize1 = (d3.min(final_dataset,function(d){ return d.cost; }));
var rscale1 = d3.scaleLinear()
.domain([minSize1, maxSize1])
.range([5,10]);
var colorScale = d3.scaleLinear()
.domain(d3.range(0, max+calcStep, calcStep))
.range(colorbrewer);
points = points.sort(function(a, b) {
return a.beta - b.beta;
})
var labels_beta = [];
var abbr_labels_beta = [];
labels_beta = d3.range(0, max+calcStep, calcStep);
for (var i=0; i<9; i++){
labels_beta[i] = parseInt(labels_beta[i]);
abbr_labels_beta[i] = abbreviateNumber(labels_beta[i]);
}
var svg = d3.select("#legend1");
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10,15)");
var legend = d3.legendColor()
.labelFormat(d3.format(",.0f"))
.cells(9)
.labels([abbr_labels_beta[0],abbr_labels_beta[1],abbr_labels_beta[2],abbr_labels_beta[3],abbr_labels_beta[4],abbr_labels_beta[5],abbr_labels_beta[6],abbr_labels_beta[7],abbr_labels_beta[8]])
.title("1 / sigma")
.scale(colorScale);
svg.select(".legendLinear")
.call(legend);
} else {
var max = (d3.max(final_dataset,function(d){ return d.cost; }));
var min = (d3.min(final_dataset,function(d){ return d.cost; }));
var maxSize2 = (d3.max(final_dataset,function(d){ return d.beta; }));
var minSize2 = (d3.min(final_dataset,function(d){ return d.beta; }));
var rscale2 = d3.scaleLinear()
.domain([minSize2, maxSize2])
.range([5,10]);
var colorbrewer = ["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"];
var calcStep = (max-min)/9;
var colorScale = d3.scaleLinear()
.domain(d3.range(min, max, calcStep))
.range(colorbrewer);
points = points.sort(function(a, b) {
return a.cost - b.cost;
})
var labels_cost = [];
var abbr_labels_cost = [];
labels_cost = d3.range(min, max, calcStep);
for (var i=0; i<9; i++){
labels_cost[i] = labels_cost[i].toFixed(5);
abbr_labels_cost[i] = abbreviateNumber(labels_cost[i]);
}
var svg = d3.select("#legend1");
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10,15)");
var legend = d3.legendColor()
.labelFormat(d3.format(",.5f"))
.cells(9)
.labels([abbr_labels_cost[0],abbr_labels_cost[1],abbr_labels_cost[2],abbr_labels_cost[3],abbr_labels_cost[4],abbr_labels_cost[5],abbr_labels_cost[6],abbr_labels_cost[7],abbr_labels_cost[8]])
.title("KLD(P||Q)")
.scale(colorScale);
svg.select(".legendLinear")
.call(legend);
}
let vertices = [];
let colors = [];
let sizes = new Float32Array(points.length);
let tempSort = -1;
for (var i=0; i<points.length; i++){
if (points[i].DimON != null) {
tempSort = points[i].DimON.match(/\d+/)[0];
}
}
if (tempSort != -1){
points = points.sort(function(a, b) {
return a[tempSort] - b[tempSort];
})
}
for (var i=0; i<points.length; i++){
let singleObj = {};
// convert the position from pixels to 0.0 to 1.0
let zeroToOne = points[i].x / dimensions;
let zeroToOne2 = points[i].y / dimensions;
// convert from 0->1 to 0->2
let zeroToTwo = zeroToOne * 2.0;
let zeroToTwo2 = zeroToOne2 * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
let clipSpace = zeroToTwo - 1.0;
let clipSpace2 = zeroToTwo2 - 1.0;
singleObj = clipSpace;
vertices.push(singleObj);
singleObj = clipSpace2 * -1;
vertices.push(singleObj);
singleObj = 0.0;
vertices.push(singleObj);
}
for (var i=0; i<points.length; i++){
let singleCol = {};
if (ColSizeSelector == "color"){
let singleSizeCol = rscale1(points[i].cost);
sizes[i] = singleSizeCol;
} else {
let singleSizeCol = rscale2(points[i].beta);
sizes[i] = singleSizeCol;
}
if (points[i].selected == false){
let colval = d3.rgb(211,211,211);
singleCol = colval.r/255;
colors.push(singleCol);
singleCol = colval.g/255;
colors.push(singleCol);
singleCol = colval.b/255;
colors.push(singleCol);
} else if (points[i].DimON != null) {
let temp = points[i].DimON.match(/\d+/)[0];
var maxDim = (d3.max(points,function(d){ if(d.selected == true){return d[temp]}; }));
var minDim = (d3.min(points,function(d){ if(d.selected == true){return d[temp]}; }));
let colorsBarChart = ['#fcfbfd','#efedf5','#dadaeb','#bcbddc','#9e9ac8','#807dba','#6a51a3','#54278f','#3f007d'];
var calcStepDim = (maxDim-minDim)/8;
var colorScaleDim = d3.scaleLinear()
.domain(d3.range(minDim, maxDim+calcStepDim, calcStepDim))
.range(colorsBarChart);
let colval = d3.rgb(colorScaleDim(points[i][temp]));
singleCol = colval.r/255;
colors.push(singleCol);
singleCol = colval.g/255;
colors.push(singleCol);
singleCol = colval.b/255;
colors.push(singleCol);
} else if (ColSizeSelector == "color") {
let colval = d3.rgb(colorScale(points[i].beta));
singleCol = colval.r/255;
colors.push(singleCol);
singleCol = colval.g/255;
colors.push(singleCol);
singleCol = colval.b/255;
colors.push(singleCol);
}
else{
let colval = d3.rgb(colorScale(points[i].cost));
singleCol = colval.r/255;
colors.push(singleCol);
singleCol = colval.g/255;
colors.push(singleCol);
singleCol = colval.b/255;
colors.push(singleCol);
}
}
var temporal = 0;
for (var j=0; j < points.length; j++){
if(points[j].DimON != null) {
temporal = temporal + 1;
var labels_dim = [];
var abbr_labels_dim = [];
labels_dim = d3.range(minDim, maxDim+calcStepDim, calcStepDim);
for (var i=0; i<9; i++){
labels_dim[i] = labels_dim[i].toFixed(2);
abbr_labels_dim[i] = abbreviateNumber(labels_dim[i]);
}
d3.select("#legend1").selectAll('*').remove();
var svg = d3.select("#legend1");
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10,15)");
var legend = d3.legendColor()
.labelFormat(d3.format(",.0f"))
.cells(9)
.labels([abbr_labels_dim[0],abbr_labels_dim[1],abbr_labels_dim[2],abbr_labels_dim[3],abbr_labels_dim[4],abbr_labels_dim[5],abbr_labels_dim[6],abbr_labels_dim[7],abbr_labels_dim[8]])
.title(points[j].DimON)
.scale(colorScaleDim);
svg.select(".legendLinear")
.call(legend);
break;
}
}
for (var j=0; j < points.length; j++){
if(temporal == 0 && points[j].DimON == null){
if (ColSizeSelector == "color"){
d3.select("#legend1").selectAll('*').remove();
var svg = d3.select("#legend1");
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10,15)");
var legend = d3.legendColor()
.labelFormat(d3.format(",.0f"))
.cells(9)
.labels([abbr_labels_beta[0],abbr_labels_beta[1],abbr_labels_beta[2],abbr_labels_beta[3],abbr_labels_beta[4],abbr_labels_beta[5],abbr_labels_beta[6],abbr_labels_beta[7],abbr_labels_beta[8]])
.title("1 / sigma")
.scale(colorScale);
svg.select(".legendLinear")
.call(legend);
break;
} else {
d3.select("#legend1").selectAll('*').remove();
var svg = d3.select("#legend1");
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10,15)");
var legend = d3.legendColor()
.labelFormat(d3.format(".4f"))
.cells(9)
.labels([abbr_labels_cost[0],abbr_labels_cost[1],abbr_labels_cost[2],abbr_labels_cost[3],abbr_labels_cost[4],abbr_labels_cost[5],abbr_labels_cost[6],abbr_labels_cost[7],abbr_labels_cost[8]])
.title("KLD(P||Q)")
.scale(colorScale);
svg.select(".legendLinear")
.call(legend);
break;
}
}
}
// Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object and store color data
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
var size_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, size_buffer);
gl.bufferData(gl.ARRAY_BUFFER, sizes, gl.STATIC_DRAW);
// Increase/reduce size factor selected by the user
var limitdist = document.getElementById("param-lim-value").value;
limitdist = parseFloat(limitdist).toFixed(1);
// vertex shader source code
var vertCode = 'attribute vec3 coordinates;'+
'attribute float vSizes;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
'gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'gl_PointSize = '+ limitdist + '*vSizes;'+
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// fragment shader source code
var fragCode = `
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif
precision mediump float;
varying vec3 vColor;
void main()
{
float r = 0.0, delta = 0.0, alpha = 1.0;
vec2 cxy = 2.0 * gl_PointCoord - 1.0;
r = dot(cxy, cxy);
#ifdef GL_OES_standard_derivatives
delta = fwidth(r);
alpha = 1.0 - smoothstep(1.0 - delta, 1.0 + delta, r);
#endif
gl_FragColor = vec4(vColor, alpha);
gl_FragColor.rgb *= gl_FragColor.a;
}`;
gl.getExtension('OES_standard_derivatives');
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to
// store the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
// bind the color buffer
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
// get the attribute location
var color = gl.getAttribLocation(shaderProgram, "color");
// point attribute to the volor buffer object
gl.vertexAttribPointer(color, 3, gl.FLOAT, false, 0, 0) ;
// enable the color attribute
gl.enableVertexAttribArray(color);
gl.bindBuffer(gl.ARRAY_BUFFER, size_buffer);
var vSize = gl.getAttribLocation(shaderProgram, "vSizes");
gl.vertexAttribPointer(vSize, 1, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vSize);
// Clear the canvas
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.enable( gl.BLEND );
gl.blendFunc( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA );
gl.disable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
resize(gl.canvas);
gl.viewport(0, 0, dimensions, dimensions);
//Draw the triangle
gl.drawArrays(gl.POINTS, 0, points.length);
*/